2024年8月

JSON是我们编写API时候用于数据传递的常用格式,那么你是否知道JSON Schema呢?

在数据交换领域,JSON Schema 以其强大的标准化能力,为定义和规范 JSON 数据的结构与规则提供了有力支持。通过一系列精心设计的关键字,JSON Schema 能够详尽地描述数据的各项属性。然而,仅凭 JSON Schema 本身,尚不足以验证 JSON 实例是否严格遵循预设的模式。此时,JSON Schema 验证器的角色便显得尤为关键。这些验证器如同严格的检查官,确保每一个 JSON 文档都能忠实地反映出模式的定义。JSON Schema 验证器,作为实现 JSON Schema 规范的技术工具,其灵活的集成能力使得无论项目规模大小,都能轻松地将 JSON Schema 融入开发流程,从而提升数据处理的效率与准确性。

下面我们来看看如何在Spring Boot应用中使用JSON Schema校验JSON数据

动手试试

  1. 创建一个基本的Spring Boot应用,如果还不会可以
    点击查看快速入门


  2. pom.xml
    中添加
    json-schema-validator
    依赖

<dependency>
  <groupId>com.networknt</groupId>
  <artifactId>json-schema-validator</artifactId>
  <version>1.4.0</version>
</dependency>
  1. 创建JSON Schema


src/main/resources
目录下创建一个
validation.json
文件,然后在里面制定一套详尽的验证规则,比如下面这样:

{
 "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Order Event",
    "description": "Order event schema for example",
    "required": ["order_id", "total_price", "products" ],
    "properties": {
       "order_id": {
          "type": "string"
        },
        "event": {
          "enum": ["PLACED", "DELIVERED", "RETURNED"],
          "type": "string"
        },
        "total_price": { 
         "type": "number",
             "minimum": 0
     },
        "products": {
      "type": "array",
      "items": {
        "additionalProperties": true,
        "required": ["product_id", "price"],
        "minItems": 1,
        "properties": {
          "product_id": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "minimum": 0
          },
          "quantity": {
            "type": "integer"
          }
        }
      }
    }
   }
}
  1. 创建 JsonSchema 的 Bean

当然,你也可以直接new来创建,但实战中还是推荐用Spring管理这些实例,比如 下面这样:

@Configuration
public class JsonSchemaConfiguration {

    private static final String SCHEMA_VALIDATION_FILE = "validation.json";
   
    @Bean
    public JsonSchema jsonSchema() {
        return JsonSchemaFactory
                .getInstance( SpecVersion.VersionFlag.V7 )
                .getSchema( getClass().getResourceAsStream( SCHEMA_VALIDATION_FILE ) );
    }
}
  1. 使用 JsonSchema
@Slf4j
@Service
public class JsonSchemaValidationService{
  
  @Autowired
  private JsonSchema jsonSchema;
  
  public String validateJson(JsonNode jsonNode){
    
    Set<ValidationMessage> errors = jsonSchema.validate(jsonNode);
    if(errors.isEmpty()){
      log.info("event is valid");
    }else{
      log.info("event is invalid");
     }
      return errors.toString();
  }
}
  1. 在 Web 层的应用

创建一个Controller,当接收到来自客户端的JSON数据之后,就可以像下面这样对json数据进行校验:

import com.fasterxml.jackson.databind.JsonNode;
@RestController
public class JsonSchemaController {
    @Autowired
    private JsonSchemaValidationService service;

    @PostMapping("/test")
    public String validateEvent( @RequestBody JsonNode jsonNode ){
       return service.validateJson(jsonNode);
    }
}
  1. 测试一下

启动 Sprint Boot 应用,然后使用你喜欢的http客户端工具对
/test
接口发送测试请求:

比如,下面使用Curl来进行测试:

  • 符合规则的合法请求:

$ curl --location 'localhost:8080/test' \
--header 'Content-Type: application/json' \
--data '{
  "order_id":"order134",
   "event": "PLACED",
   "products": [
     {
       "product_id": "product_1",
        "price":20.5,
       "quantity":2
     }
   ],
   "total_price": 41
}'

校验通过,返回:[],没有错误信息

  • 不符合规则的非法请求(却少order id):
$ curl --location 'localhost:8080/test' \
--header 'Content-Type: application/json' \
--data '{
   "event": "PLACED",
   "products": [
     {
       "product_id": "product_1",
        "price":20.5,
       "quantity":2
     }
   ],
   "total_price": 41
}'

校验失败,将返回错误信息:
[$.order_id: is missing but it is required]

好了,今天的分享就到这里,希望对您有用。如果您学习过程中如遇困难?可以加入我们超高质量的
Spring技术交流群
,参与交流与讨论,更好的学习与进步!更多
Spring Boot教程可以点击直达!
,欢迎收藏与转发支持!

相关资料

欢迎关注我的公众号:程序猿DD。第一时间了解前沿行业消息、分享深度技术干货、获取优质学习资源

前言:

