Merge branch 'develop' of https://github.com/HBAI-Ltd/Toonflow-app into develop
This commit is contained in:
commit
f450ebe6a4
@ -260,12 +260,6 @@ pm2 monit # 监控面板
|
||||
yarn dev #端口60000
|
||||
```
|
||||
|
||||
- 使用 Bun 快速运行开发服务:
|
||||
|
||||
```bash
|
||||
yarn bun:dev #端口60000
|
||||
```
|
||||
|
||||
4. **项目打包**
|
||||
|
||||
- 编译并生成 TypeScript 文件:
|
||||
|
||||
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "toonflow-serve",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.5",
|
||||
"description": "ToonFlow Serve - Electron Application",
|
||||
"main": "build/main.js",
|
||||
"author": "ToonFlow Team",
|
||||
@ -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": {
|
||||
|
||||
@ -115,19 +115,91 @@ async function mergeImages(imagePaths: string[]): Promise<Buffer> {
|
||||
return compressImage(mergedImage);
|
||||
}
|
||||
|
||||
// 处理图片列表,确保不超过10张且每张不超过3MB
|
||||
// 进一步压缩单张图片到指定大小
|
||||
async function compressToSize(buffer: Buffer, targetSize: number): Promise<Buffer> {
|
||||
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<Buffer[]> {
|
||||
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<Buffer[]> {
|
||||
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 过滤与分镜相关的资产
|
||||
|
||||
17
src/lib/fixDB.ts
Normal file
17
src/lib/fixDB.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
export default async (knex: Knex): Promise<void> => {
|
||||
const videoHasTime = await knex.schema.hasColumn("t_video", "time");
|
||||
if (!videoHasTime) {
|
||||
await knex.schema.alterTable("t_video", (table) => {
|
||||
table.integer("time");
|
||||
});
|
||||
}
|
||||
|
||||
const configHasIndex = await knex.schema.hasColumn("t_config", "index");
|
||||
if (configHasIndex) {
|
||||
await knex.schema.alterTable("t_config", (table) => {
|
||||
table.dropColumn("index");
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -151,6 +151,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
table.text("firstFrame");
|
||||
table.text("storyboardImgs");
|
||||
table.text("model");
|
||||
table.integer("time");
|
||||
table.integer("state");
|
||||
table.integer("scriptId");
|
||||
table.integer("configId"); // 关联的视频配置ID
|
||||
|
||||
@ -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 || "未知错误"));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -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();
|
||||
@ -36,7 +33,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));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -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,
|
||||
|
||||
3
src/types/database.d.ts
vendored
3
src/types/database.d.ts
vendored
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<string, any> = {
|
||||
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) => {
|
||||
@ -239,7 +251,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
|
||||
|
||||
414
src/utils/ai/modelList.ts
Normal file
414
src/utils/ai/modelList.ts
Normal file
@ -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;
|
||||
88
src/utils/ai/text.ts
Normal file
88
src/utils/ai/text.ts
Normal file
@ -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<T extends Record<string, z.ZodTypeAny> | undefined = undefined> {
|
||||
system?: string;
|
||||
tools?: Record<string, Tool>;
|
||||
maxStep?: number;
|
||||
output?: T;
|
||||
prompt?: string;
|
||||
messages?: Array<ModelMessage>;
|
||||
}
|
||||
|
||||
interface AIConfig {
|
||||
model?: string;
|
||||
apiKey?: string;
|
||||
baseURL?: string;
|
||||
}
|
||||
|
||||
const buildOptions = async (input: AIInput<any>, 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<string, (schema: any) => 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> = T extends Record<string, z.ZodTypeAny> ? z.infer<z.ZodObject<T>> : GenerateTextResult<Record<string, Tool>, never>;
|
||||
|
||||
const ai = Object.create({}) as {
|
||||
invoke<T extends Record<string, z.ZodTypeAny> | undefined = undefined>(input: AIInput<T>, config?: AIConfig): Promise<InferOutput<T>>;
|
||||
stream(input: AIInput, config?: AIConfig): Promise<ReturnType<typeof streamText>>;
|
||||
};
|
||||
|
||||
ai.invoke = async (input: AIInput<any>, 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;
|
||||
@ -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);
|
||||
|
||||
|
||||
43
src/utils/getConfig copy.ts
Normal file
43
src/utils/getConfig copy.ts
Normal file
@ -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 string> = T extends "video" ? resData[] : resData;
|
||||
|
||||
// 主方法
|
||||
export default async function getConfig<T extends ModelType | "video">(type: T, manufacturer?: string): Promise<ReturnType<T>> {
|
||||
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<T>;
|
||||
}
|
||||
|
||||
// 只查询当前需要的字段
|
||||
const modelName = modelFields[type as ModelType];
|
||||
const data: Record<string, any> | 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<T>;
|
||||
}
|
||||
@ -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 string> = T extends "video" ? resData[] : resData;
|
||||
interface ImageResData extends BaseConfig {
|
||||
manufacturer: "openAi" | "gemini" | "volcengine" | "runninghub" | "apimart";
|
||||
}
|
||||
|
||||
// 主方法
|
||||
export default async function getConfig<T extends ModelType | "video">(type: T, manufacturer?: string): Promise<ReturnType<T>> {
|
||||
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<T>;
|
||||
type ResDataMap = {
|
||||
text: TextResData;
|
||||
image: ImageResData;
|
||||
video: VideoResData;
|
||||
};
|
||||
|
||||
const errorMessages: Record<AIType, string> = {
|
||||
text: "文本模型配置不存在",
|
||||
image: "图像模型配置不存在",
|
||||
video: "视频模型配置不存在",
|
||||
};
|
||||
|
||||
const needBaseURL: AIType[] = ["text", "video"];
|
||||
|
||||
export default async function getConfig<T extends AIType>(aiType: T): Promise<ResDataMap[T]> {
|
||||
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<string, any> | 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<T>;
|
||||
return result as ResDataMap[T];
|
||||
}
|
||||
|
||||
144
yarn.lock
144
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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user