diff --git a/package.json b/package.json index 39b85a6..4e13a5d 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/src/agents/storyboard/index.ts b/src/agents/storyboard/index.ts index 308985f..4d76cfc 100644 --- a/src/agents/storyboard/index.ts +++ b/src/agents/storyboard/index.ts @@ -242,11 +242,10 @@ ${sections.join("\n\n")} const skipped: number[] = []; for (const item of shots) { - const resultIndex = item.segmentIndex - 1; - const exists = this.shots.some((f) => f.segmentId === resultIndex); + const exists = this.shots.some((f) => f.segmentId === item.segmentIndex); if (exists) { - skipped.push(resultIndex); + skipped.push(item.segmentIndex); continue; } // 分配独立的分镜ID @@ -254,15 +253,15 @@ ${sections.join("\n\n")} const shotId = this.shotIdCounter; this.shots.push({ id: shotId, - segmentId: resultIndex, + segmentId: item.segmentIndex, title: `分镜 ${shotId}`, x: 0, y: 0, cells: item.prompts.map((prompt) => ({ id: u.uuid(), prompt })), - fragmentContent: this.segments[resultIndex]?.description, + fragmentContent: this.segments[item.segmentIndex - 1]?.description, assetsTags: item.assetsTags, }); - added.push({ id: shotId, segmentIndex: resultIndex }); + added.push({ id: shotId, segmentIndex: item.segmentIndex }); } const addedInfo = added.map((a) => `分镜${a.id}(片段${a.segmentIndex})`).join(", "); diff --git a/src/lib/fixDB.ts b/src/lib/fixDB.ts index 9c52bcd..1b9371a 100644 --- a/src/lib/fixDB.ts +++ b/src/lib/fixDB.ts @@ -41,7 +41,14 @@ export default async (knex: Knex): Promise => { .update({ defaultValue: `# 电影分镜提示词优化师\n\n你是专业电影分镜提示词优化师,负责将用户的分镜描述转化为高质量的AI绘图JSON提示词。\n\n## 核心原则\n\n### 保留原始信息\n- 人物描述:五官、表情、姿态、动作、视线\n- 服装细节:款式、颜色、材质\n- 场景元素:建筑、物品、光影、天气\n- 构图信息:人物位置、景深\n\n### 原始语言保留规则(强制执行)\n\n**此规则优先级最高,必须严格遵守:**\n\n| 类型 | 规则 | 正确示例 | 错误示例 |\n|------|------|----------|----------|\n| 人物名 | 保留原文,禁止翻译或拼音 | \`王林 standing\` | \`Wang Lin standing\` |\n| 场景地名 | 保留原文 | \`老旧厢房 interior\` | \`old room interior\` |\n| 道具名 | 保留原文 | \`油纸伞 in hand\` | \`oil paper umbrella\` |\n| 服装名 | 保留原文 | \`青布长衫\` | \`blue cloth robe\` |\n| 物品名 | 保留原文 | \`发黄书册\` | \`yellowed book\` |\n| 建筑名 | 保留原文 | \`厢房 window\` | \`side room window\` |\n\n**prompt_text 写法示范:**\n\`\`\`\nMedium shot, 王林 sitting at desk, 发黄书册 in foreground, 油纸伞 beside, 老旧厢房 interior, dim lighting...\n\`\`\`\n\n### 补充电影语言\n- 景别:大远景/远景/全景/中景/近景/特写\n- 机位:平视/俯拍/仰拍/侧拍/过肩镜头\n- 构图:三分法/中心构图/对角线/框架构图\n- 光影:光源方向、光质(硬光/柔光)、色温\n\n## 连贯性规则\n\n1. **位置固化**:人物左右站位全程不变\n2. **场景固化**:建筑、道具位置全程一致\n3. **光照固化**:光源方向、阴影、色温统一\n4. **时间固化**:时间段和天气全程不变\n5. **色调固化**:主色调和冷暖倾向一致\n\n## Prompt核心规则\n\n1. **极简提炼**:将复杂场景压缩为核心关键词\n2. **标签化语法**:使用"关键词 + 逗号"形式,严禁长难句\n3. **字数控制**:每个 prompt_text 严格控制在 **25-40个单词**\n4. **强制后缀**:每个prompt末尾必须加 \`8k, ultra HD, high detail, no timecode, no subtitles\`\n5. **风格标签**:从用户描述中提取3-4个风格标签追加到prompt\n6. **禁止废话**:严禁 "A scene showing...", "There is a..." 等句式\n7. **原名保留**:人物名、地名、道具名、服装名、物品名必须使用用户输入的原始语言,直接嵌入prompt中\n\n### Prompt组合公式\n\n\`\`\`\n[景别英文] + [主体原名 + 动作英文] + [道具原名] + [场景原名 + 环境英文描述] + [风格标签] + 8k, ultra HD, high detail, no timecode, no subtitles\n\`\`\`\n\n## 插黑图规则\n\n### 识别方式\n用户输入以下任意表述时,识别为插黑图:\n- \`纯黑图\`\n- \`黑屏\`\n- \`黑幕\`\n- \`全黑\`\n- \`black frame\`\n- \`淡出黑\`\n- \`fade to black\`\n\n### 固定输出格式\n插黑图的 prompt_text 固定为:\n\`\`\`\nPure black frame, 8k, ultra HD, high detail, no timecode, no subtitles\n\`\`\`\n\n### 布局计算\n- 插黑图计入总格数\n- 根据实际shot数量(含插黑图)自动计算grid_layout\n- 示例:9个内容镜头 + 3个插黑图 = 12格 = 3x4布局\n\n## 超清标识(强制追加)\n\n每个 prompt_text 末尾必须包含:\n\`\`\`\n8k, ultra HD, high detail, no timecode, no subtitles\n\`\`\`\n\n## 风格标签参考\n\n| 用户风格描述 | 提取标签示例 |\n|-------------|-------------|\n| 赛博朋克 | Cyberpunk, Neon glow, High contrast, Futuristic |\n| 水墨国风 | Chinese ink painting, Minimalist, Ethereal, Monochrome |\n| 日系动漫 | Anime style, Soft lighting, Pastel colors, 2D aesthetic |\n| 电影写实 | Cinematic, Photorealistic, Film grain, Dramatic lighting |\n| 3D渲染 | 3D render, Octane render, Volumetric lighting |\n| 仙侠古风 | Xianxia, Chinese ancient style, 2D aesthetic, Cinematic |\n\n## 分辨率配置\n\n### 全局分辨率\n- 在 \`global_settings\` 中设置全局默认分辨率\n- 可选值:\`"16:9"\` 或 \`"9:16"\`\n\n### 单镜分辨率(新增)\n- 每个shot可独立配置 \`grid_aspect_ratio\`\n- 优先级:单镜配置 > 全局配置\n- 用途:特殊镜头(如竖版手机画面、横版宽屏等)\n\n## 输出格式\n\n默认布局:**3列×3行=9格**,根据实际镜头数量自动调整行数。\n\n严格输出纯净JSON,无任何额外说明:\n\n\`\`\`json\n{\n "image_generation_model": "NanoBananaPro",\n "grid_layout": "3x行数",\n "grid_aspect_ratio": "16:9",\n "style_tags": "风格标签",\n "global_settings": {\n "scene": "场景描述(保留原名)",\n "time": "时间",\n "lighting": "光照",\n "color_tone": "色调",\n "character_position": "人物站位(保留原名)"\n },\n "shots": [\n {\n "shot_number": "第1行第1列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "精简prompt,原名嵌入..."\n }\n ]\n}\n\`\`\`\n\n## 输出示例\n\n用户输入:\n【风格】仙侠古风\n【人物】王林\n【地点】老旧厢房\n【道具】油纸伞、发黄书册、青布长衫\n[1]: 老旧厢房窗外夜色沉静,王林孤身桌旁\n[2]: 王林坐桌前,左手压书册,右手握油纸伞柄\n[3]: 王林俯身低语,眉头微蹙\n[4]: 王林双眼闭合,双手合十\n[5]: 王林手握油纸伞柄特写\n[6]: 王林眼部特写,瞳孔倒映灯光\n[7]: 王林起身推开窗户,月光流泻\n[8]: 王林目光望向窗外夜色\n[9]: 王林坐回书桌沉思\n[10]: 纯黑图\n[11]: 纯黑图\n[12]: 纯黑图\n\n优化输出:\n\`\`\`json\n{\n "image_generation_model": "NanoBananaPro",\n "grid_layout": "3x4",\n "grid_aspect_ratio": "16:9",\n "style_tags": "Xianxia, Chinese ancient style, 2D aesthetic, Cinematic",\n "global_settings": {\n "scene": "老旧厢房 interior at night, 发黄书册 and 油纸伞 as props, cold blue atmosphere",\n "time": "Midnight",\n "lighting": "Dim cold blue with warm lamp spots, soft shadows",\n "color_tone": "Cool blue primary, subtle warm accents",\n "character_position": "王林 center frame throughout"\n },\n "shots": [\n {\n "shot_number": "第1行第1列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Wide shot, 老旧厢房 interior night, 王林 sitting alone at desk, 油纸伞 and 发黄书册 in foreground, breeze through window gauze, cold blue tones, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第1行第2列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Full shot, slight low angle, 王林 seated at desk, left hand pressing 发黄书册, right hand gripping 油纸伞 handle, 青布长衫 collar catching light, lamp glow contrast, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第1行第3列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Medium shot, 王林 leaning forward whispering, brows furrowed, lamp shadow falling on 发黄书册 pages, cool tone, inner resolve, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第2行第1列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Close-up, 王林 eyes closed, resolute brow, hands clasped at chest, 油纸伞 silhouette blurred behind, warm lamp spots, shallow depth, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第2行第2列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Extreme close-up, 王林 hand gripping 油纸伞 handle, finger details sharp, 发黄书册 edge visible, umbrella pattern texture, rim light, cold blue tone, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第2行第3列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Ultra close-up, top light, 王林 eye detail, pupil reflecting lamp and book pages, tear traces on brow, sweat on face, shallow focus, emotion surge, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第3行第1列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Medium shot, 王林 rising to push 老旧厢房 window open, moonlight flooding in, night breeze moving gauze, village path dimly visible, cool tones, spatial layering, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第3行第2列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Close-up POV, 王林 gaze toward night outside 老旧厢房 window, quiet village, scattered lantern lights, window lattice shadows, deep blue grey, silent hope, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第3行第3列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Wide shot, 王林 seated back at desk in thought, murmuring softly, lamp dimming, starry night vast outside 老旧厢房, deep focus, blue yellow mix, determined mind, Xianxia, 2D aesthetic, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第4行第1列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Pure black frame, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第4行第2列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Pure black frame, 8k, ultra HD, high detail, no timecode, no subtitles"\n },\n {\n "shot_number": "第4行第3列",\n "grid_aspect_ratio": "16:9",\n "prompt_text": "Pure black frame, 8k, ultra HD, high detail, no timecode, no subtitles"\n }\n ]\n}\n\`\`\`\n\n## 注意事项\n\n1. **原名强制保留**:每格prompt中的人物名、场景名、道具名、服装名必须使用用户输入的原始语言文字,禁止翻译、禁止拼音转写\n2. 每格必须写完整人物名称(原始语言),不可用代词(he/she/they)\n3. **插黑图固定格式**:\`Pure black frame, 8k, ultra HD, high detail, no timecode, no subtitles\`\n4. 直接输出JSON,不要任何解释或Markdown包裹\n5. 确保各格描述连贯一致\n6. shots数组数量必须与布局格数一致(含插黑图)\n7. **每个prompt_text必须以 \`8k, ultra HD, high detail, no timecode, no subtitles\` 结尾**\n8. **布局自动计算**:根据总镜头数(内容+插黑图)计算行数,列数固定为3\n9. **分辨率配置**:每个shot必须包含 \`grid_aspect_ratio\` 字段,值为 \`"16:9"\` 或 \`"9:16"\`\n\n## 原名保留自查清单\n\n输出前检查每个prompt_text:\n- [ ] 人物名是否为原始语言?(如 王林 而非 Wang Lin)\n- [ ] 场景名是否为原始语言?(如 老旧厢房 而非 old side room)\n- [ ] 道具名是否为原始语言?(如 油纸伞 而非 oil paper umbrella)\n- [ ] 服装名是否为原始语言?(如 青布长衫 而非 blue cloth robe)\n- [ ] 是否以超清标识结尾?\n- [ ] 插黑图是否使用固定格式?\n- [ ] 每个shot是否包含 \`grid_aspect_ratio\` 字段?\n\n## shot_number计算验证表\n\n**16:9布局(3列)验证:**\n| 镜头索引 | 计算公式 | shot_number |\n|---------|---------|-------------|\n| 0 | (0//3+1, 0%3+1) | 第1行第1列 |\n| 1 | (1//3+1, 1%3+1) | 第1行第2列 |\n| 2 | (2//3+1, 2%3+1) | 第1行第3列 |\n| 3 | (3//3+1, 3%3+1) | 第2行第1列 |\n| 4 | (4//3+1, 4%3+1) | 第2行第2列 |\n| 5 | (5//3+1, 5%3+1) | 第2行第3列 |\n\n**9:16布局(2列)验证:**\n| 镜头索引 | 计算公式 | shot_number |\n|---------|---------|-------------|\n| 0 | (0//2+1, 0%2+1) | 第1行第1列 |\n| 1 | (1//2+1, 1%2+1) | 第1行第2列 |\n| 2 | (2//2+1, 2%2+1) | 第2行第1列 |\n| 3 | (3//2+1, 3%2+1) | 第2行第2列 |\n| 4 | (4//2+1, 4%2+1) | 第3行第1列 |\n| 5 | (5//2+1, 5%2+1) | 第3行第2列 |`, }) - .where("id", 8); + .where("code", "generateImagePrompts"); + + + await knex("t_prompts") + .update({ + defaultValue:'# 角色定位\\n你是一名专业的视频分镜图片提示词设计师,根据用户提供的分镜信息,生成具象化的中文图片描述提示词,如果剧本中包含对话要把对话加入到提示词中。\\n## 核心任务\\n将分镜名称和描述转化为一条完整、具象化的中文图片提示词,供后续AI图像生成使用。\\n---\\n## 描述要素(按优先级排列)\\n### 核心要素(必须包含)\\n1. **镜头语言**:镜头类型(特写/近景/中景/全景/远景)、视角(平视/俯视/仰视)、构图方式\\n2. **场景环境**:场所类型、室内外、时间段、天气、季节氛围\\n3. **人物特征**:数量、性别、年龄、外貌特点、服饰细节、发型、表情状态\\n4. **人物动作**:具体姿态、动态描述、肢体语言、互动行为\\n### 辅助要素(丰富画面)\\n5. **空间布局**:前景中景背景层次、物品摆放、景深关系\\n6. **光影色彩**:光源方向、明暗对比、主色调、情绪氛围\\n7. **道具细节**:重要道具的外观、材质、位置\\n8. **材质质感**:环境或物品的材质特征\\n---\\n## 镜头类型参考\\n- **特写**:局部细节放大,强调情绪或关键物件\\n- **近景**:胸部以上,聚焦面部表情\\n- **中景**:腰部以上,平衡角色与环境\\n- **全景**:全身入镜,展现完整动作姿态\\n- **远景**:人物与环境关系,空间感\\n- **大远景**:环境主导,史诗感或孤独感\\n## 视角参考\\n- **平视**:客观中立的观察视角\\n- **俯视**:表现渺小、脆弱、被压迫\\n- **仰视**:表现威严、力量、崇敬\\n- **斜角**:不安、紧张、失衡感\\n- **肩后视角**:增强代入感和互动感\\n---\\n## 输出规范\\n### 必须遵守\\n- 纯中文描述,一段式连贯输出\\n- 使用具象化、可视化的具体描述,避免抽象词汇\\n- 涵盖镜头语言、场景、人物、光影等关键要素\\n- 只输出提示词本身,不包含任何解释说明\\n### 严格禁止在提示词中包含\\n- 分镜编号、镜号标记(如"场景1"、"镜头5")\\n- 技术注释(如"推镜头"、"淡入淡出")\\n- 时长标记、帧数说明\\n- 任何画外解释性文字\\n- 水印、Logo相关描述\\n---\\n## 输出示例\\n用户输入:分镜名称"少年奔跑",描述"主角在校园操场上奔跑"\\n输出:\\n全景镜头平视角度,阳光明媚的午后校园操场,身穿白色运动服的少年正在向前奔跑,短发随风飘动,侧脸表情专注而坚定,双臂有力摆动,背景是清晰可见的红色教学楼,翠绿草坪平整开阔,银色篮球架立于画面右侧,整体暖黄色调,自然光从左侧照射形成柔和投影,充满青春活力氛围\\n---\\n请等待用户提供分镜信息后开始生成提示词。', + }) + .where("code", "storyboard-polish"); const videoText = await knex("t_prompts").where("code", "video-text").first(); if (!videoText) { await knex("t_prompts").insert({ diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index 62c0713..9672b57 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -436,7 +436,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => type: "system", parentCode: null, defaultValue: - '# 角色定位\\n你是一名专业的视频分镜图片提示词设计师,根据用户提供的分镜信息,生成具象化的中文图片描述提示词。\\n## 核心任务\\n将分镜名称和描述转化为一条完整、具象化的中文图片提示词,供后续AI图像生成使用。\\n---\\n## 描述要素(按优先级排列)\\n### 核心要素(必须包含)\\n1. **镜头语言**:镜头类型(特写/近景/中景/全景/远景)、视角(平视/俯视/仰视)、构图方式\\n2. **场景环境**:场所类型、室内外、时间段、天气、季节氛围\\n3. **人物特征**:数量、性别、年龄、外貌特点、服饰细节、发型、表情状态\\n4. **人物动作**:具体姿态、动态描述、肢体语言、互动行为\\n### 辅助要素(丰富画面)\\n5. **空间布局**:前景中景背景层次、物品摆放、景深关系\\n6. **光影色彩**:光源方向、明暗对比、主色调、情绪氛围\\n7. **道具细节**:重要道具的外观、材质、位置\\n8. **材质质感**:环境或物品的材质特征\\n---\\n## 镜头类型参考\\n- **特写**:局部细节放大,强调情绪或关键物件\\n- **近景**:胸部以上,聚焦面部表情\\n- **中景**:腰部以上,平衡角色与环境\\n- **全景**:全身入镜,展现完整动作姿态\\n- **远景**:人物与环境关系,空间感\\n- **大远景**:环境主导,史诗感或孤独感\\n## 视角参考\\n- **平视**:客观中立的观察视角\\n- **俯视**:表现渺小、脆弱、被压迫\\n- **仰视**:表现威严、力量、崇敬\\n- **斜角**:不安、紧张、失衡感\\n- **肩后视角**:增强代入感和互动感\\n---\\n## 输出规范\\n### 必须遵守\\n- 纯中文描述,一段式连贯输出\\n- 使用具象化、可视化的具体描述,避免抽象词汇\\n- 涵盖镜头语言、场景、人物、光影等关键要素\\n- 只输出提示词本身,不包含任何解释说明\\n### 严格禁止在提示词中包含\\n- 分镜编号、镜号标记(如"场景1"、"镜头5")\\n- 技术注释(如"推镜头"、"淡入淡出")\\n- 时长标记、帧数说明\\n- 任何画外解释性文字\\n- 水印、Logo相关描述\\n---\\n## 输出示例\\n用户输入:分镜名称"少年奔跑",描述"主角在校园操场上奔跑"\\n输出:\\n全景镜头平视角度,阳光明媚的午后校园操场,身穿白色运动服的少年正在向前奔跑,短发随风飘动,侧脸表情专注而坚定,双臂有力摆动,背景是清晰可见的红色教学楼,翠绿草坪平整开阔,银色篮球架立于画面右侧,整体暖黄色调,自然光从左侧照射形成柔和投影,充满青春活力氛围\\n---\\n请等待用户提供分镜信息后开始生成提示词。', + '# 角色定位\\n你是一名专业的视频分镜图片提示词设计师,根据用户提供的分镜信息,生成具象化的中文图片描述提示词,如果剧本中包含对话要把对话加入到提示词中。\\n## 核心任务\\n将分镜名称和描述转化为一条完整、具象化的中文图片提示词,供后续AI图像生成使用。\\n---\\n## 描述要素(按优先级排列)\\n### 核心要素(必须包含)\\n1. **镜头语言**:镜头类型(特写/近景/中景/全景/远景)、视角(平视/俯视/仰视)、构图方式\\n2. **场景环境**:场所类型、室内外、时间段、天气、季节氛围\\n3. **人物特征**:数量、性别、年龄、外貌特点、服饰细节、发型、表情状态\\n4. **人物动作**:具体姿态、动态描述、肢体语言、互动行为\\n### 辅助要素(丰富画面)\\n5. **空间布局**:前景中景背景层次、物品摆放、景深关系\\n6. **光影色彩**:光源方向、明暗对比、主色调、情绪氛围\\n7. **道具细节**:重要道具的外观、材质、位置\\n8. **材质质感**:环境或物品的材质特征\\n---\\n## 镜头类型参考\\n- **特写**:局部细节放大,强调情绪或关键物件\\n- **近景**:胸部以上,聚焦面部表情\\n- **中景**:腰部以上,平衡角色与环境\\n- **全景**:全身入镜,展现完整动作姿态\\n- **远景**:人物与环境关系,空间感\\n- **大远景**:环境主导,史诗感或孤独感\\n## 视角参考\\n- **平视**:客观中立的观察视角\\n- **俯视**:表现渺小、脆弱、被压迫\\n- **仰视**:表现威严、力量、崇敬\\n- **斜角**:不安、紧张、失衡感\\n- **肩后视角**:增强代入感和互动感\\n---\\n## 输出规范\\n### 必须遵守\\n- 纯中文描述,一段式连贯输出\\n- 使用具象化、可视化的具体描述,避免抽象词汇\\n- 涵盖镜头语言、场景、人物、光影等关键要素\\n- 只输出提示词本身,不包含任何解释说明\\n### 严格禁止在提示词中包含\\n- 分镜编号、镜号标记(如"场景1"、"镜头5")\\n- 技术注释(如"推镜头"、"淡入淡出")\\n- 时长标记、帧数说明\\n- 任何画外解释性文字\\n- 水印、Logo相关描述\\n---\\n## 输出示例\\n用户输入:分镜名称"少年奔跑",描述"主角在校园操场上奔跑"\\n输出:\\n全景镜头平视角度,阳光明媚的午后校园操场,身穿白色运动服的少年正在向前奔跑,短发随风飘动,侧脸表情专注而坚定,双臂有力摆动,背景是清晰可见的红色教学楼,翠绿草坪平整开阔,银色篮球架立于画面右侧,整体暖黄色调,自然光从左侧照射形成柔和投影,充满青春活力氛围\\n---\\n请等待用户提供分镜信息后开始生成提示词。', customValue: null, }, { @@ -634,15 +634,16 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => }, initData: async (knex) => { await knex("t_imageModel").insert([ - { id: 1, manufacturer: "volcengine", model: "doubao-seedream-4-5-251128", grid: 0, type: "ti2i" }, - { id: 2, manufacturer: "volcengine", model: "doubao-seedream-4-0-250828", grid: 0, type: "ti2i" }, - { id: 3, manufacturer: "kling", model: "kling-image-o1", grid: 0, type: "ti2i" }, - { id: 4, manufacturer: "gemini", model: "gemini-2.5-flash-image", grid: 1, type: "ti2i" }, - { id: 5, manufacturer: "gemini", model: "gemini-3-pro-image-preview", grid: 1, type: "ti2i" }, - { id: 6, manufacturer: "vidu", model: "viduq1", grid: 0, type: "i2i" }, - { id: 7, manufacturer: "vidu", model: "viduq2", grid: 0, type: "ti2i" }, - { id: 8, manufacturer: "runninghub", model: "nanobanana", grid: 1, type: "ti2i" }, - { id: 9, manufacturer: "modelScope", model: "Qwen/Qwen-Image", grid: 1, type: "ti2i" }, + { manufacturer: "volcengine", model: "doubao-seedream-5-0-260128", grid: 1, type: "ti2i" }, + { manufacturer: "volcengine", model: "doubao-seedream-4-5-251128", grid: 0, type: "ti2i" }, + { manufacturer: "volcengine", model: "doubao-seedream-4-0-250828", grid: 0, type: "ti2i" }, + { manufacturer: "kling", model: "kling-image-o1", grid: 0, type: "ti2i" }, + { manufacturer: "gemini", model: "gemini-2.5-flash-image", grid: 1, type: "ti2i" }, + { manufacturer: "gemini", model: "gemini-3-pro-image-preview", grid: 1, type: "ti2i" }, + { manufacturer: "vidu", model: "viduq1", grid: 0, type: "i2i" }, + { manufacturer: "vidu", model: "viduq2", grid: 0, type: "ti2i" }, + { manufacturer: "runninghub", model: "nanobanana", grid: 1, type: "ti2i" }, + { manufacturer: "modelScope", model: "Qwen/Qwen-Image", grid: 1, type: "ti2i" }, ]); }, }, diff --git a/src/router.ts b/src/router.ts index 23eb89b..cd4946e 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash bf59be4347a649430bc8b6067c3cf9ef +// @routes-hash c97cf72361299980ea4b0c43549a0de8 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -48,38 +48,41 @@ import route44 from "./routes/script/geScriptApi"; import route45 from "./routes/setting/addModel"; import route46 from "./routes/setting/configurationModel"; import route47 from "./routes/setting/delModel"; -import route48 from "./routes/setting/getAiModelMap"; -import route49 from "./routes/setting/getLog"; -import route50 from "./routes/setting/getSetting"; -import route51 from "./routes/setting/getVideoModelList"; -import route52 from "./routes/setting/updateModel"; -import route53 from "./routes/setting/updeteModel"; -import route54 from "./routes/storyboard/batchSuperScoreImage"; -import route55 from "./routes/storyboard/chatStoryboard"; -import route56 from "./routes/storyboard/delStoryboard"; -import route57 from "./routes/storyboard/generateShotImage"; -import route58 from "./routes/storyboard/generateStoryboardApi"; -import route59 from "./routes/storyboard/generateVideoPrompt"; -import route60 from "./routes/storyboard/getStoryboard"; -import route61 from "./routes/storyboard/keepStoryboard"; -import route62 from "./routes/storyboard/saveStoryboard"; -import route63 from "./routes/storyboard/uploadImage"; -import route64 from "./routes/task/getTaskApi"; -import route65 from "./routes/task/taskDetails"; -import route66 from "./routes/user/getUser"; -import route67 from "./routes/video/addVideo"; -import route68 from "./routes/video/addVideoConfig"; -import route69 from "./routes/video/deleteVideoConfig"; -import route70 from "./routes/video/generatePrompt"; -import route71 from "./routes/video/generateVideo"; -import route72 from "./routes/video/getManufacturer"; -import route73 from "./routes/video/getVideo"; -import route74 from "./routes/video/getVideoConfigs"; -import route75 from "./routes/video/getVideoModel"; -import route76 from "./routes/video/getVideoStoryboards"; -import route77 from "./routes/video/reviseVideoStoryboards"; -import route78 from "./routes/video/saveVideo"; -import route79 from "./routes/video/upDateVideoConfig"; +import route48 from "./routes/setting/getAiModelList"; +import route49 from "./routes/setting/getAiModelMap"; +import route50 from "./routes/setting/getLog"; +import route51 from "./routes/setting/getSetting"; +import route52 from "./routes/setting/getVideoModelDetail"; +import route53 from "./routes/setting/getVideoModelList"; +import route54 from "./routes/setting/updateModel"; +import route55 from "./routes/setting/updeteModel"; +import route56 from "./routes/storyboard/batchSuperScoreImage"; +import route57 from "./routes/storyboard/chatStoryboard"; +import route58 from "./routes/storyboard/delStoryboard"; +import route59 from "./routes/storyboard/generateShotImage"; +import route60 from "./routes/storyboard/generateStoryboardApi"; +import route61 from "./routes/storyboard/generateVideoPrompt"; +import route62 from "./routes/storyboard/getStoryboard"; +import route63 from "./routes/storyboard/keepStoryboard"; +import route64 from "./routes/storyboard/saveStoryboard"; +import route65 from "./routes/storyboard/uploadImage"; +import route66 from "./routes/task/getTaskApi"; +import route67 from "./routes/task/taskDetails"; +import route68 from "./routes/user/getUser"; +import route69 from "./routes/user/saveUser"; +import route70 from "./routes/video/addVideo"; +import route71 from "./routes/video/addVideoConfig"; +import route72 from "./routes/video/deleteVideoConfig"; +import route73 from "./routes/video/generatePrompt"; +import route74 from "./routes/video/generateVideo"; +import route75 from "./routes/video/getManufacturer"; +import route76 from "./routes/video/getVideo"; +import route77 from "./routes/video/getVideoConfigs"; +import route78 from "./routes/video/getVideoModel"; +import route79 from "./routes/video/getVideoStoryboards"; +import route80 from "./routes/video/reviseVideoStoryboards"; +import route81 from "./routes/video/saveVideo"; +import route82 from "./routes/video/upDateVideoConfig"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -129,36 +132,39 @@ export default async (app: Express) => { app.use("/setting/addModel", route45); app.use("/setting/configurationModel", route46); app.use("/setting/delModel", route47); - app.use("/setting/getAiModelMap", route48); - app.use("/setting/getLog", route49); - app.use("/setting/getSetting", route50); - app.use("/setting/getVideoModelList", route51); - app.use("/setting/updateModel", route52); - app.use("/setting/updeteModel", route53); - app.use("/storyboard/batchSuperScoreImage", route54); - app.use("/storyboard/chatStoryboard", route55); - app.use("/storyboard/delStoryboard", route56); - app.use("/storyboard/generateShotImage", route57); - app.use("/storyboard/generateStoryboardApi", route58); - app.use("/storyboard/generateVideoPrompt", route59); - app.use("/storyboard/getStoryboard", route60); - app.use("/storyboard/keepStoryboard", route61); - app.use("/storyboard/saveStoryboard", route62); - app.use("/storyboard/uploadImage", route63); - app.use("/task/getTaskApi", route64); - app.use("/task/taskDetails", route65); - app.use("/user/getUser", route66); - app.use("/video/addVideo", route67); - app.use("/video/addVideoConfig", route68); - app.use("/video/deleteVideoConfig", route69); - app.use("/video/generatePrompt", route70); - app.use("/video/generateVideo", route71); - app.use("/video/getManufacturer", route72); - app.use("/video/getVideo", route73); - app.use("/video/getVideoConfigs", route74); - app.use("/video/getVideoModel", route75); - app.use("/video/getVideoStoryboards", route76); - app.use("/video/reviseVideoStoryboards", route77); - app.use("/video/saveVideo", route78); - app.use("/video/upDateVideoConfig", route79); + app.use("/setting/getAiModelList", route48); + app.use("/setting/getAiModelMap", route49); + app.use("/setting/getLog", route50); + app.use("/setting/getSetting", route51); + app.use("/setting/getVideoModelDetail", route52); + app.use("/setting/getVideoModelList", route53); + app.use("/setting/updateModel", route54); + app.use("/setting/updeteModel", route55); + app.use("/storyboard/batchSuperScoreImage", route56); + app.use("/storyboard/chatStoryboard", route57); + app.use("/storyboard/delStoryboard", route58); + app.use("/storyboard/generateShotImage", route59); + app.use("/storyboard/generateStoryboardApi", route60); + app.use("/storyboard/generateVideoPrompt", route61); + app.use("/storyboard/getStoryboard", route62); + app.use("/storyboard/keepStoryboard", route63); + app.use("/storyboard/saveStoryboard", route64); + app.use("/storyboard/uploadImage", route65); + app.use("/task/getTaskApi", route66); + app.use("/task/taskDetails", route67); + app.use("/user/getUser", route68); + app.use("/user/saveUser", route69); + app.use("/video/addVideo", route70); + app.use("/video/addVideoConfig", route71); + app.use("/video/deleteVideoConfig", route72); + app.use("/video/generatePrompt", route73); + app.use("/video/generateVideo", route74); + app.use("/video/getManufacturer", route75); + app.use("/video/getVideo", route76); + app.use("/video/getVideoConfigs", route77); + app.use("/video/getVideoModel", route78); + app.use("/video/getVideoStoryboards", route79); + app.use("/video/reviseVideoStoryboards", route80); + app.use("/video/saveVideo", route81); + app.use("/video/upDateVideoConfig", route82); } diff --git a/src/routes/other/testAI.ts b/src/routes/other/testAI.ts index 4fe5d85..8296f83 100644 --- a/src/routes/other/testAI.ts +++ b/src/routes/other/testAI.ts @@ -48,6 +48,7 @@ export default router.post( ); res.status(200).send(success(reply)); } catch (err) { + console.log("%c Line:51 🥟 err", "background:#e41a6a", err); const msg = u.error(err).message; console.error(msg); res.status(500).send(error(msg)); diff --git a/src/routes/script/generateScriptApi.ts b/src/routes/script/generateScriptApi.ts index 87a0427..7f79258 100644 --- a/src/routes/script/generateScriptApi.ts +++ b/src/routes/script/generateScriptApi.ts @@ -1,7 +1,7 @@ import express from "express"; import u from "@/utils"; import { z } from "zod"; -import { success } from "@/lib/responseFormat"; +import { error, success } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; import { generateScript } from "@/utils/generateScript"; const router = express.Router(); @@ -43,14 +43,18 @@ export default router.post( if (novelData.length == 0) return res.status(500).send(success({ message: "原文为空" })); const result: string = mergeNovelText(novelData); + try { + const data = await generateScript(parameter ?? "", result ?? ""); + if (!data) return res.status(500).send({ message: "生成剧本失败" }); - const data = await generateScript(parameter ?? "", result ?? ""); - if (!data) return res.status(500).send({ message: "生成剧本失败" }); + await u.db("t_script").where("id", scriptId).update({ + content: data, + }); - await u.db("t_script").where("id", scriptId).update({ - content: data, - }); - - res.status(200).send(success({ message: "生成剧本成功" })); + res.status(200).send(success({ message: "生成剧本成功" })); + } catch (e) { + const errMsg = u.error(e).message || "生成剧本失败"; + res.status(500).send(error(errMsg)); + } }, ); 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..8a75a08 100644 --- a/src/routes/video/deleteVideoConfig.ts +++ b/src/routes/video/deleteVideoConfig.ts @@ -33,9 +33,9 @@ export default router.post( if (result.filePath) { filesToDelete.push(result.filePath); } - if (result.firstFrame) { - filesToDelete.push(result.firstFrame); - } + // if (result.firstFrame) { + // filesToDelete.push(result.firstFrame); + // } } // 删除文件 diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 25cd1ff..47862e0 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,20 +1,6 @@ -// @db-hash ab4e3e93bfba304164daa7d28c804eaf +// @db-hash 0f9789bd5ad2eebd79bd502988efcb4e //该文件由脚本自动生成,请勿手动修改 -export interface _t_video_old_20260210 { - 'aiConfigId'?: number | null; - 'configId'?: number | null; - 'filePath'?: string | null; - 'firstFrame'?: string | null; - 'id'?: number; - 'model'?: string | null; - 'prompt'?: string | null; - 'resolution'?: string | null; - 'scriptId'?: number | null; - 'state'?: number | null; - 'storyboardImgs'?: string | null; - 'time'?: number | null; -} export interface t_aiModelMap { 'configId'?: number | null; 'id'?: number; @@ -66,13 +52,6 @@ export interface t_image { 'type'?: string | null; 'videoId'?: number | null; } -export interface t_imageConfig { - 'grid'?: number | null; - 'id'?: number; - 'manufacturer'?: string | null; - 'model'?: string | null; - 'type'?: string | null; -} export interface t_imageModel { 'grid'?: number | null; 'id'?: number; @@ -145,15 +124,6 @@ export interface t_taskList { 'startTime'?: string | null; 'state'?: string | null; } -export interface t_textConfig { - 'id'?: number; - 'image'?: number | null; - 'manufacturer'?: string | null; - 'model'?: string | null; - 'responseFormat'?: string | null; - 'think'?: number | null; - 'tool'?: number | null; -} export interface t_textModel { 'id'?: number; 'image'?: number | null; @@ -212,13 +182,11 @@ export interface t_videoModel { } export interface DB { - "_t_video_old_20260210": _t_video_old_20260210; "t_aiModelMap": t_aiModelMap; "t_assets": t_assets; "t_chatHistory": t_chatHistory; "t_config": t_config; "t_image": t_image; - "t_imageConfig": t_imageConfig; "t_imageModel": t_imageModel; "t_novel": t_novel; "t_outline": t_outline; @@ -228,7 +196,6 @@ export interface DB { "t_setting": t_setting; "t_storyline": t_storyline; "t_taskList": t_taskList; - "t_textConfig": t_textConfig; "t_textModel": t_textModel; "t_user": t_user; "t_video": t_video; diff --git a/src/utils/ai/image/owned/other.ts b/src/utils/ai/image/owned/other.ts index b0158e1..f30fc89 100644 --- a/src/utils/ai/image/owned/other.ts +++ b/src/utils/ai/image/owned/other.ts @@ -69,26 +69,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..919dbfb 100644 --- a/src/utils/ai/image/owned/volcengine.ts +++ b/src/utils/ai/image/owned/volcengine.ts @@ -8,18 +8,26 @@ 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, watermark: false, ...(input.imageBase64 && { image: input.imageBase64 }), }; - const url = config.baseURL ?? "https://ark.cn-beijing.volces.com/api/v3/images/generations"; try { const { data } = await axios.post(url, body, { headers: { Authorization: apiKey } }); @@ -28,4 +36,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 a2dfdf5..3dd97f7 100644 --- a/src/utils/ai/text/index.ts +++ b/src/utils/ai/text/index.ts @@ -34,7 +34,6 @@ const buildOptions = async (input: AIInput, config: AIConfig = {}) => { if (!owned) owned = modelList.find((m) => m.manufacturer === manufacturer); } if (!owned) throw new Error("不支持的厂商"); - console.log("%c Line:36 🥛 owned", "background:#6ec1c2", owned); const modelInstance = owned.instance({ apiKey, baseURL: baseURL!, name: "xixixi" }); @@ -55,8 +54,9 @@ const buildOptions = async (input: AIInput, config: AIConfig = {}) => { }; const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null; - const chatModelManufacturer = ["volcengine", "other", "openai"]; + const chatModelManufacturer = ["volcengine", "other", "openai", "modelScope"]; const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!); + return { config: { model: modelFn as LanguageModel, @@ -79,7 +79,7 @@ const ai = Object.create({}) as { ai.invoke = async (input: AIInput, config: AIConfig) => { const options = await buildOptions(input, config); - console.log("%c Line:81 🍧 options", "background:#93c0a4", options); + const result = await generateText(options.config); if (options.responseFormat === "object" && input.output) { const pattern = /{[^{}]*}|{(?:[^{}]*|{[^{}]*})*}/g; @@ -96,7 +96,7 @@ ai.invoke = async (input: AIInput, config: AIConfig) => { ai.stream = async (input: AIInput, config: AIConfig) => { const options = await buildOptions(input, config); - console.log("%c Line:98 🍬 options", "background:#fca650", options); + return streamText(options.config); }; diff --git a/src/utils/ai/text/modelList.ts b/src/utils/ai/text/modelList.ts index ea1789c..a3c102c 100644 --- a/src/utils/ai/text/modelList.ts +++ b/src/utils/ai/text/modelList.ts @@ -1,7 +1,7 @@ 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"; 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"