学习ComfyUI是一场持久战, efficiency-nodes-comfyui是提高工作流创造效率的工具,包含效率节点整合工作流中的基础功能,比如Efficient Loader节点相当于Load Checkpoint+Clip set layer+Load VAE等等的合集,并且该插件提供了更加简便快捷的X/Y对比图,能够使测评工作的效率进一步提升。祝大家学习顺利,早日成为ComfyUI的高手!

目录

一、安装方法

二、Efficient Loader节点

三、KSampler Adv. (Efficient)节点

四、Lora stack/Controlnet Stacker节点

五、XY节点

六、XY Plot节点

一、安装方法

在ComfyUI主目录里面输入CMD回车。

1

在弹出的CMD命令行输入git clone xxx,即可开始下载。

2

在终端输入下面这行代码开始下载

git clone https://github.com/jags111/efficiency-nodes-comfyui.git

二、Efficient Loader节点

该节点是一个用于加载高效深度学习模型的节点。这个节点的设计目的是通过加载预训练的高效模型,提供快速且准确的图像处理能力。

3

重要参数:

lora_stack → 可连接lora模型加载栈 **比如CR库和本身库自带节点

cnet_stack → 可连接ControlNet模型加载栈

token normalization → 词条归一化,也就是设置文本编码的方式

weight interpretation → 权重初始化,模型的基础设置参数

DEPENDENCIES → 对后续进行X/Y对比试验有作用

注意:下图为四种不同token normalization在同参数下出图对比,从结果来看几乎没有影响。尝试了五种不同的weight interpretation,对结果也是没有影响。

4

5

使用场景:

· 快速图像处理:利用高效模型进行快速的图像处理任务,如去噪、修复、增强等。

· 图像识别与分类:使用高效模型进行图像识别和分类任务,提供准确的结果。

· 自动化处理:在自动化图像处理流程中,使用高效模型实现高效、准确的图像处理。

通过使用Efficient Loader节点,可以在图像处理工作流程中实现高效的模型加载和应用,提升图像处理的速度和效果。

三、KSampler Adv. (Efficient)节点

该节点专注于高效的图像采样和生成,通过高级采样技术和优化算法,实现快速且高质量的图像处理。

6

重要参数:

script → 与X/Y测试有关

add_noise → 是否在生图过程中添加噪声 **该选项仅跟ancestral采样器有关

Randomize/last Queued Seed → 点击左边为随机生成一个噪声,右边使用上次生图的噪声

return_with_leftover_noise → 是否进行完整的去噪过程,说是影响画面细节保留

preview method → 为去噪过程中预览设置,与manager管理器的预览方式一样。

vae_decode → 当我们传入optional_vae后,选择false就不输出image,选择true才会输出

使用场景:

· 高效图像生成:在需要快速生成高质量图像的场景中,使用高效采样技术实现图像生成。

· 图像增强:通过高级采样技术,对图像进行增强和优化,提高图像质量。

· 自动化处理:在自动化图像处理流程中,通过高效采样算法实现高效、准确的图像处理。

通过使用KSampler Adv. (Efficient)节点,可以在图像处理工作流程中实现高效的图像采样和生成,提升图像处理的速度和质量。

四、Lora stack/Controlnet Stacker节点

Lora Stack 节点专注于通过叠加多个Lora模型进行图像生成和处理。Lora模型是一种用于增强图像生成能力的预训练模型,Lora Stack节点可以加载和叠加多个Lora模型,以实现更加复杂和高质量的图像处理效果。

Controlnet Stacker 节点专注于叠加多个ControlNet模型进行图像生成和处理。ControlNet是一种控制生成图像的神经网络,通过叠加多个ControlNet模型,可以实现更复杂的图像控制和生成效果。

7

重要参数:

lora_stack → 串联可加载多个lora模型

Lora_count → 改变这个数值可以同步增加可加载lora数量

Control_net → 串联可加载多个ControlNet模型

input_mode → 选择simple可简单设置lora权重,选择advanced可开启大模型权重设置

打开advanced选项后,可以更改model权重。

8

示例1:下图为多个ControlNet串联,其中一个为tile来控制出图的元素,第二个为openpose来控制人物的骨骼,通过串联来影响最终的出图效果。

9

示例2:下图为多个Lora加载示例工作流,通过改变lora_count增加该节点加载lora的数量。

10

使用场景:

· 复杂图像生成:在需要生成复杂和高质量图像的任务中,通过叠加多个Lora/ControlNet模型实现增强效果。

· 图像处理优化:利用多个Lora/ControlNet模型的优势,对图像进行优化和增强。

通过使用Lora Stack和Controlnet Stacker节点,可以在图像处理工作流程中实现高效的模型叠加和应用,提升图像处理的复杂性和质量,满足各种复杂图像处理需求。

五、XY节点

XY节点专注于在图像处理和生成过程中进行参数扫图。通过在X轴和Y轴上分别设置不同的参数值,生成一系列图像,方便用户观察和比较不同参数组合对图像效果的影响。

11

重要参数:

