likes
comments
collection
share

如何利用OpenAI Embedding实现网页“相关推荐”功能?

作者站长头像
站长
· 阅读数 37

    在当今互联网的时代里,个性化已经成为吸引用户关注和提升用户体验的重要策略之一。当我们浏��网站时,经常可以看到一个名为“相关推荐”的版块,它能精准地展示出符合我们兴趣的内容。但是,您是否好奇过这些推荐是如何生成的,它们又是如何如此准确地捕捉到我们的偏好 在本文中我将为大家介绍OpanAI中的embedding,向量计算模型实现相似度/推荐等功能。

如何利用OpenAI Embedding实现网页“相关推荐”功能?

正文

    首先我们先阐述一下向量计算模型实现相似度/推荐等功能的理论依据。我们使用OpenAI的embedding接口,把我们输入的关键字变成数学向量,然后在一个空间中是可以存在多个向量的,向量与向量之间存在角度,这里我们使用cosin(cos)表示向量与向量之间的关系,众所周知cos越大,其角度越小,当两个向量的cos值越大,我们就可以理解为这两条数据的相似度越高,也就是文章内容越接近,然后我们把相似度高的数据拿出来,就可以实现推荐功能了。

    接下来我们就正式开始实现这个功能了。第一步我们先在Vscode中初始化一个后端项目,使用npm执行,然后完成一些配置项

//初始化后端
npm init -y
//安装OpenAI依赖
npm i openai
//安装dotenv依赖
npm i dotenv

创建文件app.service.mjs在这个文件中我们把模块引入项目中

// 模块化输出client 给各项ai任务调用
import OpenAI from 'openai'
import dotenv from 'dotenv'
dotenv.config({path:'.env'})


export const client = new OpenAI({
    apiKey: process.env.OPENAI_KEY,
    baseURL: 'https://api.302.ai/v1'
})

最后要记得抛出client. 接下来我们创建一个embedding,创建文件create-embeddings.mjs,这里我们的读取的数据已经写好在一个json文件中,所以这里我们使用fs文件系统读取数据

// 更年轻的fs模块
import fs from 'fs/promises';

获取app.service.mjs抛出的client

import {client} from './app.service.mjs'

在我们文件create-embedding.mjs中的主要任务是将源数据posts.json里面的所有内容计算向量,所以这里我们准备了两个变量,一个存放源数据inputFilePath,一个存放向量计算后的数据outputFilePath.现在我们读取源数据中的数据并JSON化数据,使用fs文件系统中的readFile

const data = await fs.readFile(inputFilePath, 'utf8');
const posts = JSON.parse(data)

这里我们加了一个await是因为fs/promises返回的是一个Promise对象,这里我们需要使用到await. 定义一个新数组postsWithEmbedding存放向量计算后的数据,现在我们遍历JSON化后的源数据posts并且解构数据title,category.然后使用client.embedding.create()创建一个embedding接口,这里我们需要给一个模型model和输入input,当接口embedding接口数据处理完成之后,我们把解构出来的title,category,以及向量计算后的数据存入postsWithEmbedding中。最后把数据写入outputFilePath中,我们这个创建embedding接口这个文件就算是写好了。

// 先把所有的内容计算向量
// 更年轻的fs模块
import fs from 'fs/promises';
//将openai的实例封装
import {client} from './app.service.mjs'

//源数据,麻烦
const inputFilePath = './data/posts.json';
// 整整数据 让每一个数据多一个1536维的向量数字
const outputFilePath = './data/posts_with_embedding.json';

// promisify  重点 
const data = await fs.readFile(inputFilePath, 'utf8');
const posts = JSON.parse(data)
// 新数组
const postsWithEmbedding = [];

for(const {title,category} of posts){
    const response = await client.embeddings.create({
        model: 'text-embedding-ada-002',
        // 当搜索vue是,也可以搜索到vue相关的文章 搜索vue+分类
        input: `标题 ${title} 分类 ${category}`
    })
    postsWithEmbedding.push({
        title,
        category,
        embedding: response.data[0].embedding  // 取得embedding的第一个元素
    })
}


await fs.writeFile(outputFilePath, JSON.stringify(postsWithEmbedding))

// console.log(data);

最后一部分我们实现数据查询就好了,创建文件semantic-search.mjs 获取所有的向量计算后的数据

const posts = JSON.parse(await fs.readFile(inputFilePath));

计算向量的余弦相似度函数(这个函数我们直接在网上找就好了)

const cosineSimilarity = (v1, v2) => {
    // 计算向量的点积
    const dotProduct = v1.reduce((acc, curr, i) => acc + curr * v2[i], 0);
  
    // 计算向量的长度
    const lengthV1 = Math.sqrt(v1.reduce((acc, curr) => acc + curr * curr, 0));
    const lengthV2 = Math.sqrt(v2.reduce((acc, curr) => acc + curr * curr, 0));
  
    // 计算余弦相似度
    const similarity = dotProduct / (lengthV1 * lengthV2);
  
    return similarity;
  };

然后我再定义一个变量。用来存放我们想要查询的内容,并进行向量计算。最后解构出向量值

const searchText = 'vue组件开发'
//先向量化
const response = await client.embeddings.create({
    model:'text-embedding-ada-002',
    input: searchText
})
//要推荐的原文embedding
const { embedding } = response.data[0]

最后一步就是遍历数据,对数据中进行一个排序,取得前三项

const results = posts.map(item=>({
    ...item,
    similarity:cosineSimilarity(embedding,item.embedding)
}))

    .sort((a,b)=>a.similarity - b.similarity)
    .reverse()
    .slice(0,3)
    .map((item,index)=>`${index+1},${item.title},${item.category}`)
    .join('\n')


console.log(results);

完整代码

// nlp 相似性搜索
import fs from 'fs/promises'
import { client} from './app.service.mjs'

const inputFilePath = './data/posts_with_embedding.json';

// select * 让数据在内存之中
const posts = JSON.parse(await fs.readFile(inputFilePath));

// 计算向量的余弦相似度 cosine 
const cosineSimilarity = (v1, v2) => {
    // 计算向量的点积
    const dotProduct = v1.reduce((acc, curr, i) => acc + curr * v2[i], 0);
  
    // 计算向量的长度
    const lengthV1 = Math.sqrt(v1.reduce((acc, curr) => acc + curr * curr, 0));
    const lengthV2 = Math.sqrt(v2.reduce((acc, curr) => acc + curr * curr, 0));
  
    // 计算余弦相似度
    const similarity = dotProduct / (lengthV1 * lengthV2);
  
    return similarity;
  };
// vue | 组件 | 开发  LLM 基于语义搜索,而不是简单的文字匹配
const searchText = 'vue组件开发'
//先向量化
const response = await client.embeddings.create({
    model:'text-embedding-ada-002',
    input: searchText
})
//要推荐的原文embedding
const { embedding } = response.data[0]
// posts每一项embedding 进行cosin计算
const results = posts.map(item=>({
    ...item,
    similarity:cosineSimilarity(embedding,item.embedding)
}))

    .sort((a,b)=>a.similarity - b.similarity)
    .reverse()
    .slice(0,3)
    .map((item,index)=>`${index+1},${item.title},${item.category}`)
    .join('\n')


console.log(results);

如何利用OpenAI Embedding实现网页“相关推荐”功能?

感谢大家阅读,若有不足,恳请各位指出!!!

如何利用OpenAI Embedding实现网页“相关推荐”功能?

转载自:https://juejin.cn/post/7390319492120985636
评论
请登录