diff --git a/package.json b/package.json index 2a4ba85..5335ecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/ai", - "version": "0.0.18", + "version": "0.0.19", "description": "AI Center Services", "main": "index.js", "basename": "/root/ai-center-services", diff --git a/src/test/aliyun/test.ts b/src/test/aliyun/test.ts deleted file mode 100644 index e984cc0..0000000 --- a/src/test/aliyun/test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { BailianProvider } from '../../provider/index.ts' -import dotenv from 'dotenv'; - -dotenv.config(); -import { App } from '@kevisual/router' -import util from 'node:util'; -const ai = new BailianProvider({ - apiKey: process.env.BAILIAN_API_KEY || '', - model: 'qwen-turbo-latest', - baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1' -}) - - -// const res = await ai.chat([ - -// { -// role: 'user', -// content: `1+1等于多少?` -// }, - -// ], -// ) -// // console.log('AI Response:', res); -// const content = res.choices[0].message?.content || '' - -// console.log(util.inspect(res, { depth: null })) - -// console.log('responseText', ai.responseText) - - -// const res = await ai.chatStream([ - -// { -// role: 'user', -// content: `1+1等于多少?` -// }, - -// ], -// ) -// // console.log('AI Response:', res); -// export const readStream = async (chatStream) => { -// let buffer = ''; -// for await (const chunk of chatStream) { -// // chunk 已经是解码后的字符串,直接拼接即可 -// buffer += chunk; -// } -// console.log('AI Response:', buffer); -// }; - -// await readStream(res); - -const embe = await ai.generateEmbeddingCore([ - '你好,世界!', - 'Hello, world!', -], { - model: 'text-embedding-v4' -}); - -console.log('Embedding Response:', util.inspect(embe, { depth: null })); \ No newline at end of file diff --git a/src/test/chunks/01-get.ts b/src/test/chunks/01-get.ts deleted file mode 100644 index 65e0128..0000000 --- a/src/test/chunks/01-get.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { getChunks } from '../../provider/utils/chunk.ts'; - -const str = 'Hello world this is a test 你好沙盒 very big'; - - -const str2 = `不能直接使用 tiktoken(OpenAI的分词器)来计算 Qwen 模型的 Token 数量,因为两者的分词规则(Tokenization)和词表(Vocabulary)完全不同。 - -为什么不能混用? -词表不同 - -tiktoken 是 OpenAI 为 GPT 系列设计的(如 gpt-3.5-turbo, gpt-4),其词表针对英语和代码优化。 - -Qwen 使用独立训练的 BPE 词表,对中文、多语言的支持更友好,分词粒度可能不同。 - -分词结果差异大 -同一段文本,tiktoken 和 Qwen 的分词结果可能完全不同。例如: - -OpenAI (tiktoken): "你好" → ['你', '好'](2 Tokens) - -Qwen: "你好" → ['你好'](1 Token,如果词表中包含该组合) - -性能问题 -即使强制使用 tiktoken 计算 Qwen 的 Token,结果也不准确,可能导致: - -输入超出模型上下文限制(因统计偏差)。 - -API 计费或本地推理时出现意外错误。 - -正确方法:用 Qwen 的分词器 -通过 Hugging Face transformers 加载 Qwen 的原生分词器: - -python -复制 -from transformers import AutoTokenizer - -# 加载 Qwen 的分词器(以 Qwen-7B 为例) -tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B", trust_remote_code=True) - -text = "你好,Qwen模型!" -tokens = tokenizer.tokenize(text) # 查看分词结果 -token_count = len(tokenizer.encode(text, add_special_tokens=False)) - -print("分词结果:", tokens) -print("Token数量:", token_count) -常见问题 -为什么需要 trust_remote_code=True? -Qwen 的分词器是自定义实现的(非 Hugging Face 原生),此参数允许从模型仓库加载运行代码。 - -其他语言的 Token 计算? -Qwen 对非英语(如中文、日文)的分词效率较高,但仍需用其原生分词器统计。 - -与 tiktoken 的速度对比? -tiktoken 是纯 Python 实现,速度较快;Qwen 的分词器基于 Hugging Face,可能稍慢但对齐模型需求。 - -总结 -禁止混用:tiktoken ≠ Qwen 分词器。 - -始终使用模型配套工具:Qwen 需通过 transformers 加载其官方分词器。 - -中文场景特别注意:Qwen 对中文的分词更高效,直接使用可避免偏差。 - -如果需要验证分词规则,可通过 tokenizer.vocab 查看词表内容(但注意词表通常较大)。` - -const chunks = getChunks(str2); -console.log(chunks); diff --git a/src/test/common.ts b/src/test/common.ts deleted file mode 100644 index 09d8db5..0000000 --- a/src/test/common.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Jimen } from "../jimeng/index.ts" -import dotenv from 'dotenv'; -dotenv.config(); - -const jimeng = new Jimen({ - token: process.env.JIMENG_TOKEN, -}) - -console.log("Generating image..."); - -await jimeng.generateImage({ - prompt: "创建一幅未来城市的数字艺术作品,充满科技感和创新元素,色彩鲜艳,细节丰富", - resolution: "2k" -}).then((res) => { - console.log("Image generation response:", res); -}).catch((err) => { - console.error("Error generating image:", err); -}); \ No newline at end of file diff --git a/src/test/encrypt/index.ts b/src/test/encrypt/index.ts deleted file mode 100644 index 99b3f84..0000000 --- a/src/test/encrypt/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { encryptAES, decryptAES } from '../..//provider/utils/parse-config.ts'; - -const plainx = process.env.API_KEY; -const decryptKey = process.env.DECRYPT_KEY; -const encrypt = encryptAES(plainx, decryptKey); -console.log('encrypt', encrypt); - -const decrypt = decryptAES(encrypt, decryptKey); -console.log(decrypt); diff --git a/src/test/func-call/curl.sh b/src/test/func-call/curl.sh deleted file mode 100644 index f9f00ae..0000000 --- a/src/test/func-call/curl.sh +++ /dev/null @@ -1,35 +0,0 @@ -curl --request POST \ - --url https://api.siliconflow.cn/v1/chat/completions \ - --header 'Authorization: Bearer sk-qbiigkzoaamuqxtwlgkugodncebkfbosemadfubjrseobpvx' \ - --header 'Content-Type: application/json' \ - --data '{ - "model": "Qwen/Qwen3-14B", - "messages": [ - { - "role": "user", - "content": "计算a+b的值" - } - ], - "stream": false, - "max_tokens": 512, - "stop": null, - "temperature": 0.7, - "top_p": 0.7, - "top_k": 50, - "frequency_penalty": 0.5, - "n": 1, - "response_format": { - "type": "text" - }, - "tools": [ - { - "type": "function", - "function": { - "description": "计算a,b,c算法的值,a=1,b=2,c=3", - "name": "compouted", - "parameters": {}, - "strict": false - } - } - ] -}' \ No newline at end of file diff --git a/src/test/func-call/demo.ts b/src/test/func-call/demo.ts deleted file mode 100644 index 6b91d7f..0000000 --- a/src/test/func-call/demo.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { SiliconFlow } from '../../provider/chat-adapter/siliconflow.ts'; -import { Ollama } from '../../provider/chat-adapter/ollama.ts'; -import dotenv from 'dotenv'; - -dotenv.config(); -const siliconflow = new SiliconFlow({ - apiKey: process.env.SILICONFLOW_API_KEY, - model: 'Qwen/Qwen3-14B', -}); -const ollama = new Ollama({ - model: 'qwen3:32b', - apiKey: process.env.OLLAMA_API_KEY, - baseURL: process.env.OLLAMA_BASE_URL, -}); -const main = async () => { - const usage = await siliconflow.getUsageInfo(); - console.log(usage); -}; -// 1. 定义工具函数 -const availableFunctions: Record Promise> = { - get_time: async (args: { location: string }) => { - // 模拟API调用 - console.log('time', args); - return { - time: '2022-03-22 12:00:00', - }; - }, - get_location: async (args: { symbol: string }) => { - // 模拟API调用 - console.log('location', args); - return { - city: 'Beijing', - }; - }, -}; - -// main(); -const funcCall = async (model = siliconflow) => { - const tools = [ - { - type: 'function', - function: { - name: 'get_time', - description: '获取当前时间', - parameters: { - type: 'object', - properties: { - place: { - type: 'string', - description: '位置', - }, - }, - required: ['place'], - }, - }, - }, - { - type: 'function', - function: { - name: 'get_location', - description: '获取当前位置', - // parameters: {}, - parameters: {}, - strict: false, - }, - }, - ]; - const messages: any[] = [{ role: 'user', content: '获取当前位置的当前时间' }]; - const res = await model.chat(messages, { - tools: tools as any, - }); - console.log(res.choices[0]); - const assistantMessage = res.choices[0].message; - const finish_reason = res.choices[0].finish_reason; - messages.push(assistantMessage); - let toolCalls = assistantMessage.tool_calls; - console.log("toolCalls", JSON.stringify(toolCalls)); - let maxRetries = 3; - while (toolCalls && toolCalls.length > 0) { - // 处理每个函数调用 - for (const toolCall of toolCalls) { - const functionName = toolCall.function.name; - const functionArgs = JSON.parse(toolCall.function.arguments); - // 调用本地函数 - const functionResponse = await availableFunctions[functionName](functionArgs); - // 将结果添加到消息历史 - messages.push({ - role: 'tool', - name: functionName, - content: JSON.stringify(functionResponse), - tool_call_id: toolCall.id, - }); - } - - // 第二次调用 - 将函数结果发送给模型获取最终回复 - const secondResponse = await model.chat(messages, { - tools: tools as any, - }); - - const finalMessage = secondResponse.choices[0].message; - messages.push(finalMessage); - const _toolCalls = finalMessage.tool_calls; - console.log("toolCalls", JSON.stringify(toolCalls) ,finalMessage.role); - toolCalls = _toolCalls ? _toolCalls : []; - maxRetries--; - if (maxRetries <= 0) { - break; - } - - console.log('tool calls', toolCalls); - } - - console.log(messages); -}; - -funcCall(ollama as any); diff --git a/src/test/model-scope/index.ts b/src/test/model-scope/index.ts deleted file mode 100644 index 7f28630..0000000 --- a/src/test/model-scope/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ModelScope } from '../../provider/chat-adapter/model-scope.ts'; -import { logger } from '../../modules/logger.ts'; -import util from 'util'; -import { config } from 'dotenv'; -config(); - -const chat = new ModelScope({ - apiKey: process.env.MODEL_SCOPE_API_KEY, - model: 'Qwen/Qwen2.5-Coder-32B-Instruct', -}); - -// chat.chat([{ role: 'user', content: 'Hello, world! 1 + 1 equals ?' }]); -const chatMessage = [{ role: 'user', content: 'Hello, world! 1 + 1 equals ?' }]; - -const main = async () => { - const res = await chat.test(); - logger.info('test', res); -}; - -main(); -const mainChat = async () => { - const res = await chat.chat(chatMessage as any); - logger.info('chat', res); -}; - -// mainChat(); diff --git a/src/test/ollama-knowledge.ts b/src/test/ollama-knowledge.ts deleted file mode 100644 index de514ed..0000000 --- a/src/test/ollama-knowledge.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Knowledge } from '../../../../src/provider/knowledge/knowledge.ts'; -import fs from 'fs'; -import dotenv from 'dotenv'; - -dotenv.config(); -const knowledge = new Knowledge({ - embeddingModel: 'bge-m3:latest', - baseURL: 'https://ollama.xiongxiao.me/v1', - model: 'qwq:latest', - apiKey: process.env.OLLAMA_API_KEY, -}); - -const main = async () => { - const res = await knowledge.generateEmbeddingCore('Hello world this is a test 你好沙盒 very big'); - fs.writeFileSync('docs/embedding.json', JSON.stringify(res, null, 2)); - console.log(res); -}; - -main(); - -const main2 = async () => { - const text1 = 'Hello, world! this is a test'; - const text2 = 'Hello, world! this is a test 2'; - const text3 = 'Hello, world! this is a test 3'; - const text4 = 'Hello, world! this is a test 4'; - const text5 = 'Hello, world! this is a test 5'; - const text6 = 'Hello, world! this is a test 6'; - const text7 = 'Hello, world! this is a test 7'; - const text8 = 'Hello, world! this is a test 8'; - const text9 = 'Hello, world! this is a test 9'; - const text10 = 'Hello, world! this is a test 10'; - const res = await knowledge.generateEmbeddingCore([text1, text2, text3, text4, text5, text6, text7, text8, text9, text10]); - fs.writeFileSync('docs/embedding2.json', JSON.stringify(res, null, 2)); - console.log(res); -}; - -// main2(); diff --git a/src/test/ollama.ts b/src/test/ollama.ts deleted file mode 100644 index c71658d..0000000 --- a/src/test/ollama.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Ollama } from '../../../../src/provider/chat-adapter/ollama.ts'; -import util from 'util'; -const chat = new Ollama({ - baseURL: 'https://ollama.xiongxiao.me/v1', - apiKey: 'xiongxiao2233', - model: 'qwq:latest', -}); - -// chat.chat([{ role: 'user', content: 'Hello, world!' }]); - -const main = async () => { - const res = await chat.test(); - console.log(util.inspect(res, { depth: null, colors: true })); -}; - -// main(); - -const getJson = async () => { - const res = await chat.chat( - [ - { role: 'system', content: '把发送的数据,返回给我对应的json,只处理完发送的数据。如果发送了多个,给我一个数组' }, - // { role: 'user', content: '{"name":"John","age":30}' }, - { role: 'user', content: 'name: 张三' }, - { role: 'user', content: 'name: 李四, age: 18' }, - ], - { - response_format: { - type: 'json_schema', - json_schema: { - name: 'user', - description: '用户信息', - schema: { - type: 'object', - // properties: { - // name: { type: 'string' }, - // // age: { type: 'number' }, - // }, - // // required: ['name', 'age'], - // required: ['name'], - properties: { - name: { type: 'string' }, - age: { type: 'number' }, - }, - required: ['name', 'age'], - }, - }, - }, - n: 10, - }, - ); - console.log(util.inspect(res, { depth: null, colors: true })); -}; - -// getJson(); - -const createChat1 = async () => { - const res = await chat.chat( - [ - { role: 'user', content: 'a=1, b=2, c=3' }, - { role: 'user', content: 'a+b+c=?' }, - { role: 'assistant', content: '给定的值为 \\( a = 1 \\), \\( b = 2 \\), \\( c = 3 \\)。\n' + '\n' + '因此,\\( a + b + c = 1 + 2 + 3 = 6 \\)。' }, - { role: 'user', content: 'a+b+c+4=?' }, - ], - { - model: 'qwen2.5:7b', - }, - ); - console.log(util.inspect(res, { depth: null, colors: true })); -}; - -// createChat1(); - -const getTags = async () => { - const res = await chat.listModels(); - console.log(util.inspect(res, { depth: null, colors: true })); -}; - -// getTags(); - -const getRunModels = async () => { - const res = await chat.listRunModels(); - console.log('current', new Date().toISOString()); - console.log(util.inspect(res, { depth: null, colors: true })); -}; - -// getRunModels(); diff --git a/src/test/provider/index.ts b/src/test/provider/index.ts deleted file mode 100644 index e099a87..0000000 --- a/src/test/provider/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ProviderManager } from '../..//provider/index.ts'; -import { config } from 'dotenv'; -config(); -const providerConfig = { provider: 'ModelScope', model: 'Qwen/Qwen2.5-Coder-32B-Instruct', apiKey: process.env.MODEL_SCOPE_API_KEY }; -const provider = await ProviderManager.createProvider(providerConfig); -const result = await provider.chat([{ role: 'user', content: '你好' }]); -console.log(result); diff --git a/src/utils/json.ts b/src/utils/json.ts deleted file mode 100644 index 560e572..0000000 --- a/src/utils/json.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 尝试从字符串中提取JSON对象 - */ -export const getJsonFromString = (str: string) => { - try { - const jsonMatch = str.match(/```json\s*([\s\S]*?)\s*```/); - if (jsonMatch && jsonMatch[1]) { - return JSON.parse(jsonMatch[1]); - } - } catch (error) {} - return null; -};