first_xxx → 开始的参数选择

last_xxx → 输出的参数选择 **会根据batch_count自动填充过度过程

示例:对比三个大模型,在三个不同的CFG值下的表现情况,通过对比可以更清晰的发现模型的优劣势。

12

使用场景:

· 参数优化:通过对比不同参数组合生成的图像,优化图像处理参数,获得最佳效果。

· 实验和测试:在图像处理过程中进行实验和测试,观察参数变化对结果的影响。

· 图像生成:在图像生成任务中,通过参数扫图获得多样化的生成结果。

通过使用XY节点,可以在图像处理和生成过程中进行高效的参数扫图和优化,提升图像处理的效果和质量。

六、XY Plot节点

XY Plot节点专注于通过二维参数扫图生成和展示一系列图像。通过设置X轴和Y轴上的不同参数值,可以直观地比较和分析参数变化对图像效果的影响,从而优化图像处理参数。

13

重要参数:

grip_spacing → 输出对比图像之间的接缝大小

XY_flip → 翻转X,Y

Y_label_orientation → 设置Y轴标签是竖行展示还是纵列展示

ksampler_output_image → 选择image输出为图像,设置Plot输出为对比图合成的大图。

示例:当XY_flip打开之后,设置Y轴标签为纵向展示,最终的输出结果如下图所示。

14

使用场景:

· 参数优化:通过对比不同参数组合生成的图像,找到最佳的图像处理参数设置。

· 实验和测试:在图像处理过程中进行参数实验和测试,观察参数变化对结果的影响。

· 图像生成:在图像生成任务中,通过参数扫图获得多样化的生成结果,找到最佳生成参数组合。

通过使用XY Plot节点,可以在图像处理和生成过程中进行高效的参数扫图和优化,提升图像处理的效果和质量,满足各种复杂图像处理需求。

**孜孜以求,方能超越自我。坚持不懈,乃是成功关键。**

最近跟身边的程序员老杆子讨论需求时,惊奇的发现,他居然没使用AI编程助手。一时间有2个想法从大脑闪过,然后心里还带了一丝轻蔑:

  1. AI编程助手这么好的东西,你居然不用。
  2. 作为老程序员,你居然不跟上时代步伐,在想啥呢。

不过确实有一些老杆子是用过AI编程助手,又选择了放弃,具体啥原因,我们来聊聊。首先说说市面上常用的几款AI编程助手。

1、几款AI编程助手

GitHub Copilot

GitHub Copilot是由GitHub和OpenAI联合推出的AI编程助手,是我最早使用的一款编程助手。刚推出时我立马尝鲜,真香!当时立马感觉解放了许多生产力。对于中文的理解以及生成的代码质量我还是满意的。

但是,因为价格的原因(一年需要1000多元),我一直使用的学生版和代理版。但是半年前发现GitHub对于代理版和学生版查的比较严,Copilot经常掉线,在加上服务器本来就在国外,有时候生成代码的响应速度确实有些慢,渐渐地放弃了。

文心快码

文心快码(Comate),是百度推出的AI编程助手。放弃了GitHub Copilot之后,在国内寻找,当时发现可用的基本就是文心快码了。试用了一段时间后,觉得生成代码的速度还行,但是代码的准确率或者被采用率,有点堪忧。

不过当时想着免费嘛,就随便用用吧,不合适的代码一个
ESC
键也就过了,合适的代码一个
TAB
键就采纳了,多少也能节省些工作量吧。

毕竟当时我 对于 不熟悉的领域 或者 大片段的代码,都是让ChatGPT生成的,我使用文心快码的主要场景是辅助生成一些简单或重复的代码。

通义灵码

通义灵码是阿里巴巴推出的AI编程助手,基于强大的Qianwen2大模型。通义灵码是我最近正在使用的AI编程助手。

一次偶然的机会,我被邀参加阿里的一个AI沙龙会,当时有一个小专题是讲通义灵码的。本来用文心快码时觉得效果一般,心里想着,通义灵码估计也就那样吧。

后来看那位宣讲通义灵码的哥们,激情满满,特别自豪,好像这款产品是他造出来的。这倒引起了我的好奇心。当时,他自豪地说他们的大模型怎么好怎么牛,通义灵码做了多少多少的微调,做了多少多少的优化,他们对安全是怎么怎么重视。

虽说,他的话我不全信,但真的是被他当时的激情所感染(也许是出于一个产品人的同理心吧)。

当晚,我就试用了通义灵码。安不安全的我不知道,但是,生成代码的速度挺快。随后,我又写了1个小时的代码测试,发现生成的代码正确率和被采用率还不错,后来就一直在用了。

通过这次选择,更加说明一个道理
自助者天助之
。一个产品人一定要对自己的产品充满自行。即使是一名程序员,在AI时代,也要将自己看做一个产品人。

ChatGPT

ChatGPT真的是永远的No1。要说生成代码的准确率和自然语言的理解力,即使是中文场景,ChatGPT也是最好的。

