From 57d88cbb09535216e3296694c213c1ae6de9b009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Sat, 31 Jan 2026 00:01:28 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d505e73..038e2d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "toonflow-serve", - "version": "1.0.2", + "version": "1.0.3", "description": "ToonFlow Serve - Electron Application", "main": "build/main.js", "author": "ToonFlow Team", From b44e7b6e597a3fbd6086f707a8976c997639d383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Sat, 31 Jan 2026 16:40:57 +0800 Subject: [PATCH 2/4] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E7=94=9F=E6=88=90=E8=A7=86=E9=A2=91=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/lib/fixDB.ts | 13 +++++++++++++ src/lib/initDB.ts | 1 + src/types/database.d.ts | 3 ++- src/utils/ai.ts | 2 +- src/utils/db.ts | 2 ++ 6 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/lib/fixDB.ts diff --git a/package.json b/package.json index 038e2d0..60ce3c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "toonflow-serve", - "version": "1.0.3", + "version": "1.0.4", "description": "ToonFlow Serve - Electron Application", "main": "build/main.js", "author": "ToonFlow Team", diff --git a/src/lib/fixDB.ts b/src/lib/fixDB.ts new file mode 100644 index 0000000..92748b2 --- /dev/null +++ b/src/lib/fixDB.ts @@ -0,0 +1,13 @@ +import { Knex } from "knex"; + +export default async (knex: Knex): Promise => { + const hasTime = await knex.schema.hasColumn("t_video", "time"); + if (!hasTime) { + await knex.schema.alterTable("t_video", (table) => { + table.integer("time"); + }); + console.log("字段 'time' 已添加到 t_video 表"); + } else { + console.log("t_video 表已存在 'time' 字段"); + } +}; diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index 9ca7800..818b050 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -151,6 +151,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => table.text("firstFrame"); table.text("storyboardImgs"); table.text("model"); + table.integer("time"); table.integer("state"); table.integer("scriptId"); table.integer("configId"); // 关联的视频配置ID diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 710c68b..4bc0401 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,4 @@ -// @db-hash f95df46ccfda3c7f0b2a9cefdc399035 +// @db-hash b6b4d8cdc25a2f4d60f1c239cd7e7060 //该文件由脚本自动生成,请勿手动修改 export interface t_assets { @@ -128,6 +128,7 @@ export interface t_video { 'scriptId'?: number | null; 'state'?: number | null; 'storyboardImgs'?: string | null; + 'time'?: number | null; } export interface t_videoConfig { 'createTime'?: number | null; diff --git a/src/utils/ai.ts b/src/utils/ai.ts index 7fb78ca..d7b4eda 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -239,7 +239,7 @@ const generateVideoWithConfig = async (config: VideoConfig, configItem: { model: const createRes = await axios.post( baseURL ?? "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks", { - model, + model: "doubao-seedance-1-5-pro-251215", content: [ { type: "text", text: config.prompt }, ...(doubaoConfig.imageBase64 diff --git a/src/utils/db.ts b/src/utils/db.ts index 7d13268..efca2e2 100644 --- a/src/utils/db.ts +++ b/src/utils/db.ts @@ -4,6 +4,7 @@ import fs from "fs"; import path from "path"; import knex from "knex"; import initDB from "@/lib/initDB"; +import fixDB from "@/lib/fixDB"; import type { DB } from "@/types/database"; import crypto from "crypto"; @@ -40,6 +41,7 @@ const db = knex({ }); initDB(db); +fixDB(db); if (process.env.NODE_ENV == "dev") initKnexType(db); From 07d209d1fecbba6ef5dc03962fa3f432fbfabb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Sat, 31 Jan 2026 17:11:02 +0800 Subject: [PATCH 3/4] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8D=E7=81=AB=E5=B1=B1?= =?UTF-8?q?=E5=BC=95=E6=93=8E=E5=9B=BE=E5=83=8F=E7=94=9F=E6=88=90=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=97=A0=E6=B3=95=E4=BD=BF=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/routes/other/testImage.ts | 3 ++- src/utils/ai.ts | 24 ++++++++++++++++++------ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 60ce3c8..2c7aced 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "toonflow-serve", - "version": "1.0.4", + "version": "1.0.5", "description": "ToonFlow Serve - Electron Application", "main": "build/main.js", "author": "ToonFlow Team", diff --git a/src/routes/other/testImage.ts b/src/routes/other/testImage.ts index 54d1be8..d0d3a6e 100644 --- a/src/routes/other/testImage.ts +++ b/src/routes/other/testImage.ts @@ -36,7 +36,8 @@ export default router.post( ); res.status(200).send(success(contentStr)); } catch (err: any) { - res.status(500).send(error(err.error.message || "模型调用失败")); + const message = err?.response?.data?.error?.message || err?.error?.message || "模型调用失败"; + res.status(500).send(error(message)); } }, ); diff --git a/src/utils/ai.ts b/src/utils/ai.ts index d7b4eda..a0488aa 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -112,13 +112,25 @@ const uploadBase64ToRunninghub = async (base64Image: string, apiKey: string, bas const generators = { volcengine: async (config: ImageConfig, apiKey: string, baseURL: string, model: string) => { + if (config.size == "1K") config.size = "2K"; apiKey = apiKey.replace("Bearer ", ""); - const res = await axios.post( - `https://api.volcengineapi.com/v1/images/generations`, - { model, prompt: config.systemPrompt, image: config.imageBase64, size: config.size, watermark: false }, - { headers: { Authorization: `Bearer ${apiKey}` } }, - ); - return res.data[0].url; + const body: Record = { + model, + prompt: config.prompt, + size: config.size, + response_format: "url", + sequential_image_generation: "disabled", + stream: false, + watermark: false, + }; + // 图生图:存在图片时添加 image 字段 + if (config.imageBase64) { + body.image = config.imageBase64; + } + const res = await axios.post(`https://ark.cn-beijing.volces.com/api/v3/images/generations`, body, { + headers: { Authorization: `Bearer ${apiKey}` }, + }); + return res.data.data[0].url; }, gemini: async (config: ImageConfig, apiKey: string, baseURL: string, model: string) => { From e57728b1c584599e6d43aafa54283c7391c7a5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Tue, 3 Feb 2026 18:27:09 +0800 Subject: [PATCH 4/4] no message --- README.md | 6 - package.json | 8 + src/agents/storyboard/generateImageTool.ts | 88 ++++- src/lib/fixDB.ts | 14 +- src/routes/other/testAI.ts | 56 ++- src/routes/other/testImage.ts | 3 - src/routes/setting/getSetting.ts | 2 +- src/utils.ts | 8 +- src/utils/ai/modelList.ts | 414 +++++++++++++++++++++ src/utils/ai/text.ts | 88 +++++ src/utils/getConfig copy.ts | 43 +++ src/utils/getConfig.ts | 73 ++-- yarn.lock | 144 ++++++- 13 files changed, 871 insertions(+), 76 deletions(-) create mode 100644 src/utils/ai/modelList.ts create mode 100644 src/utils/ai/text.ts create mode 100644 src/utils/getConfig copy.ts diff --git a/README.md b/README.md index b274f85..802a9ab 100644 --- a/README.md +++ b/README.md @@ -260,12 +260,6 @@ pm2 monit # 监控面板 yarn dev #端口60000 ``` - - 使用 Bun 快速运行开发服务: - - ```bash - yarn bun:dev #端口60000 - ``` - 4. **项目打包** - 编译并生成 TypeScript 文件: diff --git a/package.json b/package.json index 2c7aced..a005f94 100644 --- a/package.json +++ b/package.json @@ -22,13 +22,19 @@ "license": "bun run scripts/license.ts" }, "dependencies": { + "@ai-sdk/anthropic": "^3.0.35", + "@ai-sdk/deepseek": "^2.0.17", + "@ai-sdk/google": "^3.0.20", + "@ai-sdk/openai": "^3.0.25", "@aigne/core": "^1.72.0", "@aigne/openai": "^0.16.16", "@langchain/core": "^1.1.15", "@langchain/openai": "^1.2.1", "@rmp135/sql-ts": "^2.2.0", + "ai": "^6.0.67", "axios": "^1.13.2", "axios-retry": "^4.5.0", + "best-effort-json-parser": "^1.2.1", "better-sqlite3": "^12.6.2", "cors": "^2.8.5", "dotenv": "^17.2.3", @@ -42,8 +48,10 @@ "knex": "^3.1.0", "langchain": "^1.2.10", "morgan": "^1.10.1", + "qwen-ai-provider": "^0.1.1", "sharp": "^0.34.5", "sqlite3": "^5.1.7", + "zhipu-ai-provider": "^0.2.2", "zod": "^4.3.5" }, "devDependencies": { diff --git a/src/agents/storyboard/generateImageTool.ts b/src/agents/storyboard/generateImageTool.ts index e90023a..151c830 100644 --- a/src/agents/storyboard/generateImageTool.ts +++ b/src/agents/storyboard/generateImageTool.ts @@ -115,19 +115,91 @@ async function mergeImages(imagePaths: string[]): Promise { return compressImage(mergedImage); } -// 处理图片列表,确保不超过10张且每张不超过3MB +// 进一步压缩单张图片到指定大小 +async function compressToSize(buffer: Buffer, targetSize: number): Promise { + if (buffer.length <= targetSize) { + return buffer; + } + + const metadata = await sharp(buffer).metadata(); + let quality = 80; + let scale = 1.0; + let compressedBuffer = buffer; + + // 先尝试降低质量 + while (compressedBuffer.length > targetSize && quality > 10) { + compressedBuffer = await sharp(buffer).jpeg({ quality }).toBuffer(); + quality -= 10; + } + + // 如果还是太大,缩小尺寸 + while (compressedBuffer.length > targetSize && scale > 0.2) { + scale -= 0.1; + const newWidth = Math.round((metadata.width || 1000) * scale); + const newHeight = Math.round((metadata.height || 1000) * scale); + compressedBuffer = await sharp(buffer) + .resize(newWidth, newHeight, { fit: "inside" }) + .jpeg({ quality: Math.max(quality, 20) }) + .toBuffer(); + } + + return compressedBuffer; +} + +// 确保图片列表总大小不超过指定限制 +async function ensureTotalSizeLimit(buffers: Buffer[], maxTotalBytes: number = 10 * 1024 * 1024): Promise { + let totalSize = buffers.reduce((sum, buf) => sum + buf.length, 0); + + if (totalSize <= maxTotalBytes) { + return buffers; + } + + // 计算每张图片的平均目标大小 + const avgTargetSize = Math.floor(maxTotalBytes / buffers.length); + + // 按大小降序排列,优先压缩大图片 + const indexedBuffers = buffers.map((buf, idx) => ({ buf, idx, size: buf.length })); + indexedBuffers.sort((a, b) => b.size - a.size); + + const result = [...buffers]; + + for (const item of indexedBuffers) { + totalSize = result.reduce((sum, buf) => sum + buf.length, 0); + if (totalSize <= maxTotalBytes) { + break; + } + + // 计算这张图片需要压缩到的目标大小 + const excessSize = totalSize - maxTotalBytes; + const targetSize = Math.max(item.buf.length - excessSize, avgTargetSize, 100 * 1024); // 最小100KB + + if (item.buf.length > targetSize) { + result[item.idx] = await compressToSize(item.buf, targetSize); + } + } + + return result; +} + +// 处理图片列表,确保不超过10张且每张不超过3MB,总大小不超过10MB async function processImages(images: ImageInfo[]): Promise { const maxImages = 10; + let processedBuffers: Buffer[]; + if (images.length <= maxImages) { const buffers = await Promise.all(images.map((img) => u.oss.getFile(img.filePath))); - return Promise.all(buffers.map((buffer) => compressImage(buffer))); + processedBuffers = await Promise.all(buffers.map((buffer) => compressImage(buffer))); + } else { + const mergeStartIndex = maxImages - 1; + const firstBuffers = await Promise.all(images.slice(0, mergeStartIndex).map((img) => u.oss.getFile(img.filePath))); + const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer))); + const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath); + const mergedImage = await mergeImages(imagesToMergeList); + processedBuffers = [...compressedFirstImages, mergedImage]; } - const mergeStartIndex = maxImages - 1; - const firstBuffers = await Promise.all(images.slice(0, mergeStartIndex).map((img) => u.oss.getFile(img.filePath))); - const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer))); - const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath); - const mergedImage = await mergeImages(imagesToMergeList); - return [...compressedFirstImages, mergedImage]; + + // 确保总大小不超过10MB + return ensureTotalSizeLimit(processedBuffers); } // 使用 AI 过滤与分镜相关的资产 diff --git a/src/lib/fixDB.ts b/src/lib/fixDB.ts index 92748b2..501a6f6 100644 --- a/src/lib/fixDB.ts +++ b/src/lib/fixDB.ts @@ -1,13 +1,17 @@ import { Knex } from "knex"; export default async (knex: Knex): Promise => { - const hasTime = await knex.schema.hasColumn("t_video", "time"); - if (!hasTime) { + const videoHasTime = await knex.schema.hasColumn("t_video", "time"); + if (!videoHasTime) { await knex.schema.alterTable("t_video", (table) => { table.integer("time"); }); - console.log("字段 'time' 已添加到 t_video 表"); - } else { - console.log("t_video 表已存在 'time' 字段"); + } + + const configHasIndex = await knex.schema.hasColumn("t_config", "index"); + if (configHasIndex) { + await knex.schema.alterTable("t_config", (table) => { + table.dropColumn("index"); + }); } }; diff --git a/src/routes/other/testAI.ts b/src/routes/other/testAI.ts index e32ceaa..b64db1d 100644 --- a/src/routes/other/testAI.ts +++ b/src/routes/other/testAI.ts @@ -1,12 +1,14 @@ import express from "express"; import { success, error } from "@/lib/responseFormat"; -import { createAgent } from "langchain"; -import { openAI } from "@/agents/models"; -import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai"; import { validateFields } from "@/middleware/middleware"; +import u from "@/utils"; import { z } from "zod"; +import { generateText, Output, tool, stepCountIs } from "ai"; const router = express.Router(); +import { createOpenAI } from "@ai-sdk/openai"; +import { createDeepSeek } from "@ai-sdk/deepseek"; + // 检查语言模型 export default router.post( "/", @@ -17,24 +19,42 @@ export default router.post( }), async (req, res) => { const { modelName, apiKey, baseURL } = req.body; - const ai = new OpenAIChatModel({ - apiKey: apiKey, - baseURL: baseURL, - model: modelName, - modelOptions: { temperature: 0.7 }, + + const getWeatherTool = tool({ + // strict: true, + description: "Get the weather in a location", + inputSchema: z.object({ + location: z.string().describe("The location to get the weather for"), + }), + execute: async ({ location }) => { + return { + location, + temperature: 72 + Math.floor(Math.random() * 21) - 10, + }; + }, }); try { - const data = await ai.invoke({ - messages: [ - { - role: "user", - content: "hello", + const { reply } = await u.ai.text.invoke( + { + prompt: "请调用工具获取北京的天气,并回答我多少气温", + tools: { getWeatherTool }, + output: { + reply: z.string().describe("回复内容"), }, - ], - }); - res.status(200).send(success(data)); - } catch (err: any) { - res.status(500).send(error(err.error.message || "模型调用失败")); + }, + { + model: modelName, + apiKey, + baseURL, + }, + ); + console.log("%c Line:52 🍐 reply", "background:#ffdd4d", reply); + res.status(200).send(success(reply)); + } catch (err) { + console.log(err); + if (typeof err === "string") return res.status(500).send(error(err)); + const msg = err instanceof Error ? err.message : (err as any)?.error?.message; + return res.status(500).send(error(msg || "未知错误")); } }, ); diff --git a/src/routes/other/testImage.ts b/src/routes/other/testImage.ts index d0d3a6e..11d52f3 100644 --- a/src/routes/other/testImage.ts +++ b/src/routes/other/testImage.ts @@ -1,9 +1,6 @@ import express from "express"; import { success, error } from "@/lib/responseFormat"; import u from "@/utils"; -import { createAgent } from "langchain"; -import { openAI } from "@/agents/models"; -import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai"; import { validateFields } from "@/middleware/middleware"; import { z } from "zod"; const router = express.Router(); diff --git a/src/routes/setting/getSetting.ts b/src/routes/setting/getSetting.ts index 8d0b990..7110d63 100644 --- a/src/routes/setting/getSetting.ts +++ b/src/routes/setting/getSetting.ts @@ -15,7 +15,7 @@ export default router.post( const settingData = await u.db("t_setting").select("*"); - const configData = await u.db("t_config").where("userId", userId).select("*").orderBy("index", "asc"); + const configData = await u.db("t_config").where("userId", userId).select("*") ; const parsedData = settingData.map((item) => ({ ...item, diff --git a/src/utils.ts b/src/utils.ts index 2957df8..e9f14c6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,16 +1,20 @@ import db from "@/utils/db"; import oss from "@/utils/oss"; -import * as ai from "@/utils/ai"; +// import * as ai from "@/utils/ai"; import editImage from "@/utils/editImage"; import number2Chinese from "@/utils/number2Chinese"; import deleteOutline from "@/utils/deleteOutline"; import getConfig from "./utils/getConfig"; import { v4 as uuid } from "uuid"; +import AIText from "@/utils/ai/text"; + export default { db, oss, - ai, + ai: { + text: AIText, + }, editImage, number2Chinese, deleteOutline, diff --git a/src/utils/ai/modelList.ts b/src/utils/ai/modelList.ts new file mode 100644 index 0000000..d56b7c5 --- /dev/null +++ b/src/utils/ai/modelList.ts @@ -0,0 +1,414 @@ +import { createOpenAI } from "@ai-sdk/openai"; +import { createDeepSeek } from "@ai-sdk/deepseek"; +import { createZhipu } from "zhipu-ai-provider"; +import { createQwen } from "qwen-ai-provider"; +import { createGoogleGenerativeAI } from "@ai-sdk/google"; +import { createAnthropic } from "@ai-sdk/anthropic"; + +interface Owned { + manufacturer: string; + model: string; + responseFormat: "schema" | "object"; + image: boolean; + think: boolean; + tool: boolean; + instance: + | typeof createOpenAI + | typeof createDeepSeek + | typeof createZhipu + | typeof createQwen + | typeof createGoogleGenerativeAI + | typeof createAnthropic; +} + +const modelList: Owned[] = [ + // DeepSeek + { + manufacturer: "deepseek", + model: "deepseek-chat", + responseFormat: "schema", + image: false, + think: false, + instance: createDeepSeek, + tool: true, + }, + { + manufacturer: "deepseek", + model: "deepseek-reasoner", + responseFormat: "schema", + image: false, + think: true, + instance: createDeepSeek, + tool: true, + }, + + // 豆包 + { + manufacturer: "doubao", + model: "doubao-seed-1-8", + responseFormat: "schema", + image: true, + think: true, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "doubao", + model: "doubao-seed-1-6", + responseFormat: "schema", + image: true, + think: true, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "doubao", + model: "doubao-seed-1-6-lite", + responseFormat: "schema", + image: true, + think: true, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "doubao", + model: "doubao-seed-1-6-flash", + responseFormat: "schema", + image: true, + think: true, + instance: createOpenAI, + tool: true, + }, + // GLM + { + manufacturer: "zhipu", + model: "glm-4.7", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.7-flashx", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.6", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.5-air", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.5-airx", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4-long", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4-flashx-250414", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.7-flash", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.5-flash", + responseFormat: "object", + image: false, + think: true, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4-flash-250414", + responseFormat: "object", + image: false, + think: false, + instance: createZhipu, + tool: true, + }, + { + manufacturer: "zhipu", + model: "glm-4.6v", + responseFormat: "object", + image: true, + think: true, + instance: createZhipu, + tool: true, + }, + // Qwen + { + manufacturer: "qwen", + model: "qwen-vl-max", + responseFormat: "schema", + image: true, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen-plus-latest", + responseFormat: "schema", + image: false, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen-max", + responseFormat: "schema", + image: false, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen2.5-72b-instruct", + responseFormat: "schema", + image: false, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen2.5-14b-instruct-1m", + responseFormat: "schema", + image: false, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen2.5-vl-72b-instruct", + responseFormat: "schema", + image: true, + think: false, + instance: createQwen, + tool: true, + }, + // OpenAI + { + manufacturer: "openai", + model: "gpt-4o", + responseFormat: "schema", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "openai", + model: "gpt-4o-mini", + responseFormat: "schema", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "openai", + model: "gpt-4.1", + responseFormat: "schema", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "openai", + model: "gpt-5.1", + responseFormat: "schema", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "openai", + model: "gpt-5.2", + responseFormat: "schema", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + + // Gemini + { + manufacturer: "google", + model: "gemini-2.5-pro", + responseFormat: "schema", + image: true, + think: true, + instance: createGoogleGenerativeAI, + tool: true, + }, + { + manufacturer: "google", + model: "gemini-2.5-flash", + responseFormat: "schema", + image: true, + think: true, + instance: createGoogleGenerativeAI, + tool: true, + }, + { + manufacturer: "google", + model: "gemini-2.0-flash", + responseFormat: "schema", + image: true, + think: false, + instance: createGoogleGenerativeAI, + tool: true, + }, + { + manufacturer: "google", + model: "gemini-2.0-flash-lite", + responseFormat: "schema", + image: true, + think: false, + instance: createGoogleGenerativeAI, + tool: true, + }, + { + manufacturer: "google", + model: "gemini-1.5-pro", + responseFormat: "schema", + image: true, + think: false, + instance: createGoogleGenerativeAI, + tool: true, + }, + { + manufacturer: "google", + model: "gemini-1.5-flash", + responseFormat: "schema", + image: true, + think: false, + instance: createGoogleGenerativeAI, + tool: true, + }, + // Anthropic (Claude) + { + manufacturer: "anthropic", + model: "claude-opus-4-5", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-haiku-4-5", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-sonnet-4-5", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-opus-4-1", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-opus-4-0", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-sonnet-4-0", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-3-7-sonnet-latest", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, + { + manufacturer: "anthropic", + model: "claude-3-5-haiku-latest", + responseFormat: "schema", + image: true, + think: false, + instance: createAnthropic, + tool: true, + }, +]; + +export default modelList; diff --git a/src/utils/ai/text.ts b/src/utils/ai/text.ts new file mode 100644 index 0000000..29d4ead --- /dev/null +++ b/src/utils/ai/text.ts @@ -0,0 +1,88 @@ +import u from "@/utils"; +import { generateText, streamText, Output, stepCountIs, ModelMessage, LanguageModel, Tool, GenerateTextResult } from "ai"; +import { parse } from "best-effort-json-parser"; +import modelList from "./modelList"; +import { z } from "zod"; + +interface AIInput | undefined = undefined> { + system?: string; + tools?: Record; + maxStep?: number; + output?: T; + prompt?: string; + messages?: Array; +} + +interface AIConfig { + model?: string; + apiKey?: string; + baseURL?: string; +} + +const buildOptions = async (input: AIInput, config: AIConfig) => { + const sqlTextModelConfig = await u.getConfig("text"); + const { model, apiKey, baseURL } = { ...sqlTextModelConfig, ...config }; + + const owned = modelList.find((m) => m.model === model); + if (!owned) throw new Error("不支持的模型或厂商"); + + const modelInstance = owned.instance({ apiKey, baseURL }); + + const maxStep = input.maxStep ?? (input.tools ? Object.keys(input.tools).length * 5 : undefined); + const outputBuilders: Record any> = { + schema: (s) => Output.object({ schema: z.object(s) }), + object: () => { + const jsonSchemaPrompt = `\n请按照以下 JSON Schema 格式返回结果:\n${JSON.stringify( + z.toJSONSchema(z.object(input.output)), + null, + 2, + )}\n只返回结果,不要将Schema返回。`; + input.system = (input.system ?? "") + jsonSchemaPrompt; + // return Output.json(); + }, + }; + + const output = input.output ? outputBuilders[owned.responseFormat]?.(input.output) ?? null : null; + + return { + config: { + model: modelInstance(model) as LanguageModel, + ...(input.system && { system: input.system }), + ...(input.prompt ? { prompt: input.prompt } : { messages: input.messages! }), + ...(input.tools && owned.tool && { tools: input.tools }), + ...(maxStep && { stopWhen: stepCountIs(maxStep) }), + ...(output && { output }), + }, + responseFormat: owned.responseFormat, + }; +}; + +type InferOutput = T extends Record ? z.infer> : GenerateTextResult, never>; + +const ai = Object.create({}) as { + invoke | undefined = undefined>(input: AIInput, config?: AIConfig): Promise>; + stream(input: AIInput, config?: AIConfig): Promise>; +}; + +ai.invoke = async (input: AIInput, config: AIConfig = {}) => { + const options = await buildOptions(input, config); + const result = await generateText(options.config); + if (options.responseFormat === "object" && input.output) { + const pattern = /{[^{}]*}|{(?:[^{}]*|{[^{}]*})*}/g; + const jsonLikeTexts = Array.from(result.text.matchAll(pattern), (m) => m[0]); + + const res = jsonLikeTexts.map((jsonText) => parse(jsonText)); + return res[0]; + } + if (options.responseFormat === "schema" && input.output) { + return JSON.parse(result.text); + } + return result; +}; + +ai.stream = async (input: AIInput, config: AIConfig = {}) => { + const options = await buildOptions(input, config); + return streamText(options.config); +}; + +export default ai; diff --git a/src/utils/getConfig copy.ts b/src/utils/getConfig copy.ts new file mode 100644 index 0000000..7f157b9 --- /dev/null +++ b/src/utils/getConfig copy.ts @@ -0,0 +1,43 @@ +import u from "@/utils"; + +// 只包含 t_setting 表里实际存在的字段 +const modelFields = { + image: "imageModel", + language: "languageModel", +} as const; + +interface resData { + model: string; + apiKey: string; + baseURL: string; + manufacturer: "openAi" | "volcengine" | "runninghub" | "gemini" | "apimart"; +} + +type ModelType = keyof typeof modelFields; + +// 定义返回类型映射 +type ReturnType = T extends "video" ? resData[] : resData; + +// 主方法 +export default async function getConfig(type: T, manufacturer?: string): Promise> { + if (type === "video") { + // 查询 t_config 表,返回数组 + const configList = await u.db("t_config").where("manufacturer", manufacturer).orderBy("index", "asc"); + + return configList.map((i) => { + return { + ...i, + baseURL: i.baseUrl, + }; + }) as ReturnType; + } + + // 只查询当前需要的字段 + const modelName = modelFields[type as ModelType]; + const data: Record | undefined = await u.db("t_setting").where({ id: 1 }).select([modelName]).first(); + + if (!data) throw new Error("设置数据不存在"); + + // 字段值为 JSON 字符串,解析 + return JSON.parse(data[modelName] || "{}") as ReturnType; +} diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index 29596b8..3bf3859 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -1,44 +1,55 @@ import u from "@/utils"; -// 只包含 t_setting 表里实际存在的字段 -const modelFields = { - image: "imageModel", - language: "languageModel", - doubao: "doubaoModel", -} as const; +type AIType = "text" | "image" | "video"; -interface resData { +interface BaseConfig { model: string; apiKey: string; - baseURL: string; - manufacturer: "openAi" | "volcengine" | "runninghub" | "gemini" | "apimart"; + manufacturer: string; } -type ModelType = keyof typeof modelFields; +interface TextResData extends BaseConfig { + baseURL: string; + manufacturer: "deepseek" | "openAi" | "doubao"; +} -// 定义返回类型映射 -type ReturnType = T extends "video" ? resData[] : resData; +interface ImageResData extends BaseConfig { + manufacturer: "openAi" | "gemini" | "volcengine" | "runninghub" | "apimart"; +} -// 主方法 -export default async function getConfig(type: T, manufacturer?: string): Promise> { - if (type === "video") { - // 查询 t_config 表,返回数组 - const configList = await u.db("t_config").where("manufacturer", manufacturer).orderBy("index", "asc"); +interface VideoResData extends BaseConfig { + baseURL: string; + manufacturer: "openAi" | "volcengine" | "runninghub" | "apimart" | "confyUI"; +} - return configList.map((i) => { - return { - ...i, - baseURL: i.baseUrl, - }; - }) as ReturnType; +type ResDataMap = { + text: TextResData; + image: ImageResData; + video: VideoResData; +}; + +const errorMessages: Record = { + text: "文本模型配置不存在", + image: "图像模型配置不存在", + video: "视频模型配置不存在", +}; + +const needBaseURL: AIType[] = ["text", "video"]; + +export default async function getConfig(aiType: T): Promise { + const config = await u.db("t_config").where("type", aiType).first(); + + if (!config) throw new Error(errorMessages[aiType]); + + const result: BaseConfig = { + model: config?.model ?? "", + apiKey: config?.apiKey ?? "", + manufacturer: config?.manufacturer ?? "", + }; + + if (needBaseURL.includes(aiType)) { + return { ...result, baseURL: config.baseUrl } as ResDataMap[T]; } - // 只查询当前需要的字段 - const modelName = modelFields[type as ModelType]; - const data: Record | undefined = await u.db("t_setting").where({ id: 1 }).select([modelName]).first(); - - if (!data) throw new Error("设置数据不存在"); - - // 字段值为 JSON 字符串,解析 - return JSON.parse(data[modelName] || "{}") as ReturnType; + return result as ResDataMap[T]; } diff --git a/yarn.lock b/yarn.lock index c482804..f52c0c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,95 @@ resolved "https://registry.npmmirror.com/7zip-bin/-/7zip-bin-5.2.0.tgz#7a03314684dd6572b7dfa89e68ce31d60286854d" integrity sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A== +"@ai-sdk/anthropic@^3.0.35": + version "3.0.35" + resolved "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.35.tgz#334bf3f5415ebab77cf23d52f197b8027087821e" + integrity sha512-Y3g/5uVj621XSB9lGF7WrD7qR+orhV5xpaYkRF8kfj2j4W7e7BBGIvxcdsCf85FjJbc6tKQdNTZ84ZEqT3Y5TQ== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + +"@ai-sdk/deepseek@^2.0.17": + version "2.0.17" + resolved "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-2.0.17.tgz#14a8460d141d36fda08040074b887b2fab06948e" + integrity sha512-rkZiasQ24UyOMiZd8Mb7R+OF3Yt90bRQyfyzIkrb0zKZj7kU2h2z2nu1CO6j0X8poE+SZhEEaHOBFhRcp6hKVg== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + +"@ai-sdk/gateway@3.0.32": + version "3.0.32" + resolved "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.32.tgz#4738f75fc2eba7f245f77fd0dc139225a08c9c47" + integrity sha512-7clZRr07P9rpur39t1RrbIe7x8jmwnwUWI8tZs+BvAfX3NFgdSVGGIaT7bTz2pb08jmLXzTSDbrOTqAQ7uBkBQ== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + "@vercel/oidc" "3.1.0" + +"@ai-sdk/google@^3.0.20": + version "3.0.20" + resolved "https://registry.npmmirror.com/@ai-sdk/google/-/google-3.0.20.tgz#608ec12a13371439a6a06992fb7e7d1d4d029432" + integrity sha512-bVGsulEr6JiipAFlclo9bjL5WaUV0iCSiiekLt+PY6pwmtJeuU2GaD9DoE3OqR8LN2W779mU13IhVEzlTupf8g== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + +"@ai-sdk/openai@^3.0.25": + version "3.0.25" + resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.25.tgz#452c8f8ed597468048569ec9476a0b5641888d2a" + integrity sha512-DsaN46R98+D1W3lU3fKuPU3ofacboLaHlkAwxJPgJ8eup1AJHmPK1N1y10eJJbJcF6iby8Tf/vanoZxc9JPUfw== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + +"@ai-sdk/provider-utils@4.0.13": + version "4.0.13" + resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.13.tgz#d2240b0c4d701eef8a4273ade71585a691e34e04" + integrity sha512-HHG72BN4d+OWTcq2NwTxOm/2qvk1duYsnhCDtsbYwn/h/4zeqURu1S0+Cn0nY2Ysq9a9HGKvrYuMn9bgFhR2Og== + dependencies: + "@ai-sdk/provider" "3.0.7" + "@standard-schema/spec" "^1.1.0" + eventsource-parser "^3.0.6" + +"@ai-sdk/provider-utils@^2.1.6": + version "2.2.8" + resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz#ad11b92d5a1763ab34ba7b5fc42494bfe08b76d1" + integrity sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA== + dependencies: + "@ai-sdk/provider" "1.1.3" + nanoid "^3.3.8" + secure-json-parse "^2.7.0" + +"@ai-sdk/provider-utils@^3.0.0": + version "3.0.20" + resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-3.0.20.tgz#61d7741065550833eae3ac6440d943e9d3d25120" + integrity sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ== + dependencies: + "@ai-sdk/provider" "2.0.1" + "@standard-schema/spec" "^1.0.0" + eventsource-parser "^3.0.6" + +"@ai-sdk/provider@1.1.3", "@ai-sdk/provider@^1.0.7": + version "1.1.3" + resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-1.1.3.tgz#ebdda8077b8d2b3f290dcba32c45ad19b2704681" + integrity sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/provider@2.0.1", "@ai-sdk/provider@^2.0.0": + version "2.0.1" + resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-2.0.1.tgz#4aba415f1815da33a7a81e5f41a0219af53278c0" + integrity sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/provider@3.0.7": + version "3.0.7" + resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-3.0.7.tgz#470bb8f9e46ec9d8d62b07b4c1f5737b991ebe83" + integrity sha512-VkPLrutM6VdA924/mG8OS+5frbVTcu6e046D2bgDo00tehBANR1QBJ/mPcZ9tXMFOsVcm6SQArOregxePzTFPw== + dependencies: + json-schema "^0.4.0" + "@aigne/afs-history@^1.2.0": version "1.2.0" resolved "https://registry.npmmirror.com/@aigne/afs-history/-/afs-history-1.2.0.tgz#42086667ee83f2bbe181b247d6987cd05793d96f" @@ -969,7 +1058,7 @@ dependencies: "@opentelemetry/api" "^1.3.0" -"@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.0": +"@opentelemetry/api@1.9.0", "@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.0": version "1.9.0" resolved "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== @@ -1348,7 +1437,7 @@ resolved "https://registry.npmmirror.com/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.50.1-build1.tgz#67dd9944b0e37ddb0ef2c8b195baa74ece838e44" integrity sha512-yH4M/SHN98NibniIwTVk6rwTJjy7n39l7zwWY3u+qsfZBGTi4lC1uEl2NDvIlkzsFtfCBvHBJJFJ1iuU3UzzEQ== -"@standard-schema/spec@1.1.0": +"@standard-schema/spec@1.1.0", "@standard-schema/spec@^1.0.0", "@standard-schema/spec@^1.1.0": version "1.1.0" resolved "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== @@ -1574,6 +1663,11 @@ resolved "https://registry.npmmirror.com/@ungap/with-resolvers/-/with-resolvers-0.1.0.tgz#63a07b13bbf10ffff074a36498cce8d82aeeecc4" integrity sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw== +"@vercel/oidc@3.1.0": + version "3.1.0" + resolved "https://registry.npmmirror.com/@vercel/oidc/-/oidc-3.1.0.tgz#066caee449b84079f33c7445fc862464fe10ec32" + integrity sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w== + "@xmldom/xmldom@^0.8.8": version "0.8.11" resolved "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608" @@ -1651,6 +1745,16 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ai@^6.0.67: + version "6.0.67" + resolved "https://registry.npmmirror.com/ai/-/ai-6.0.67.tgz#eb808301e0196915b9fe097ac7de47ce8131c2a9" + integrity sha512-xBnTcByHCj3OcG6V8G1s6zvSEqK0Bdiu+IEXYcpGrve1iGFFRgcrKeZtr/WAW/7gupnSvBbDF24BEv1OOfqi1g== + dependencies: + "@ai-sdk/gateway" "3.0.32" + "@ai-sdk/provider" "3.0.7" + "@ai-sdk/provider-utils" "4.0.13" + "@opentelemetry/api" "1.9.0" + ajv-formats@^3.0.1: version "3.0.1" resolved "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" @@ -1911,6 +2015,11 @@ basic-auth@~2.0.1: dependencies: safe-buffer "5.1.2" +best-effort-json-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/best-effort-json-parser/-/best-effort-json-parser-1.2.1.tgz#e8d0b8355a0c268d918681faa0e3cf6aa192ea00" + integrity sha512-UICSLibQdzS1f+PBsi3u2YE3SsdXcWicHUg3IMvfuaePS2AYnZJdJeKhGv5OM8/mqJwPt79aDrEJ1oa84tELvw== + better-sqlite3@^12.6.2: version "12.6.2" resolved "https://registry.npmmirror.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937" @@ -3779,6 +3888,11 @@ json-schema-typed@^8.0.2: resolved "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz#e98ee7b1899ff4a184534d1f167c288c66bbeff4" integrity sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA== +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -4327,6 +4441,11 @@ mute-stream@^2.0.0: resolved "https://registry.npmmirror.com/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== +nanoid@^3.3.8: + version "3.3.11" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + napi-build-utils@^2.0.0: version "2.0.0" resolved "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz#13c22c0187fcfccce1461844136372a47ddc027e" @@ -4887,6 +5006,14 @@ quick-lru@^5.1.1: resolved "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +qwen-ai-provider@^0.1.1: + version "0.1.1" + resolved "https://registry.npmmirror.com/qwen-ai-provider/-/qwen-ai-provider-0.1.1.tgz#f854379514eed919fe01de20007f6238a8ad2b41" + integrity sha512-7dVu97U7fbOGgCYdaOunC4NQqC+7Or3/Gsbx+P16+Ny4VxST7WJxfUCogQl6D2EDxIJdHGz4akHm+5fyEulmyw== + dependencies: + "@ai-sdk/provider" "^1.0.7" + "@ai-sdk/provider-utils" "^2.1.6" + radix3@^1.1.2: version "1.1.2" resolved "https://registry.npmmirror.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" @@ -5161,6 +5288,11 @@ sax@^1.2.4: resolved "https://registry.npmmirror.com/sax/-/sax-1.4.4.tgz#f29c2bba80ce5b86f4343b4c2be9f2b96627cf8b" integrity sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw== +secure-json-parse@^2.7.0: + version "2.7.0" + resolved "https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" + integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -6106,6 +6238,14 @@ yoctocolors-cjs@^2.1.3: resolved "https://registry.npmmirror.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw== +zhipu-ai-provider@^0.2.2: + version "0.2.2" + resolved "https://registry.npmmirror.com/zhipu-ai-provider/-/zhipu-ai-provider-0.2.2.tgz#cbee428475b1c2fca446f273ac09006ef86f6f00" + integrity sha512-UjX1ho4DI9ICUv/mrpAnzmrRe5/LXrGkS5hF6h4WDY2aup5GketWWopFzWYCqsbArXAM5wbzzdH9QzZusgGiBg== + dependencies: + "@ai-sdk/provider" "^2.0.0" + "@ai-sdk/provider-utils" "^3.0.0" + zip-stream@^6.0.1: version "6.0.1" resolved "https://registry.npmmirror.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb"