diff --git a/package.json b/package.json index 8fd8fad..203b72a 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "jsonwebtoken": "^9.0.3", "knex": "^3.1.0", "morgan": "^1.10.1", - "qwen-ai-provider": "^0.1.1", + "qwen-ai-provider-v5": "^2.1.0", "serialize-error": "^13.0.1", "sharp": "^0.34.5", "sqlite3": "^5.1.7", diff --git a/scripts/main.ts b/scripts/main.ts index a1e2470..761511b 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -1,7 +1,33 @@ -import { app, BrowserWindow } from "electron"; +import { app, BrowserWindow, dialog } from "electron"; import path from "path"; +import net from "net"; import startServe, { closeServe } from "src/app"; +// 检测端口是否被占用 +function checkPortInUse(port: number): Promise { + return new Promise((resolve) => { + const server = net.createServer(); + + server.once('error', (err: NodeJS.ErrnoException) => { + if (err.code === 'EADDRINUSE') { + + resolve(true); // 端口被占用 + } else { + + resolve(false); + } + }); + + server.once('listening', () => { + server.close(); + + resolve(false); // 端口可用 + }); + + server.listen(port); + }); +} + function createMainWindow(): void { const isDev = process.env.NODE_ENV === "dev" || !app.isPackaged; const basePath = isDev ? process.cwd() : app.getAppPath(); @@ -21,6 +47,20 @@ function createMainWindow(): void { void win.loadFile(htmlPath); } app.whenReady().then(async () => { + const port = parseInt(process.env.PORT || "60000"); + const isPortInUse = await checkPortInUse(port); + + + if (isPortInUse) { + + await dialog.showErrorBox( + "端口被占用", + `端口 ${port} 已被占用,请关闭占用该端口的程序后重试。\n\n您可以使用以下命令查看占用端口的程序:\nWindows: netstat -ano | findstr ${port}\nLinux/Mac: lsof -i :${port}` + ); + app.quit(); + return; + } + createMainWindow(); await startServe(); }); diff --git a/src/router.ts b/src/router.ts index ae73206..7175522 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash 3cfad40b3c8658b442ab766a9323d740 +// @routes-hash 2c228db11434e5c7874e23f6fe832d00 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -65,19 +65,20 @@ import route61 from "./routes/storyboard/uploadImage"; import route62 from "./routes/task/getTaskApi"; import route63 from "./routes/task/taskDetails"; import route64 from "./routes/user/getUser"; -import route65 from "./routes/video/addVideo"; -import route66 from "./routes/video/addVideoConfig"; -import route67 from "./routes/video/deleteVideoConfig"; -import route68 from "./routes/video/generatePrompt"; -import route69 from "./routes/video/generateVideo"; -import route70 from "./routes/video/getManufacturer"; -import route71 from "./routes/video/getVideo"; -import route72 from "./routes/video/getVideoConfigs"; -import route73 from "./routes/video/getVideoModel"; -import route74 from "./routes/video/getVideoStoryboards"; -import route75 from "./routes/video/reviseVideoStoryboards"; -import route76 from "./routes/video/saveVideo"; -import route77 from "./routes/video/upDateVideoConfig"; +import route65 from "./routes/user/saveUser"; +import route66 from "./routes/video/addVideo"; +import route67 from "./routes/video/addVideoConfig"; +import route68 from "./routes/video/deleteVideoConfig"; +import route69 from "./routes/video/generatePrompt"; +import route70 from "./routes/video/generateVideo"; +import route71 from "./routes/video/getManufacturer"; +import route72 from "./routes/video/getVideo"; +import route73 from "./routes/video/getVideoConfigs"; +import route74 from "./routes/video/getVideoModel"; +import route75 from "./routes/video/getVideoStoryboards"; +import route76 from "./routes/video/reviseVideoStoryboards"; +import route77 from "./routes/video/saveVideo"; +import route78 from "./routes/video/upDateVideoConfig"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -144,17 +145,18 @@ export default async (app: Express) => { app.use("/task/getTaskApi", route62); app.use("/task/taskDetails", route63); app.use("/user/getUser", route64); - app.use("/video/addVideo", route65); - app.use("/video/addVideoConfig", route66); - app.use("/video/deleteVideoConfig", route67); - app.use("/video/generatePrompt", route68); - app.use("/video/generateVideo", route69); - app.use("/video/getManufacturer", route70); - app.use("/video/getVideo", route71); - app.use("/video/getVideoConfigs", route72); - app.use("/video/getVideoModel", route73); - app.use("/video/getVideoStoryboards", route74); - app.use("/video/reviseVideoStoryboards", route75); - app.use("/video/saveVideo", route76); - app.use("/video/upDateVideoConfig", route77); + app.use("/user/saveUser", route65); + app.use("/video/addVideo", route66); + app.use("/video/addVideoConfig", route67); + app.use("/video/deleteVideoConfig", route68); + app.use("/video/generatePrompt", route69); + app.use("/video/generateVideo", route70); + app.use("/video/getManufacturer", route71); + app.use("/video/getVideo", route72); + app.use("/video/getVideoConfigs", route73); + app.use("/video/getVideoModel", route74); + app.use("/video/getVideoStoryboards", route75); + app.use("/video/reviseVideoStoryboards", route76); + app.use("/video/saveVideo", route77); + app.use("/video/upDateVideoConfig", route78); } diff --git a/src/routes/assets/generateAssets.ts b/src/routes/assets/generateAssets.ts index 7889f1a..b0d9cdb 100644 --- a/src/routes/assets/generateAssets.ts +++ b/src/routes/assets/generateAssets.ts @@ -2,7 +2,7 @@ import express from "express"; import u from "@/utils"; import { z } from "zod"; import { v4 as uuidv4 } from "uuid"; -import { success } from "@/lib/responseFormat"; +import { success,error } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; import sharp from "sharp"; const router = express.Router(); @@ -124,8 +124,8 @@ export default router.post( assetsId: id, }); const apiConfig = await u.getPromptAi("assetsImage"); - - const contentStr = await u.ai.image( + try{ + const contentStr = await u.ai.image( { systemPrompt, prompt: userPrompt, @@ -175,6 +175,14 @@ export default router.post( // const state = await u.db("t_assets").where("id", id).select("state").first(); res.status(200).send(success({ path, assetsId: id })); + }catch(e){ + await u.db("t_image").where("id",imageId).update({ + state:"生成失败" + }) + const msg = u.error(e).message || "图片生成失败" + return res.status(400).send(error(msg)) + } + }, ); async function imageAddText(name: string, imageBuffer: Buffer) { diff --git a/src/routes/user/saveUser.ts b/src/routes/user/saveUser.ts new file mode 100644 index 0000000..07709a2 --- /dev/null +++ b/src/routes/user/saveUser.ts @@ -0,0 +1,24 @@ +import express from "express"; +import u from "@/utils"; +import { z } from "zod"; +import { success } from "@/lib/responseFormat"; +import { validateFields } from "@/middleware/middleware"; +const router = express.Router(); + +// 获取用户 +export default router.post( + "/", + validateFields({ + name: z.string(), + password: z.string(), + id: z.number(), + }), + async (req, res) => { + const { name, password, id } = req.body; + await u.db("t_user").where("id", id).update({ + name, + password, + }); + res.status(200).send(success("保存设置成功")); + }, +); diff --git a/src/routes/video/deleteVideoConfig.ts b/src/routes/video/deleteVideoConfig.ts index 360467c..30c1884 100644 --- a/src/routes/video/deleteVideoConfig.ts +++ b/src/routes/video/deleteVideoConfig.ts @@ -33,9 +33,6 @@ export default router.post( if (result.filePath) { filesToDelete.push(result.filePath); } - if (result.firstFrame) { - filesToDelete.push(result.firstFrame); - } } // 删除文件 diff --git a/src/routes/video/generateVideo.ts b/src/routes/video/generateVideo.ts index e0b1b5b..d213aa8 100644 --- a/src/routes/video/generateVideo.ts +++ b/src/routes/video/generateVideo.ts @@ -6,8 +6,6 @@ import { error, success } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; import { t_config } from "@/types/database"; import sharp from "sharp"; -import fs from "fs"; -import path from "path"; const router = express.Router(); diff --git a/src/utils/ai/image/index.ts b/src/utils/ai/image/index.ts index 3054ebd..ae7ddcb 100644 --- a/src/utils/ai/image/index.ts +++ b/src/utils/ai/image/index.ts @@ -10,7 +10,7 @@ import runninghub from "./owned/runninghub"; import apimart from "./owned/apimart"; import other from "./owned/other"; import gemini from "./owned/gemini"; - +import modelScope from "./owned/modelScope"; const urlToBase64 = async (url: string): Promise => { const res = await axios.get(url, { responseType: "arraybuffer" }); const base64 = Buffer.from(res.data).toString("base64"); @@ -26,6 +26,7 @@ const modelInstance = { runninghub: runninghub, // apimart: apimart, other, + modelScope, } as const; export default async (input: ImageConfig, config: AIConfig) => { @@ -35,10 +36,10 @@ export default async (input: ImageConfig, config: AIConfig) => { const manufacturerFn = modelInstance[manufacturer as keyof typeof modelInstance]; if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的图片厂商"); - if (manufacturer !== "other") { - const owned = modelList.find((m) => m.model === model); - if (!owned) throw new Error("不支持的模型"); - } + // if (manufacturer !== "other" && manufacturer !== "modelScope") { + // const owned = modelList.find((m) => m.model === model); + // if (!owned) throw new Error("不支持的模型"); + // } // 补充图片的 base64 内容类型字符串 if (input.imageBase64 && input.imageBase64.length > 0) { @@ -65,7 +66,6 @@ export default async (input: ImageConfig, config: AIConfig) => { } let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL }); - console.log("%c Line:68 🍷 imageUrl", "background:#4fff4B", imageUrl); if (!input.resType) input.resType = "b64"; if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl); return imageUrl; diff --git a/src/utils/ai/image/modelList.ts b/src/utils/ai/image/modelList.ts index 1cce6d9..544fc86 100644 --- a/src/utils/ai/image/modelList.ts +++ b/src/utils/ai/image/modelList.ts @@ -19,6 +19,12 @@ const modelList: Owned[] = [ grid: false, type: "ti2i", }, + // { + // manufacturer: "volcengine", + // model: "doubao-seedream-5-0-260128", + // grid: false, + // type: "ti2i", + // }, //可灵 { manufacturer: "kling", diff --git a/src/utils/ai/image/owned/modelScope.ts b/src/utils/ai/image/owned/modelScope.ts new file mode 100644 index 0000000..4a13dee --- /dev/null +++ b/src/utils/ai/image/owned/modelScope.ts @@ -0,0 +1,133 @@ +import "../type"; +import { generateImage, generateText, ModelMessage } from "ai"; +import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; +import { pollTask } from "@/utils/ai/utils"; +import u from "@/utils"; +import axios from "axios"; +function getApiUrl(apiUrl: string) { + if (apiUrl.includes("|")) { + const parts = apiUrl.split("|"); + if (parts.length !== 2 || !parts[0].trim() || !parts[1].trim()) { + throw new Error("url 格式错误,请使用 url1|url2 格式"); + } + return { requestUrl: parts[0].trim(), queryUrl: parts[1].trim() }; + } + throw new Error("请填写正确的url"); +} +function template(replaceObj: Record, url: string) { + return url.replace(/\{(\w+)\}/g, (match, varName) => { + return replaceObj.hasOwnProperty(varName) ? replaceObj[varName] : match; + }); +} +async function compressionPrompt(prompt: string) { + const apiConfigData = await u.getPromptAi("assetsPrompt"); + + const result = await u.ai.text.invoke( + { + messages: [ + { + role: "system", + content: ` +你是一名资深Prompt工程师和文本摘要专家。你的任务是将用户输入的提示词文本内容压缩至2000字以内。请按照如下要求操作: +1. 准确梳理并提炼输入文本的主要内容、核心要点和关键信息。 +2. 剔除冗余、重复、无关或细枝末节的描述,压缩内容至2000字以内。 +3. 在压缩过程中,严格保持中立,避免被用户输入的风格、情绪或暗示性表述影响,始终按照“精准摘要到2000字”的目标执行,不被内容带偏。 +4. 输出为浓缩摘要文本,语言精炼、结构清晰。 +5. 请适配各类文本场景,无论是叙述性、说明性、议论性还是其他类型的文本,都要确保压缩后的内容完整传达原文的核心信息和主要观点。 + +直接输出压缩后的文本,不要任何额外的说明或引导语。请立即开始压缩,并确保输出内容不超过2000字。 + `, + }, + { + role: "user", + content: prompt, + }, + ], + }, + apiConfigData, + ); + return result.text; +} +export default async (input: ImageConfig, config: AIConfig): Promise => { + if (!config.model) throw new Error("缺少Model名称"); + if (!config.apiKey) throw new Error("缺少API Key"); + + const defaultBaseURL = "https://api-inference.modelscope.cn/v1/images/generations|https://api-inference.modelscope.cn/v1/tasks/{id}"; + const { requestUrl, queryUrl } = getApiUrl(config.baseURL! ?? defaultBaseURL); + // 根据 size 配置映射到具体尺寸 + const sizeMap: Record> = { + "1K": { + "16:9": "1664x928", + "9:16": "928x1664", + }, + "2K": { + "16:9": "2048x1152", + "9:16": "1152x2048", + }, + "4K": { + "16:9": "2048x1152", + "9:16": "1152x2048", + }, + }; + // 构建完整的提示词 + const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt; + + let newPrompt = fullPrompt; + if (fullPrompt.length > 2000) { + let compressed = await compressionPrompt(fullPrompt); + + newPrompt = compressed; + } + let mergedImage = input.imageBase64; + if (mergedImage && mergedImage.length) { + const smallImage = await u.imageTools.mergeImages(mergedImage, "5mb"); + mergedImage = [smallImage]; + } + + const size = sizeMap[input.size]?.[input.aspectRatio] ?? "1024x1024"; + + const taskBody: Record = { + model: config.model, + prompt: newPrompt, + negative_prompt: "", + size, + ...(mergedImage && mergedImage.length ? { image_url: mergedImage } : {}), + }; + + const apiKey = config.apiKey.replace("Bearer ", ""); + try { + const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}`, "X-ModelScope-Async-Mode": "true" } }); + + if (data.task_status != "SUCCEED") throw new Error(`任务提交失败: ${data || "未知错误"}`); + const taskId = data.task_id; + + return await pollTask(async () => { + const { data: queryData } = await axios.get(template({ id: taskId }, queryUrl), { + headers: { Authorization: `Bearer ${apiKey}`, "X-ModelScope-Task-Type": "image_generation" }, + }); + + const { task_status, output_images } = queryData || {}; + + if (task_status === "FAILED") { + return { completed: false, error: "图片生成失败" }; + } + + if (task_status === "SUCCEED") { + return { completed: true, url: output_images?.[0] }; + } + + return { completed: false }; + }); + } catch (error: any) { + console.error("%c Line:90 🥪 error", "background:#93c0a4", error.response?.data?.errors?.message); + const msg = u.error(error).message || "图片生成失败"; + throw new Error(msg); + } +}; + +async function urlToBase64(url: string): Promise { + const res = await axios.get(url, { responseType: "arraybuffer" }); + const base64 = Buffer.from(res.data).toString("base64"); + const mimeType = res.headers["content-type"] || "image/png"; + return `data:${mimeType};base64,${base64}`; +} diff --git a/src/utils/ai/image/owned/other.ts b/src/utils/ai/image/owned/other.ts index b0158e1..8ae9e59 100644 --- a/src/utils/ai/image/owned/other.ts +++ b/src/utils/ai/image/owned/other.ts @@ -27,6 +27,7 @@ export default async (input: ImageConfig, config: AIConfig): Promise => // 构建完整的提示词 const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt; const model = config.model; + if (model.includes("gemini") || model.includes("nano")) { let promptData; if (input.imageBase64 && input.imageBase64.length) { @@ -69,26 +70,28 @@ export default async (input: ImageConfig, config: AIConfig): Promise => console.error(JSON.stringify(result.response, null, 2)); throw new Error("图片生成失败"); } - const mdMatch = result.text.match(/^!\[.*?\]\((.+?)\)$/); - if (mdMatch) { - const imgInfo = mdMatch[1]; - const base64InMd = imgInfo.match(/data:image\/[a-z]+;base64,(.+)/); + // 匹配所有 markdown 图片 ![...](url) + const mdImgPattern = /!\[.*?\]\((.+?)\)/g; + const matches = [...result.text.matchAll(mdImgPattern)]; + for (const match of matches) { + const imgInfo = match[1]; + // 检查是否已是 base64 + const base64InMd = imgInfo.match(/data:image\/[a-z]+;base64,.+/); if (base64InMd) { - return imgInfo; + return imgInfo; // 已经是base64,直接返回 } else { - return await urlToBase64(imgInfo); + return await urlToBase64(imgInfo); // 否则尝试转base64 } } + // 检查纯base64字符串 const base64Match = result.text.match(/base64,([A-Za-z0-9+/=]+)/); - if (base64Match) { return "data:image/jpeg;base64," + base64Match[1]; } - // 检查是否为图片直链 url + // 检查是否为图片直链接 if (/^https?:\/\/.*\.(png|jpg|jpeg|gif|webp|bmp)$/i.test(result.text)) { return await urlToBase64(result.text); } - // 默认情况 return result.text; } diff --git a/src/utils/ai/image/owned/volcengine.ts b/src/utils/ai/image/owned/volcengine.ts index 2d93fdf..25afa69 100644 --- a/src/utils/ai/image/owned/volcengine.ts +++ b/src/utils/ai/image/owned/volcengine.ts @@ -8,11 +8,20 @@ export default async (input: ImageConfig, config: AIConfig): Promise => const apiKey = "Bearer " + config.apiKey.replace(/Bearer\s+/g, "").trim(); const size = input.size === "1K" ? "2K" : input.size; - + const sizeMap: Record> = { + "16:9": { + "2K": "2848x1600", + "4K": "4096x2304", + }, + "9:16": { + "2K": "1600x2848", + "4K": "2304x4096", + }, + }; const body: Record = { model: config.model, prompt: input.prompt, - size, + size: sizeMap[input.aspectRatio][size], response_format: "url", sequential_image_generation: "disabled", stream: false, @@ -28,4 +37,4 @@ export default async (input: ImageConfig, config: AIConfig): Promise => const msg = u.error(error).message || "Volcengine 图片生成失败"; throw new Error(msg); } -} +}; diff --git a/src/utils/ai/text/index.ts b/src/utils/ai/text/index.ts index bfc45d7..a47273f 100644 --- a/src/utils/ai/text/index.ts +++ b/src/utils/ai/text/index.ts @@ -25,12 +25,12 @@ interface AIConfig { const buildOptions = async (input: AIInput, config: AIConfig = {}) => { if (!config || !config?.model || !config?.apiKey || !config?.manufacturer) throw new Error("请检查模型配置是否正确"); const { model, apiKey, baseURL, manufacturer } = { ...config }; - let owned; - if (manufacturer == "other") { - owned = modelList.find((m) => m.manufacturer === manufacturer); - } else { - owned = modelList.find((m) => m.model === model); - } + // let owned; + // if (manufacturer == "other" || manufacturer == "modelScope") { + const owned = modelList.find((m) => m.manufacturer === manufacturer); + // } else { + // owned = modelList.find((m) => m.model === model); + // } if (!owned) throw new Error("不支持的模型或厂商"); const modelInstance = owned.instance({ apiKey, baseURL: baseURL!, name: "xixixi" }); @@ -52,7 +52,7 @@ const buildOptions = async (input: AIInput, config: AIConfig = {}) => { }; const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null; - const chatModelManufacturer = ["doubao", "other", "openai"]; + const chatModelManufacturer = ["doubao", "other", "openai", "modelScope"]; const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!); return { config: { diff --git a/src/utils/ai/text/modelList.ts b/src/utils/ai/text/modelList.ts index 421885a..c7ab3d4 100644 --- a/src/utils/ai/text/modelList.ts +++ b/src/utils/ai/text/modelList.ts @@ -1,11 +1,11 @@ -import { createOpenAI } from "@ai-sdk/openai"; +import { createOpenAI, OpenAIProviderSettings } from "@ai-sdk/openai"; import { createDeepSeek } from "@ai-sdk/deepseek"; import { createZhipu } from "zhipu-ai-provider"; -import { createQwen } from "qwen-ai-provider"; +import { createQwen } from "qwen-ai-provider-v5"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; import { createAnthropic } from "@ai-sdk/anthropic"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; -import { createXai } from '@ai-sdk/xai'; +import { createXai } from "@ai-sdk/xai"; interface Owned { manufacturer: string; @@ -82,6 +82,15 @@ const modelList: Owned[] = [ instance: createOpenAI, tool: true, }, + { + manufacturer: "doubao", + model: "doubao-seed-2-0-pro-260215", + responseFormat: "object", + image: true, + think: true, + instance: createOpenAI, + tool: true, + }, // GLM { manufacturer: "zhipu", @@ -186,7 +195,25 @@ const modelList: Owned[] = [ { manufacturer: "qwen", model: "qwen-vl-max", - responseFormat: "schema", + responseFormat: "object", + image: true, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen3.5-plus", + responseFormat: "object", + image: true, + think: false, + instance: createQwen, + tool: true, + }, + { + manufacturer: "qwen", + model: "qwen3.5-plus-2026-02-15", + responseFormat: "object", image: true, think: false, instance: createQwen, @@ -413,7 +440,7 @@ const modelList: Owned[] = [ tool: true, }, //xai - { + { manufacturer: "xai", model: "grok-3", responseFormat: "schema", @@ -422,7 +449,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4", responseFormat: "schema", @@ -431,7 +458,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", @@ -440,6 +467,16 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, + //魔塔 + { + manufacturer: "modelScope", + model: "grok-4.1", + responseFormat: "object", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, //其他 { manufacturer: "other", diff --git a/yarn.lock b/yarn.lock index 1397131..f568547 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,15 +74,6 @@ "@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" @@ -92,12 +83,14 @@ "@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== +"@ai-sdk/provider-utils@^4.0.0": + version "4.0.15" + resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz#d585c7c89cfdf13697a40be5768ecd907a251585" + integrity sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w== dependencies: - json-schema "^0.4.0" + "@ai-sdk/provider" "3.0.8" + "@standard-schema/spec" "^1.1.0" + eventsource-parser "^3.0.6" "@ai-sdk/provider@2.0.1", "@ai-sdk/provider@^2.0.0": version "2.0.1" @@ -113,6 +106,13 @@ dependencies: json-schema "^0.4.0" +"@ai-sdk/provider@3.0.8", "@ai-sdk/provider@^3.0.0": + version "3.0.8" + resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-3.0.8.tgz#fd7fac7533c03534ac1d3fb710a6b96e2aa00263" + integrity sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ== + dependencies: + json-schema "^0.4.0" + "@ai-sdk/xai@^3.0.47": version "3.0.47" resolved "https://registry.npmmirror.com/@ai-sdk/xai/-/xai-3.0.47.tgz#a8d3e08603865c5e401e19c801c7a80c3f31b890" @@ -3160,11 +3160,6 @@ ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -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" @@ -3614,13 +3609,13 @@ 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== +qwen-ai-provider-v5@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/qwen-ai-provider-v5/-/qwen-ai-provider-v5-2.1.0.tgz#8672871135bb4a5fda32409c00b70d10637f8a50" + integrity sha512-I+Iv45ymrez1wieZFu0n/lc/lSkbAQMlujWBCfUWBUOf6DizYfvPKaydsojXM7CU8TcqJbYJuN3ofnaxFIwBZA== dependencies: - "@ai-sdk/provider" "^1.0.7" - "@ai-sdk/provider-utils" "^2.1.6" + "@ai-sdk/provider" "^3.0.0" + "@ai-sdk/provider-utils" "^4.0.0" range-parser@^1.2.1: version "1.2.1" @@ -3846,11 +3841,6 @@ 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"