下面是一个ChatGPT与通义灵码针对同一需求实现代码的小示例,朋友们可以自行感受下。

需求

我有一个Html文件,想批量替换里面的font-size的数值,放大两倍。还要替换line-height的数值,也是放大两倍。请你用java写出代码

ChatGPT实现

import java.io.*;
import java.nio.file.*;
import java.util.regex.*;

public class HtmlFontSizeLineHeightMultiplier {
    
    public static void main(String[] args) {
        String filePath = "htmlFile.html";
        try {
            String content = new String(Files.readAllBytes(Paths.get(filePath)));
            String updatedContent = updateFontSizeAndLineHeight(content);
            Files.write(Paths.get("updatedHtmlFile.html"), updatedContent.getBytes());
            System.out.println("File updated successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String updateFontSizeAndLineHeight(String content) {
        // Pattern to match font-size and line-height in CSS
        Pattern fontSizePattern = Pattern.compile("font-size\\s*:\\s*(\\d+(\\.\\d+)?)(px|em|rem|%)", Pattern.CASE_INSENSITIVE);
        Pattern lineHeightPattern = Pattern.compile("line-height\\s*:\\s*(\\d+(\\.\\d+)?)(px|em|rem|%)", Pattern.CASE_INSENSITIVE);

        // Replace font-size values
        Matcher fontSizeMatcher = fontSizePattern.matcher(content);
        StringBuffer updatedContent = new StringBuffer();
        while (fontSizeMatcher.find()) {
            String originalValue = fontSizeMatcher.group(1);
            String unit = fontSizeMatcher.group(3);
            double newValue = Double.parseDouble(originalValue) * 2;
            fontSizeMatcher.appendReplacement(updatedContent, "font-size: " + newValue + unit);
        }
        fontSizeMatcher.appendTail(updatedContent);

        // Replace line-height values
        Matcher lineHeightMatcher = lineHeightPattern.matcher(updatedContent.toString());
        updatedContent = new StringBuffer();
        while (lineHeightMatcher.find()) {
            String originalValue = lineHeightMatcher.group(1);
            String unit = lineHeightMatcher.group(3);
            double newValue = Double.parseDouble(originalValue) * 2;
            lineHeightMatcher.appendReplacement(updatedContent, "line-height: " + newValue + unit);
        }
        lineHeightMatcher.appendTail(updatedContent);

        return updatedContent.toString();
    }
}

通义灵码实现

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HtmlFontSizeModifier {

    public static void main(String[] args) {
        String inputFilePath = "path/to/input.html"; // 输入文件路径
        String outputFilePath = "path/to/output.html"; // 输出文件路径

        try {
            modifyFontSizesAndLineHeights(inputFilePath, outputFilePath);
        } catch (IOException e) {
            System.err.println("Error processing file: " + e.getMessage());
        }
    }

    /**
     * 修改HTML文件中的font-size和line-height值为原来的两倍。
     *
     * @param inputPath  输入文件路径
     * @param outputPath 输出文件路径
     * @throws IOException 如果文件处理过程中出现错误
     */
    public static void modifyFontSizesAndLineHeights(String inputPath, String outputPath) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(inputPath));
             BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) {

            String line;
            Pattern fontSizePattern = Pattern.compile("(font-size:\\s*([0-9]+)(px|em|rem))");
            Pattern lineHeightPattern = Pattern.compile("(line-height:\\s*([0-9]+)(px|em|rem))");

            while ((line = reader.readLine()) != null) {
                Matcher fontSizeMatcher = fontSizePattern.matcher(line);
                Matcher lineHeightMatcher = lineHeightPattern.matcher(line);

                if (fontSizeMatcher.find()) {
                    String fontSize = fontSizeMatcher.group(2);
                    String unit = fontSizeMatcher.group(3);
                    double newSize = Double.parseDouble(fontSize) * 2;
                    line = line.replaceFirst(fontSizeMatcher.group(), "font-size: " + newSize + unit);
                }

                if (lineHeightMatcher.find()) {
                    String lineHeight = lineHeightMatcher.group(2);
                    String unit = lineHeightMatcher.group(3);
                    double newLineHeight = Double.parseDouble(lineHeight) * 2;
                    line = line.replaceFirst(lineHeightMatcher.group(), "line-height: " + newLineHeight + unit);
                }

                writer.write(line);
                writer.newLine();
            }
        }
    }
}

可以看到,在对于需求的理解上ChatGPT更好,在实现正则匹配的逻辑方面ChatGPT也更完善。

我推荐的用法

对于AI编程助手的选择,我的建议是双管齐下:
ChatGPT + 国内某个大厂的AI编程助手

核心原因有3个:

  • ChatGPT的自然语言理解能力是最强的,生成代码的准确率也是最强的,可以用来生成小块需求代码。
  • 国内某个大厂的AI编程助手虽说在 自然语言理解能力 和 代码的准确率 方面可能弱一些,但是用来生成简单重复代码 和 完成简单需求 这些方面是OK的。而且国内的编程助手,生成代码的速度都比较快。
  • 国内大模型的发展速度我们亲眼所见,虽说跟国外的大模型还有些差距,但也在不停的追赶。我们要对国内大模型的发展有信心。

2、AI编程助手的工作原理

AI编程助手的背后是大语言模型和强大的算力
。在大模型的基础上,进行了编程领域的代码和文档的微调训练,使其更加使用编程场景。

具体在编程时,AI助手会根据你的代码注释、函数名、代码文件等上下文信息,结合之前已经喂给它的开源代码库,生成与当前需求有相关性的代码片段。

3、AI编程助手的优缺点

目前,仍有许多开发者由于种种原因对AI编程助手持排斥态度,我们确实也要承认AI编程助手有缺点,但是也有许多优点。

优点

  1. **提升效率节省时间:**AI编程助手可以快速生成代码,减少手动编写的工作量。尤其是在重复性高 和 常规逻辑的编程任务中,它能够显著提升效率,让开发者有更多时间专注于核心逻辑和创新。
  2. 代码质量的提升
    :有时候能感觉到,AI生成代码质量比我自己写的好。
  3. **加速获取知识:**通过AI编程助手,开发者可以快速获取各种编程知识和技术方案,明显缩短学习曲线。在写代码时,它也能够提供即时的建议,避免开发者长时间的搜索和查阅资料。这一点,我感受非常深刻,记得两年前学Flink和Golang时,当时扫过文档之后,对应如何实践项目还是无从下手,幸好有AI编程助手,让我快速学会了未知领域的知识,并且能快速做出项目。
  4. 向AI学习
    :开发者在与AI的交互过程中,也会不断地接触到新的代码模式和最佳实践,从而提升自己的编程能力和技术水平。

缺点

  1. 对复杂逻辑的处理能力有限
    :虽然编程助手在处理简单和常见的代码片段上的表现挺好,但是对于复杂逻辑的处理能力较弱。在涉及到复杂算法或者业务逻辑的情况下,基本上给不出合适的代码。所以,大部分时候,AI编程助手生成的代码仍然需要自己过一遍。
  2. 存在安全隐患
    :在使用AI编程助手时,需要将代码丢给AI编程助手,然后它去猜测相关代码。至于它拿到代码,会不会做点什么,我们无从得知。
  3. 容易存在依赖性
    :对于长期使用AI编程助手的开发者,很容易形成依赖性。大部分场景会养成等待AI生成的习惯,一旦离开了AI编程助手,确实有些不习惯。不过这一点算是仁者见仁智者见智吧,AI的发展是大势,就像当年的互联网一样,所有的不习惯未来都会变得像空气一样无处不在。
  4. 容易养成不思考的习惯
    :长期使用AI编程助手的开发者,除了思考业务逻辑之外,大部分的代码实现都懒得自己思考了。为了避免自己变得懒惰,每次AI助手生成代码之后,我都会翻阅一遍,再与自己的思路做个对比。不过这也不一定算缺点吧,AI的出现不就是为了解放我们的思想和生产力嘛,不就是为了让我们从一个简单的执行者,变成一个操盘者嘛。

4、为什么有的开发者不使用AI编程助手

之前看过一个数据,中国约有1000万程序员,预计有200多万在使用AI编程助手,而且数字一直在飙升。我也从一些渠道了解到有些开发者不愿意使用AI编程助手,原因如下:

  • 自动提示的灾难
    :在使用AI编程助手时,几乎每次敲击都会生成提示代码,这让许多开发者觉得AI会打断自己的思路,或者有时强迫症,非要去看一眼AI提示代码是否正确。这个痛点各大厂商都在极力解决,最近我已经明显感觉到触发提示的地方变少了,相信会越来越智能的。
  • 安全隐患
    :部分个人和企业比较担心使用AI助手会泄露自己的核心代码,所以一直不敢用。虽然各大厂商都在极力宣传自己的安全策略,极力强调自己不会存储和使用代码,但是好像没人信。
  • 不愿意跟进时代
    :有些开发者确实比较保守,故步自封,不愿意尝试新事物。我倒是觉得,不管一个新事物好坏,起码先尝试下。
  • 低估AI的能力
    :有些开发者觉得AI的能力不行,写的代码不好。我倒是觉得AI的能力一直在增强,而且某些方面比人强多了,没必要那么自信,多尝试几次,你会发现AI在写重复代码和简单逻辑方面还是很强的。把杂事儿丢给AI,自己多留点精力想想复杂业务问题,不是更香嘛。

对于部分开发者和企业担心的安全问题,我有几点想说:

  1. 大厂没必要拿你的代码做二次训练,因为大厂如果想AI助手变得更好,他需要更多优质的代码。你的代码质量未必有多好,他只会拿优质的开源代码做训练。
  2. 如果你的主营业务是卖代码,估计你会担心自己的核心资产泄露。大可不必担心。因为AI只会小片段的生成代码,AI无法生成一个项目的完整代码。
  3. 如果你担心大厂拿你的代码去做业务,那也不可能。以大厂的能力,要想做某块业务,肯定会与自己的也有业务相结合,不可能直接用你的代码。而且,要是真想做某块业务,最好的办法是收购你,不会拿你的代码去用。讲实在话,代码有时候是负债,真正值钱的是你的业务。

5、未来的超级个体时代

AI的定位一直都是助手,而且AI会越来越强大。AI未来一定会淘汰码农,但是AI一定会与优秀的开发者共生。开发者应该抓住这个时代的机会,努力让自己成为一个超级个体。

在未来的超级个体时代,知识的掌握已经不再是唯一的重要因素。随着AI技术的发展,更多的创意、资源整合能力和产品能力将成为核心竞争力。

AI编程助手能够处理大量的重复性工作,释放开发者的创造力。开发者可以将更多的时间和精力投入到创新和创意上,开发出更好的产品。

经过了这一轮的经济的洗礼,有点企业倒闭了,有的企业活下来了。即使是活下来的企业,相信也学会了更灵活的用工方式。未来,有了AI的加持,个体的能力一定会被放大。届时,企业一定更倾向于找独立的个体合作。

6、总结

本篇主要聊了几款AI编程助手、它的工作原理、它的优缺点、超级个体等等。我鼓励开发者积极拥抱AI,让自己成为一个全栈开发者和超级个体,让AI帮助自己释放更多的生产力和创意,让自己充满无限可能。

本篇完结!欢迎 关注、加微信(yclxiao)交流、全网可搜(程序员半支烟)!!!

原文链接:
https://mp.weixin.qq.com/s/NwDlNIjqeRu4OuC1jVhEkA

众所周知,本地运行 LLMs 需要下载模型(体积大),并且还比较吃硬件配置。近日 GitHub 推出了 GitHub Models 服务,让开发者可以在 GitHub 上
免费测试
Llama、Phi 3、Mistral 和 GPT-4o 等大模型。但是,目前该服务仍处于公测阶段,类似早期的 Copilot,并未完全开放。需要先提交申请(waitlist)等待审核通过后才可以使用。

虽然我还没有获得公测资格,但目测该服务应该是每天提供一定量的免费在线体验 LLMs 的次数(Playground),然后再加上云开发 Codespaces 和 Azure 服务收费。我和大家都一样,最关心的还是免费的用起来爽不爽!

回到本周的开源热搜项目,既然不能完全免费使用,不妨试试用 torchchat 在手机上运行 LLMs 聊天应用,实现随时随地、不限量地与 LLMs 聊天。还有类似 Shazam 的歌曲识别服务 seek-tune,轻松发现和下载熟悉旋律的歌曲。基于语音识别技术破解 reCAPTCHA 验证码的浏览器插件 buster,用技术打败技术。

最后,用 Rust 实现的轻量级的 LDAP 服务和直观比较两个 PDF 文件的工具,体验极简应用带来的高效与便捷。

  • 本文目录
    • 1. 开源新闻
      • 1.1 GitHub Models 在线免费测试 LLMs
    • 2. 开源热搜项目
      • 2.1 随时随地与 LLMs 聊天的 Python 库:torchchat
      • 2.2 开源的恶意流量检测平台:Maltrail
      • 2.3 破解 reCAPTCHA 验证码的浏览器插件:buster
      • 2.4 轻量级的 LDAP 实现:lldap
      • 2.5 类似 Shazam 的歌曲识别算法:seek-tune
    • 3. HelloGitHub 热评
      • 3.1 直观比较两个 PDF 文件的工具:diff-pdf
      • 3.2 在 Mac 上运行 iOS 游戏和应用的工具:PlayCover
    • 4. 结尾

1. 开源新闻

1.1 GitHub Models 在线免费测试 LLMs

GitHub Models 提供了一个在线体验大型语言模型(LLMs)的聊天应用服务(Playground),用户可以在这里在线体验、测试和运行 LLMs。此外,它还打通了 Codespaces,集成了云运行和开发 LLMs 的功能,降低了大模型开发的门槛,目前仅支持 Llama、Phi 3、Mistral 和 GPT-4o 等大模型,暂不支持上传自定义模型。

2. 开源热搜项目

2.1 随时随地与 LLMs 聊天的 Python 库:torchchat

主语言:Python

Star:2.4k

周增长:2k

该项目是由 PyTorch 团队开源的 Python 库,旨在简化大型语言模型 (LLMs) 的运行,轻松在桌面、服务器、iOS 和 Android 等平台上运行 LLMs 聊天应用。用户可以直接通过命令行与大模型交互,或启动 WebUI 在浏览器中使用。此外,基于 ExecuTorch 生成的 PTE 文件,它还能生成适用于移动设备的 LLMs 聊天应用,支持 Llama 3.1、Llama 3 和 Mistral 等大模型。

GitHub 地址→
github.com/pytorch/torchchat

2.2 开源的恶意流量检测平台:Maltrail

主语言:Python

Star:6.1k

周增长:100

这是一个用 Python 开发的恶意流量检测系统,主要用于识别和追踪可疑的网络请求。它利用公开的黑名单和自定义的列表进行实时流量监控,并提供了一个简单的 Web 界面,用于展示报告和分析结果,支持检测域名、URL、IP 或 HTTP User-Agent 等可疑信息,以及启发式分析功能可发现新型或未知的威胁。

GitHub 地址→
github.com/stamparm/maltrail

2.3 破解 reCAPTCHA 验证码的浏览器插件:buster

主语言:JavaScript

Star:7.4k

周增长:200

该项目利用语言识别技术,帮助用户自动通过 reCAPTCHA 验证码认证的浏览器插件,支持 Chrome、Edge 和 Firefox 浏览器。

GitHub 地址→
github.com/dessant/buster

2.4 轻量级的 LDAP 实现:lldap

主语言:Rust

Star:4k

周增长:100

该项目用 Rust 语言实现了一个轻量级的 LDAP(轻量级目录访问协议)服务,旨在简化用户身份验证和管理。它具有配置简单、占用资源少、友好的 Web 界面等特点,支持重置密码和 Docker 部署,默认使用 SQLite 数据库,同时兼容 MySQL 和 PostgreSQL 等数据库。

GitHub 地址→
github.com/lldap/lldap

2.5 类似 Shazam 的歌曲识别算法:seek-tune

主语言:Go

Star:1.3k

周增长:1.1k

该项目用 Go 语言实现了类似 Shazam 的歌曲识别算法,并提供了简单易用的 Web 服务。它利用音频指纹技术,能够识别用户播放的音乐,并集成了 Spotify 和 YouTube,可以一键发现并下载音乐。

GitHub 地址→
github.com/cgzirim/seek-tune

3. HelloGitHub 热评

在本章节中,我们将分享本周 HelloGitHub 网站上的热门开源项目,欢迎与我们分享你上手这些开源项目后的使用体验。

3.1 直观比较两个 PDF 文件的工具:diff-pdf

主语言:C++

这是一款用 C++ 编写的 PDF 文件比较工具。它支持两种查看方式,可以将文件内容的差异输出到一个新的 PDF 文件,或直接在 GUI 中查看。

项目详情→
hellogithub.com/repository/398f817f245e404b8ae7ad8ab7e80420

3.2 在 Mac 上运行 iOS 游戏和应用的工具:PlayCover

主语言:Swift

该项目是专为 Apple Silicon Mac 设备(M 系列芯片)设计,用于运行 iOS 应用和游戏的工具。它通过模拟 iPad 环境和键盘映射功能,让用户可以在 Mac 电脑上玩 iOS 游戏,需自行下载 IPA 文件,适用于 macOS 12.0 或更高版本。

项目详情→
hellogithub.com/repository/2bb52cdd3e5b42df9cb171a00f66863a

4. 结尾

以上就是本期「GitHub 热点速览」的全部内容,希望你能够在这里找到自己感兴趣的开源项目,如果你有其他好玩、有趣的 GitHub 开源项目想要分享,欢迎来
HelloGitHub
与我们交流和讨论。

往期回顾

前言

本文通过Codeblaze.SemanticKernel这个项目,学习如何实现ITextEmbeddingGenerationService接口,接入本地嵌入模型。

项目地址:
https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel

实践

SemanticKernel初看以为只支持OpenAI的各种模型,但其实也提供了强大的抽象能力,可以通过自己实现接口,来实现接入不兼容OpenAI格式的模型。

Codeblaze.SemanticKernel这个项目实现了ITextGenerationService、IChatCompletionService与ITextEmbeddingGenerationService接口,由于现在Ollama的对话已经支持了OpenAI格式,因此可以不用实现ITextGenerationService和IChatCompletionService来接入Ollama中的模型了,但目前Ollama的嵌入还没有兼容OpenAI的格式,因此可以通过实现ITextEmbeddingGenerationService接口,接入Ollama中的嵌入模型。

查看ITextEmbeddingGenerationService接口:

image-20240806081346110

代表了一种生成浮点类型文本嵌入的生成器。

再看看IEmbeddingGenerationService<string, float>接口:

[Experimental("SKEXP0001")]
public interface IEmbeddingGenerationService<TValue, TEmbedding> : IAIService where TEmbedding : unmanaged
{
     Task<IList<ReadOnlyMemory<TEmbedding>>> GenerateEmbeddingsAsync(IList<TValue> data, Kernel? kernel = null, CancellationToken cancellationToken = default(CancellationToken));
}

再看看IAIService接口:

image-20240806081733336

说明我们只要实现了

Task<IList<ReadOnlyMemory<TEmbedding>>> GenerateEmbeddingsAsync(IList<TValue> data, Kernel? kernel = null, CancellationToken cancellationToken = default(CancellationToken));

IReadOnlyDictionary<string, object?> Attributes { get; }

这个方法和属性就行。

学习Codeblaze.SemanticKernel中是怎么做的。

添加OllamaBase类:

public interface IOllamaBase
{
    Task PingOllamaAsync(CancellationToken cancellationToken = new());
}
public abstract class OllamaBase<T> : IOllamaBase where T : OllamaBase<T>
{
    public IReadOnlyDictionary<string, object?> Attributes => _attributes;
    private readonly Dictionary<string, object?> _attributes = new();
    protected readonly HttpClient Http;
    protected readonly ILogger<T> Logger;

    protected OllamaBase(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory)
    {
        _attributes.Add("model_id", modelId);
        _attributes.Add("base_url", baseUrl);

        Http = http;
        Logger = loggerFactory is not null ? loggerFactory.CreateLogger<T>() : NullLogger<T>.Instance;
    }

    /// <summary>
    /// Ping Ollama instance to check if the required llm model is available at the instance
    /// </summary>
    /// <param name="cancellationToken"></param>
    public async Task PingOllamaAsync(CancellationToken cancellationToken = new())
    {
        var data = new
        {
            name = Attributes["model_id"]
        };

        var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/show", data, cancellationToken).ConfigureAwait(false);

        ValidateOllamaResponse(response);

        Logger.LogInformation("Connected to Ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);
    }

    protected void ValidateOllamaResponse(HttpResponseMessage? response)
    {
        try
        {
            response.EnsureSuccessStatusCode();
        }
        catch (HttpRequestException)
        {
            Logger.LogError("Unable to connect to ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);
        }
    }
}

注意这个

public IReadOnlyDictionary<string, object?> Attributes => _attributes;

实现了接口中的属性。

添加OllamaTextEmbeddingGeneration类:

#pragma warning disable SKEXP0001
   public class OllamaTextEmbeddingGeneration(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory)
      : OllamaBase<OllamaTextEmbeddingGeneration>(modelId, baseUrl, http, loggerFactory),
           ITextEmbeddingGenerationService
  {
       public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, Kernel? kernel = null,
           CancellationToken cancellationToken = new())
      {
           var result = new List<ReadOnlyMemory<float>>(data.Count);

           foreach (var text in data)
          {
               var request = new
              {
                   model = Attributes["model_id"],
                   prompt = text
              };

               var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/embeddings", request, cancellationToken).ConfigureAwait(false);

               ValidateOllamaResponse(response);

               var json = JsonSerializer.Deserialize<JsonNode>(await response.Content.ReadAsStringAsync().ConfigureAwait(false));

               var embedding = new ReadOnlyMemory<float>(json!["embedding"]?.AsArray().GetValues<float>().ToArray());

               result.Add(embedding);
          }

           return result;
      }
  }

注意实现了GenerateEmbeddingsAsync方法。实现的思路就是向Ollama中的嵌入接口发送请求,获得embedding数组。

为了在MemoryBuilder中能用还需要添加扩展方法:

#pragma warning disable SKEXP0001
   public static class OllamaMemoryBuilderExtensions
  {
       /// <summary>
       /// Adds Ollama as the text embedding generation backend for semantic memory
       /// </summary>
       /// <param name="builder">kernel builder</param>
       /// <param name="modelId">Ollama model ID to use</param>
       /// <param name="baseUrl">Ollama base url</param>
       /// <returns></returns>
       public static MemoryBuilder WithOllamaTextEmbeddingGeneration(
           this MemoryBuilder builder,
           string modelId,
           string baseUrl
      )
      {
           builder.WithTextEmbeddingGeneration((logger, http) => new OllamaTextEmbeddingGeneration(
               modelId,
               baseUrl,
               http,
               logger
          ));

           return builder;
      }      
  }

开始使用

public async Task<ISemanticTextMemory> GetTextMemory3()
{
    var builder = new MemoryBuilder();
    var embeddingEndpoint = "http://localhost:11434";
    var cancellationTokenSource = new System.Threading.CancellationTokenSource();
    var cancellationToken = cancellationTokenSource.Token;
    builder.WithHttpClient(new HttpClient());
    builder.WithOllamaTextEmbeddingGeneration("mxbai-embed-large:335m", embeddingEndpoint);
    IMemoryStore memoryStore = await SqliteMemoryStore.ConnectAsync("memstore.db");
    builder.WithMemoryStore(memoryStore);
    var textMemory = builder.Build();
    return textMemory;
}
 builder.WithOllamaTextEmbeddingGeneration("mxbai-embed-large:335m", embeddingEndpoint);

实现了WithOllamaTextEmbeddingGeneration这个扩展方法,因此可以这么写,使用的是mxbai-embed-large:335m这个向量模型。

我使用WPF简单做了个界面,来试试效果。

找了一个新闻嵌入:

image-20240806090946822

文本向量化存入数据库中:

image-20240806091040483

现在测试RAG效果:

image-20240806091137623

image-20240806091310159

image-20240806091404424

回答的效果也还可以。

大模型使用的是在线api的Qwen/Qwen2-72B-Instruct,嵌入模型使用的是本地Ollama中的mxbai-embed-large:335m。