From 46ac187d96380ed2d5c0a38a23626ddc4a46a31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Thu, 26 Feb 2026 15:29:42 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=9C=80=E6=96=B0web?= =?UTF-8?q?=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/routes/setting/getAiModelMap.ts | 2 +- src/types/database.d.ts | 19 +++---------------- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index dc914e0..3279f7e 100644 --- a/README.md +++ b/README.md @@ -546,11 +546,11 @@ Toonflow 基于 AGPL-3.0 协议开源发布,许可证详情:https://www.gnu. --- - +--- # 🙏 致谢 diff --git a/src/routes/setting/getAiModelMap.ts b/src/routes/setting/getAiModelMap.ts index fa10f51..20ec1ec 100644 --- a/src/routes/setting/getAiModelMap.ts +++ b/src/routes/setting/getAiModelMap.ts @@ -8,6 +8,6 @@ export default router.post("/", async (req, res) => { const configData = await u .db("t_aiModelMap") .leftJoin("t_config", "t_aiModelMap.configId", "t_config.id") - .select("t_aiModelMap.name", "t_config.model", "t_aiModelMap.id", "t_aiModelMap.key"); + .select("t_aiModelMap.name", "t_config.model", "t_aiModelMap.id", "t_aiModelMap.key", "t_config.manufacturer"); res.status(200).send(success(configData)); }); diff --git a/src/types/database.d.ts b/src/types/database.d.ts index c90deda..dffd599 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,19 +1,6 @@ -// @db-hash 5a633f2d45df5d971905dd32c0ac9880 +// @db-hash 945540586ca016b1b9a42042fc5ccbf3 //该文件由脚本自动生成,请勿手动修改 -export interface _t_video_old_20260131 { - '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; @@ -52,7 +39,6 @@ export interface t_config { 'manufacturer'?: string | null; 'model'?: string | null; 'modelType'?: string | null; - 'name'?: string | null; 'type'?: string | null; 'userId'?: number | null; } @@ -139,6 +125,7 @@ export interface t_user { export interface t_video { 'aiConfigId'?: number | null; 'configId'?: number | null; + 'errorReason'?: string | null; 'filePath'?: string | null; 'firstFrame'?: string | null; 'id'?: number; @@ -151,6 +138,7 @@ export interface t_video { 'time'?: number | null; } export interface t_videoConfig { + 'aiConfigId'?: number | null; 'audioEnabled'?: number | null; 'createTime'?: number | null; 'duration'?: number | null; @@ -170,7 +158,6 @@ export interface t_videoConfig { } export interface DB { - "_t_video_old_20260131": _t_video_old_20260131; "t_aiModelMap": t_aiModelMap; "t_assets": t_assets; "t_chatHistory": t_chatHistory; From 8e7e3af0ba00a2464f75b8e847584c6acf212f08 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Thu, 26 Feb 2026 18:41:38 +0800 Subject: [PATCH 02/17] no message --- package.json | 2 +- scripts/main.ts | 42 +++++++- src/router.ts | 56 ++++++----- src/routes/assets/generateAssets.ts | 14 ++- src/routes/user/saveUser.ts | 24 +++++ src/routes/video/deleteVideoConfig.ts | 3 - src/routes/video/generateVideo.ts | 2 - src/utils/ai/image/index.ts | 12 +-- src/utils/ai/image/modelList.ts | 6 ++ src/utils/ai/image/owned/modelScope.ts | 133 +++++++++++++++++++++++++ src/utils/ai/image/owned/other.ts | 21 ++-- src/utils/ai/image/owned/volcengine.ts | 15 ++- src/utils/ai/text/index.ts | 14 +-- src/utils/ai/text/modelList.ts | 51 ++++++++-- yarn.lock | 50 ++++------ 15 files changed, 346 insertions(+), 99 deletions(-) create mode 100644 src/routes/user/saveUser.ts create mode 100644 src/utils/ai/image/owned/modelScope.ts 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" From a9ce229c89078d67df7e116045cea611e2bd5b56 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Thu, 26 Feb 2026 18:43:00 +0800 Subject: [PATCH 03/17] Revert "no message" This reverts commit 8e7e3af0ba00a2464f75b8e847584c6acf212f08. --- package.json | 2 +- scripts/main.ts | 42 +------- src/router.ts | 56 +++++------ src/routes/assets/generateAssets.ts | 14 +-- src/routes/user/saveUser.ts | 24 ----- src/routes/video/deleteVideoConfig.ts | 3 + src/routes/video/generateVideo.ts | 2 + src/utils/ai/image/index.ts | 12 +-- src/utils/ai/image/modelList.ts | 6 -- src/utils/ai/image/owned/modelScope.ts | 133 ------------------------- src/utils/ai/image/owned/other.ts | 21 ++-- src/utils/ai/image/owned/volcengine.ts | 15 +-- src/utils/ai/text/index.ts | 14 +-- src/utils/ai/text/modelList.ts | 51 ++-------- yarn.lock | 50 ++++++---- 15 files changed, 99 insertions(+), 346 deletions(-) delete mode 100644 src/routes/user/saveUser.ts delete mode 100644 src/utils/ai/image/owned/modelScope.ts diff --git a/package.json b/package.json index 203b72a..8fd8fad 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-v5": "^2.1.0", + "qwen-ai-provider": "^0.1.1", "serialize-error": "^13.0.1", "sharp": "^0.34.5", "sqlite3": "^5.1.7", diff --git a/scripts/main.ts b/scripts/main.ts index 761511b..a1e2470 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -1,33 +1,7 @@ -import { app, BrowserWindow, dialog } from "electron"; +import { app, BrowserWindow } 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(); @@ -47,20 +21,6 @@ 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 7175522..ae73206 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash 2c228db11434e5c7874e23f6fe832d00 +// @routes-hash 3cfad40b3c8658b442ab766a9323d740 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -65,20 +65,19 @@ 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/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"; +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"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -145,18 +144,17 @@ export default async (app: Express) => { app.use("/task/getTaskApi", route62); app.use("/task/taskDetails", route63); app.use("/user/getUser", route64); - 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); + 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); } diff --git a/src/routes/assets/generateAssets.ts b/src/routes/assets/generateAssets.ts index b0d9cdb..7889f1a 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,error } from "@/lib/responseFormat"; +import { success } 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"); - try{ - const contentStr = await u.ai.image( + + const contentStr = await u.ai.image( { systemPrompt, prompt: userPrompt, @@ -175,14 +175,6 @@ 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 deleted file mode 100644 index 07709a2..0000000 --- a/src/routes/user/saveUser.ts +++ /dev/null @@ -1,24 +0,0 @@ -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 30c1884..360467c 100644 --- a/src/routes/video/deleteVideoConfig.ts +++ b/src/routes/video/deleteVideoConfig.ts @@ -33,6 +33,9 @@ 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 d213aa8..e0b1b5b 100644 --- a/src/routes/video/generateVideo.ts +++ b/src/routes/video/generateVideo.ts @@ -6,6 +6,8 @@ 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 ae7ddcb..3054ebd 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,7 +26,6 @@ const modelInstance = { runninghub: runninghub, // apimart: apimart, other, - modelScope, } as const; export default async (input: ImageConfig, config: AIConfig) => { @@ -36,10 +35,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" && manufacturer !== "modelScope") { - // const owned = modelList.find((m) => m.model === model); - // if (!owned) throw new Error("不支持的模型"); - // } + if (manufacturer !== "other") { + const owned = modelList.find((m) => m.model === model); + if (!owned) throw new Error("不支持的模型"); + } // 补充图片的 base64 内容类型字符串 if (input.imageBase64 && input.imageBase64.length > 0) { @@ -66,6 +65,7 @@ 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 544fc86..1cce6d9 100644 --- a/src/utils/ai/image/modelList.ts +++ b/src/utils/ai/image/modelList.ts @@ -19,12 +19,6 @@ 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 deleted file mode 100644 index 4a13dee..0000000 --- a/src/utils/ai/image/owned/modelScope.ts +++ /dev/null @@ -1,133 +0,0 @@ -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 8ae9e59..b0158e1 100644 --- a/src/utils/ai/image/owned/other.ts +++ b/src/utils/ai/image/owned/other.ts @@ -27,7 +27,6 @@ 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) { @@ -70,28 +69,26 @@ export default async (input: ImageConfig, config: AIConfig): Promise => console.error(JSON.stringify(result.response, null, 2)); throw new Error("图片生成失败"); } - // 匹配所有 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,.+/); + const mdMatch = result.text.match(/^!\[.*?\]\((.+?)\)$/); + if (mdMatch) { + const imgInfo = mdMatch[1]; + const base64InMd = imgInfo.match(/data:image\/[a-z]+;base64,(.+)/); if (base64InMd) { - return imgInfo; // 已经是base64,直接返回 + return imgInfo; } else { - return await urlToBase64(imgInfo); // 否则尝试转base64 + return await urlToBase64(imgInfo); } } - // 检查纯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 25afa69..2d93fdf 100644 --- a/src/utils/ai/image/owned/volcengine.ts +++ b/src/utils/ai/image/owned/volcengine.ts @@ -8,20 +8,11 @@ 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: sizeMap[input.aspectRatio][size], + size, response_format: "url", sequential_image_generation: "disabled", stream: false, @@ -37,4 +28,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 a47273f..bfc45d7 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" || manufacturer == "modelScope") { - const owned = modelList.find((m) => m.manufacturer === manufacturer); - // } else { - // owned = modelList.find((m) => m.model === model); - // } + let owned; + if (manufacturer == "other") { + 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", "modelScope"]; + const chatModelManufacturer = ["doubao", "other", "openai"]; 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 c7ab3d4..421885a 100644 --- a/src/utils/ai/text/modelList.ts +++ b/src/utils/ai/text/modelList.ts @@ -1,11 +1,11 @@ -import { createOpenAI, OpenAIProviderSettings } from "@ai-sdk/openai"; +import { createOpenAI } from "@ai-sdk/openai"; import { createDeepSeek } from "@ai-sdk/deepseek"; import { createZhipu } from "zhipu-ai-provider"; -import { createQwen } from "qwen-ai-provider-v5"; +import { createQwen } from "qwen-ai-provider"; 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,15 +82,6 @@ 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", @@ -195,25 +186,7 @@ const modelList: Owned[] = [ { manufacturer: "qwen", model: "qwen-vl-max", - 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", + responseFormat: "schema", image: true, think: false, instance: createQwen, @@ -440,7 +413,7 @@ const modelList: Owned[] = [ tool: true, }, //xai - { + { manufacturer: "xai", model: "grok-3", responseFormat: "schema", @@ -449,7 +422,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4", responseFormat: "schema", @@ -458,7 +431,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", @@ -467,16 +440,6 @@ 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 f568547..1397131 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,6 +74,15 @@ "@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" @@ -83,14 +92,12 @@ "@standard-schema/spec" "^1.0.0" eventsource-parser "^3.0.6" -"@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== +"@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: - "@ai-sdk/provider" "3.0.8" - "@standard-schema/spec" "^1.1.0" - eventsource-parser "^3.0.6" + json-schema "^0.4.0" "@ai-sdk/provider@2.0.1", "@ai-sdk/provider@^2.0.0": version "2.0.1" @@ -106,13 +113,6 @@ 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,6 +3160,11 @@ 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" @@ -3609,13 +3614,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-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== +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" "^3.0.0" - "@ai-sdk/provider-utils" "^4.0.0" + "@ai-sdk/provider" "^1.0.7" + "@ai-sdk/provider-utils" "^2.1.6" range-parser@^1.2.1: version "1.2.1" @@ -3841,6 +3846,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" From 1d80e476bfc72eab7084ac9fb30a81adf3b87c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Thu, 26 Feb 2026 18:43:05 +0800 Subject: [PATCH 04/17] no message --- src/router.ts | 304 ++++++++++++++-------------- src/routes/assets/delAssetsImage.ts | 27 +++ src/types/database.d.ts | 5 +- 3 files changed, 182 insertions(+), 154 deletions(-) create mode 100644 src/routes/assets/delAssetsImage.ts diff --git a/src/router.ts b/src/router.ts index ae73206..abef8f6 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,160 +1,162 @@ -// @routes-hash 3cfad40b3c8658b442ab766a9323d740 +// @routes-hash a5e432459af85c08bbc13a86444f292c import { Express } from "express"; import route1 from "./routes/assets/addAssets"; import route2 from "./routes/assets/delAssets"; -import route3 from "./routes/assets/generateAssets"; -import route4 from "./routes/assets/getAssets"; -import route5 from "./routes/assets/getImage"; -import route6 from "./routes/assets/getStoryboard"; -import route7 from "./routes/assets/polishPrompt"; -import route8 from "./routes/assets/saveAssets"; -import route9 from "./routes/assets/updateAssets"; -import route10 from "./routes/index/index"; -import route11 from "./routes/novel/addNovel"; -import route12 from "./routes/novel/delNovel"; -import route13 from "./routes/novel/getNovel"; -import route14 from "./routes/novel/updateNovel"; -import route15 from "./routes/other/clearDatabase"; -import route16 from "./routes/other/deleteAllData"; -import route17 from "./routes/other/getCaptcha"; -import route18 from "./routes/other/login"; -import route19 from "./routes/other/testAI"; -import route20 from "./routes/other/testImage"; -import route21 from "./routes/other/testVideo"; -import route22 from "./routes/outline/addOutline"; -import route23 from "./routes/outline/agentsOutline"; -import route24 from "./routes/outline/delOutline"; -import route25 from "./routes/outline/getHistory"; -import route26 from "./routes/outline/getOutline"; -import route27 from "./routes/outline/getPartScript"; -import route28 from "./routes/outline/getStoryline"; -import route29 from "./routes/outline/setHistory"; -import route30 from "./routes/outline/updateOutline"; -import route31 from "./routes/outline/updateScript"; -import route32 from "./routes/outline/updateStoryline"; -import route33 from "./routes/project/addProject"; -import route34 from "./routes/project/delProject"; -import route35 from "./routes/project/getProject"; -import route36 from "./routes/project/getProjectCount"; -import route37 from "./routes/project/getSingleProject"; -import route38 from "./routes/project/updateProject"; -import route39 from "./routes/prompt/getPrompts"; -import route40 from "./routes/prompt/updatePrompt"; -import route41 from "./routes/script/generateScriptApi"; -import route42 from "./routes/script/generateScriptSave"; -import route43 from "./routes/script/geScriptApi"; -import route44 from "./routes/setting/addModel"; -import route45 from "./routes/setting/configurationModel"; -import route46 from "./routes/setting/delModel"; -import route47 from "./routes/setting/getAiModelMap"; -import route48 from "./routes/setting/getLog"; -import route49 from "./routes/setting/getSetting"; -import route50 from "./routes/setting/getVideoModelList"; -import route51 from "./routes/setting/updateModel"; -import route52 from "./routes/setting/updeteModel"; -import route53 from "./routes/storyboard/batchSuperScoreImage"; -import route54 from "./routes/storyboard/chatStoryboard"; -import route55 from "./routes/storyboard/generateShotImage"; -import route56 from "./routes/storyboard/generateStoryboardApi"; -import route57 from "./routes/storyboard/generateVideoPrompt"; -import route58 from "./routes/storyboard/getStoryboard"; -import route59 from "./routes/storyboard/keepStoryboard"; -import route60 from "./routes/storyboard/saveStoryboard"; -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 route3 from "./routes/assets/delAssetsImage"; +import route4 from "./routes/assets/generateAssets"; +import route5 from "./routes/assets/getAssets"; +import route6 from "./routes/assets/getImage"; +import route7 from "./routes/assets/getStoryboard"; +import route8 from "./routes/assets/polishPrompt"; +import route9 from "./routes/assets/saveAssets"; +import route10 from "./routes/assets/updateAssets"; +import route11 from "./routes/index/index"; +import route12 from "./routes/novel/addNovel"; +import route13 from "./routes/novel/delNovel"; +import route14 from "./routes/novel/getNovel"; +import route15 from "./routes/novel/updateNovel"; +import route16 from "./routes/other/clearDatabase"; +import route17 from "./routes/other/deleteAllData"; +import route18 from "./routes/other/getCaptcha"; +import route19 from "./routes/other/login"; +import route20 from "./routes/other/testAI"; +import route21 from "./routes/other/testImage"; +import route22 from "./routes/other/testVideo"; +import route23 from "./routes/outline/addOutline"; +import route24 from "./routes/outline/agentsOutline"; +import route25 from "./routes/outline/delOutline"; +import route26 from "./routes/outline/getHistory"; +import route27 from "./routes/outline/getOutline"; +import route28 from "./routes/outline/getPartScript"; +import route29 from "./routes/outline/getStoryline"; +import route30 from "./routes/outline/setHistory"; +import route31 from "./routes/outline/updateOutline"; +import route32 from "./routes/outline/updateScript"; +import route33 from "./routes/outline/updateStoryline"; +import route34 from "./routes/project/addProject"; +import route35 from "./routes/project/delProject"; +import route36 from "./routes/project/getProject"; +import route37 from "./routes/project/getProjectCount"; +import route38 from "./routes/project/getSingleProject"; +import route39 from "./routes/project/updateProject"; +import route40 from "./routes/prompt/getPrompts"; +import route41 from "./routes/prompt/updatePrompt"; +import route42 from "./routes/script/generateScriptApi"; +import route43 from "./routes/script/generateScriptSave"; +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/generateShotImage"; +import route57 from "./routes/storyboard/generateStoryboardApi"; +import route58 from "./routes/storyboard/generateVideoPrompt"; +import route59 from "./routes/storyboard/getStoryboard"; +import route60 from "./routes/storyboard/keepStoryboard"; +import route61 from "./routes/storyboard/saveStoryboard"; +import route62 from "./routes/storyboard/uploadImage"; +import route63 from "./routes/task/getTaskApi"; +import route64 from "./routes/task/taskDetails"; +import route65 from "./routes/user/getUser"; +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); app.use("/assets/delAssets", route2); - app.use("/assets/generateAssets", route3); - app.use("/assets/getAssets", route4); - app.use("/assets/getImage", route5); - app.use("/assets/getStoryboard", route6); - app.use("/assets/polishPrompt", route7); - app.use("/assets/saveAssets", route8); - app.use("/assets/updateAssets", route9); - app.use("/index", route10); - app.use("/novel/addNovel", route11); - app.use("/novel/delNovel", route12); - app.use("/novel/getNovel", route13); - app.use("/novel/updateNovel", route14); - app.use("/other/clearDatabase", route15); - app.use("/other/deleteAllData", route16); - app.use("/other/getCaptcha", route17); - app.use("/other/login", route18); - app.use("/other/testAI", route19); - app.use("/other/testImage", route20); - app.use("/other/testVideo", route21); - app.use("/outline/addOutline", route22); - app.use("/outline/agentsOutline", route23); - app.use("/outline/delOutline", route24); - app.use("/outline/getHistory", route25); - app.use("/outline/getOutline", route26); - app.use("/outline/getPartScript", route27); - app.use("/outline/getStoryline", route28); - app.use("/outline/setHistory", route29); - app.use("/outline/updateOutline", route30); - app.use("/outline/updateScript", route31); - app.use("/outline/updateStoryline", route32); - app.use("/project/addProject", route33); - app.use("/project/delProject", route34); - app.use("/project/getProject", route35); - app.use("/project/getProjectCount", route36); - app.use("/project/getSingleProject", route37); - app.use("/project/updateProject", route38); - app.use("/prompt/getPrompts", route39); - app.use("/prompt/updatePrompt", route40); - app.use("/script/generateScriptApi", route41); - app.use("/script/generateScriptSave", route42); - app.use("/script/geScriptApi", route43); - app.use("/setting/addModel", route44); - app.use("/setting/configurationModel", route45); - app.use("/setting/delModel", route46); - app.use("/setting/getAiModelMap", route47); - app.use("/setting/getLog", route48); - app.use("/setting/getSetting", route49); - app.use("/setting/getVideoModelList", route50); - app.use("/setting/updateModel", route51); - app.use("/setting/updeteModel", route52); - app.use("/storyboard/batchSuperScoreImage", route53); - app.use("/storyboard/chatStoryboard", route54); - app.use("/storyboard/generateShotImage", route55); - app.use("/storyboard/generateStoryboardApi", route56); - app.use("/storyboard/generateVideoPrompt", route57); - app.use("/storyboard/getStoryboard", route58); - app.use("/storyboard/keepStoryboard", route59); - app.use("/storyboard/saveStoryboard", route60); - app.use("/storyboard/uploadImage", route61); - 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("/assets/delAssetsImage", route3); + app.use("/assets/generateAssets", route4); + app.use("/assets/getAssets", route5); + app.use("/assets/getImage", route6); + app.use("/assets/getStoryboard", route7); + app.use("/assets/polishPrompt", route8); + app.use("/assets/saveAssets", route9); + app.use("/assets/updateAssets", route10); + app.use("/index", route11); + app.use("/novel/addNovel", route12); + app.use("/novel/delNovel", route13); + app.use("/novel/getNovel", route14); + app.use("/novel/updateNovel", route15); + app.use("/other/clearDatabase", route16); + app.use("/other/deleteAllData", route17); + app.use("/other/getCaptcha", route18); + app.use("/other/login", route19); + app.use("/other/testAI", route20); + app.use("/other/testImage", route21); + app.use("/other/testVideo", route22); + app.use("/outline/addOutline", route23); + app.use("/outline/agentsOutline", route24); + app.use("/outline/delOutline", route25); + app.use("/outline/getHistory", route26); + app.use("/outline/getOutline", route27); + app.use("/outline/getPartScript", route28); + app.use("/outline/getStoryline", route29); + app.use("/outline/setHistory", route30); + app.use("/outline/updateOutline", route31); + app.use("/outline/updateScript", route32); + app.use("/outline/updateStoryline", route33); + app.use("/project/addProject", route34); + app.use("/project/delProject", route35); + app.use("/project/getProject", route36); + app.use("/project/getProjectCount", route37); + app.use("/project/getSingleProject", route38); + app.use("/project/updateProject", route39); + app.use("/prompt/getPrompts", route40); + app.use("/prompt/updatePrompt", route41); + app.use("/script/generateScriptApi", route42); + app.use("/script/generateScriptSave", route43); + app.use("/script/geScriptApi", route44); + 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/generateShotImage", route56); + app.use("/storyboard/generateStoryboardApi", route57); + app.use("/storyboard/generateVideoPrompt", route58); + app.use("/storyboard/getStoryboard", route59); + app.use("/storyboard/keepStoryboard", route60); + app.use("/storyboard/saveStoryboard", route61); + app.use("/storyboard/uploadImage", route62); + app.use("/task/getTaskApi", route63); + app.use("/task/taskDetails", route64); + app.use("/user/getUser", 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/delAssetsImage.ts b/src/routes/assets/delAssetsImage.ts new file mode 100644 index 0000000..c186af0 --- /dev/null +++ b/src/routes/assets/delAssetsImage.ts @@ -0,0 +1,27 @@ +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({ + imageId: z.number().optional(), + assetsId: z.number().optional(), + }), + async (req, res) => { + const { imageId, assetsId } = req.body; + if (assetsId) { + await u.db("t_assets").where("id", assetsId).update({ + filePath: null, + }); + } + if (imageId) { + await u.db("t_image").where("id", imageId).delete(); + } + res.status(200).send(success({ message: "删除资产图片成功" })); + }, +); diff --git a/src/types/database.d.ts b/src/types/database.d.ts index dffd599..78e03b1 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,4 @@ -// @db-hash 945540586ca016b1b9a42042fc5ccbf3 +// @db-hash 8ef9e37c14c453b2d95832b971baca8a //该文件由脚本自动生成,请勿手动修改 export interface t_aiModelMap { @@ -39,6 +39,7 @@ export interface t_config { 'manufacturer'?: string | null; 'model'?: string | null; 'modelType'?: string | null; + 'name'?: string | null; 'type'?: string | null; 'userId'?: number | null; } @@ -138,12 +139,10 @@ export interface t_video { 'time'?: number | null; } export interface t_videoConfig { - 'aiConfigId'?: number | null; 'audioEnabled'?: number | null; 'createTime'?: number | null; 'duration'?: number | null; 'endFrame'?: string | null; - 'errorReason'?: string | null; 'id'?: number; 'images'?: string | null; 'manufacturer'?: string | null; From 3dba47150026eb83937dcd2cfc92c3e13485d7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Fri, 27 Feb 2026 10:14:11 +0800 Subject: [PATCH 05/17] no message --- src/routes/assets/generateAssets.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/routes/assets/generateAssets.ts b/src/routes/assets/generateAssets.ts index 7889f1a..e510a2c 100644 --- a/src/routes/assets/generateAssets.ts +++ b/src/routes/assets/generateAssets.ts @@ -163,18 +163,22 @@ export default router.post( } await u.oss.writeFile(imagePath!, buffer); + const imageData = await u.db("t_image").where("id", imageId).select("*").first(); + if (imageData) { + await u.db("t_image").where("id", imageId).update({ + state: "生成成功", + filePath: imagePath, + type: insertType, + }); - await u.db("t_image").where("id", imageId).update({ - state: "生成成功", - filePath: imagePath, - type: insertType, - }); + const path = await u.oss.getFileUrl(imagePath!); - const path = await u.oss.getFileUrl(imagePath!); + // const state = await u.db("t_assets").where("id", id).select("state").first(); - // const state = await u.db("t_assets").where("id", id).select("state").first(); - - res.status(200).send(success({ path, assetsId: id })); + return res.status(200).send(success({ path, assetsId: id })); + } else { + return res.status(500).send("资产已被删除"); + } }, ); async function imageAddText(name: string, imageBuffer: Buffer) { From 2c0af71f55197952db3a86a5d1fce27538b56177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Fri, 27 Feb 2026 11:35:26 +0800 Subject: [PATCH 06/17] no message --- src/router.ts | 96 +++++++++++++------------- src/routes/storyboard/delStoryboard.ts | 19 +++++ 2 files changed, 68 insertions(+), 47 deletions(-) create mode 100644 src/routes/storyboard/delStoryboard.ts diff --git a/src/router.ts b/src/router.ts index abef8f6..23eb89b 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash a5e432459af85c08bbc13a86444f292c +// @routes-hash bf59be4347a649430bc8b6067c3cf9ef import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -56,29 +56,30 @@ 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/generateShotImage"; -import route57 from "./routes/storyboard/generateStoryboardApi"; -import route58 from "./routes/storyboard/generateVideoPrompt"; -import route59 from "./routes/storyboard/getStoryboard"; -import route60 from "./routes/storyboard/keepStoryboard"; -import route61 from "./routes/storyboard/saveStoryboard"; -import route62 from "./routes/storyboard/uploadImage"; -import route63 from "./routes/task/getTaskApi"; -import route64 from "./routes/task/taskDetails"; -import route65 from "./routes/user/getUser"; -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"; +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"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -136,27 +137,28 @@ export default async (app: Express) => { app.use("/setting/updeteModel", route53); app.use("/storyboard/batchSuperScoreImage", route54); app.use("/storyboard/chatStoryboard", route55); - app.use("/storyboard/generateShotImage", route56); - app.use("/storyboard/generateStoryboardApi", route57); - app.use("/storyboard/generateVideoPrompt", route58); - app.use("/storyboard/getStoryboard", route59); - app.use("/storyboard/keepStoryboard", route60); - app.use("/storyboard/saveStoryboard", route61); - app.use("/storyboard/uploadImage", route62); - app.use("/task/getTaskApi", route63); - app.use("/task/taskDetails", route64); - app.use("/user/getUser", 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); + 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); } diff --git a/src/routes/storyboard/delStoryboard.ts b/src/routes/storyboard/delStoryboard.ts new file mode 100644 index 0000000..4f467c3 --- /dev/null +++ b/src/routes/storyboard/delStoryboard.ts @@ -0,0 +1,19 @@ +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({ + id: z.number(), + }), + async (req, res) => { + const { id } = req.body; + console.log("%c Line:15 🍕 id", "background:#f5ce50", id); + await u.db("t_assets").where("id", id).delete(); + res.status(200).send(success("分镜删除成功")); + }, +); From 869bb5e998cc560999571bc3dc52c0b8be16b698 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Fri, 27 Feb 2026 18:02:22 +0800 Subject: [PATCH 07/17] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=EF=BC=8C=E8=A7=A3=E9=99=A4=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=86=99=E6=AD=BB=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/initDB.ts | 551 ++++++++++++++++++++++ src/router.ts | 130 ++--- src/routes/assets/generateAssets.ts | 105 +++-- src/routes/other/testVideo.ts | 1 + src/routes/setting/getAiModelList.ts | 33 ++ src/routes/setting/getVideoModelDetail.ts | 31 ++ src/routes/video/generateVideo.ts | 4 +- src/types/database.d.ts | 65 ++- src/utils/ai/image/index.ts | 12 +- src/utils/ai/image/modelList.ts | 7 - src/utils/ai/image/owned/modelScope.ts | 133 ++++++ src/utils/ai/text/index.ts | 11 +- src/utils/ai/text/modelList.ts | 61 ++- src/utils/ai/utils.ts | 4 +- src/utils/ai/video/index.ts | 4 +- src/utils/ai/video/owned/gemini.ts | 26 +- src/utils/ai/video/owned/kling.ts | 10 +- src/utils/ai/video/owned/runninghub.ts | 11 +- src/utils/ai/video/owned/vidu.ts | 46 +- src/utils/ai/video/owned/volcengine.ts | 8 +- src/utils/ai/video/owned/wan.ts | 18 +- src/utils/ai/video/type.ts | 1 + 22 files changed, 1064 insertions(+), 208 deletions(-) create mode 100644 src/routes/setting/getAiModelList.ts create mode 100644 src/routes/setting/getVideoModelDetail.ts create mode 100644 src/utils/ai/image/owned/modelScope.ts diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index ec89e5e..62c0713 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -554,6 +554,557 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => ]); }, }, + + { + name: "t_textModel", + builder: (table) => { + table.integer("id").notNullable(); + table.text("manufacturer"); + table.text("model"); + table.text("responseFormat"); + table.integer("image"); + table.integer("think"); + table.integer("tool"); + table.primary(["id"]); + }, + initData: async (knex) => { + await knex("t_textModel").insert([ + { manufacturer: "deepSeek", model: "deepseek-chat", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "deepSeek", model: "deepseek-reasoner", responseFormat: "schema", image: 0, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-2-0-pro-260215", responseFormat: "object", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-2-0-lite-260215", responseFormat: "object", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-2-0-mini-260215", responseFormat: "object", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-1-8-251228", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-1-6-251015", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-1-6-lite-251015", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "volcengine", model: "doubao-seed-1-6-flash-250828", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.7", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.7-flashx", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.6", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.5-air", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.5-airx", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4-long", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4-flashx-250414", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.7-flash", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.5-flash", responseFormat: "object", image: 0, think: 1, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4-flash-250414", responseFormat: "object", image: 0, think: 0, tool: 1 }, + { manufacturer: "zhipu", model: "glm-4.6v", responseFormat: "object", image: 1, think: 1, tool: 1 }, + { manufacturer: "qwen", model: "qwen-vl-max", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "qwen", model: "qwen-plus-latest", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "qwen", model: "qwen-max", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "qwen", model: "qwen2.5-72b-instruct", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "qwen", model: "qwen2.5-14b-instruct-1m", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "qwen", model: "qwen2.5-vl-72b-instruct", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "openai", model: "gpt-4o", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "openai", model: "gpt-4o-mini", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "openai", model: "gpt-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "openai", model: "gpt-5.1", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "openai", model: "gpt-5.2", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "gemini", model: "gemini-2.5-pro", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "gemini", model: "gemini-2.5-flash", responseFormat: "schema", image: 1, think: 1, tool: 1 }, + { manufacturer: "gemini", model: "gemini-2.0-flash", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "gemini", model: "gemini-2.0-flash-lite", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "gemini", model: "gemini-1.5-pro", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "gemini", model: "gemini-1.5-flash", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-opus-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-haiku-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-sonnet-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-opus-4-1", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-opus-4-0", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-sonnet-4-0", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-3-7-sonnet-latest", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "anthropic", model: "claude-3-5-haiku-latest", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "xai", model: "grok-3", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "xai", model: "grok-4", responseFormat: "schema", image: 0, think: 0, tool: 1 }, + { manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "other", model: "gpt-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 }, + { manufacturer: "modelScope", model: "deepseek-ai/DeepSeek-V3.2", responseFormat: "object", image: 0, think: 0, tool: 1 }, + ]); + }, + }, + { + name: "t_imageModel", + builder: (table) => { + table.integer("id").notNullable(); + table.text("manufacturer"); + table.text("model"); + table.integer("grid"); + table.text("type"); + table.primary(["id"]); + }, + 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" }, + ]); + }, + }, + { + name: "t_videoModel", + builder: (table) => { + table.integer("id").notNullable(); + table.text("manufacturer"); + table.text("model"); + table.text("durationResolutionMap"); + table.text("aspectRatio"); + table.integer("audio"); + table.text("type"); + table.primary(["id"]); + }, + initData: async (knex) => { + await knex("t_videoModel").insert([ + { + id: 1, + manufacturer: "volcengine", + model: "doubao-seedance-1-5-pro-251215", + durationResolutionMap: JSON.stringify([{ duration: [4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]), + audio: 1, + type: JSON.stringify(["text", "endFrameOptional"]), + }, + { + id: 2, + manufacturer: "volcengine", + model: "doubao-seedance-1-0-pro-250528", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]), + audio: 0, + type: JSON.stringify(["text", "endFrameOptional"]), + }, + { + id: 3, + manufacturer: "volcengine", + model: "doubao-seedance-1-0-pro-fast-251015", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]), + audio: 0, + type: JSON.stringify(["text", "singleImage"]), + }, + { + id: 4, + manufacturer: "volcengine", + model: "doubao-seedance-1-0-lite-i2v-250428", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["endFrameOptional", "reference"]), + }, + { + id: 5, + manufacturer: "volcengine", + model: "doubao-seedance-1-0-lite-t2v-250428", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 6, + manufacturer: "kling", + model: "kling-v1(STD)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["720p"] }]), + aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 7, + manufacturer: "kling", + model: "kling-v1(STD)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["720p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 8, + manufacturer: "kling", + model: "kling-v1(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 9, + manufacturer: "kling", + model: "kling-v1(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 10, + manufacturer: "kling", + model: "kling-v1-6(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 11, + manufacturer: "kling", + model: "kling-v1-6(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 12, + manufacturer: "kling", + model: "kling-v2-5-turbo(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 13, + manufacturer: "kling", + model: "kling-v2-5-turbo(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 14, + manufacturer: "kling", + model: "kling-v2-6(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 15, + manufacturer: "kling", + model: "kling-v2-6(PRO)", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 16, + manufacturer: "vidu", + model: "viduq3-pro", + durationResolutionMap: JSON.stringify([ + { duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]), + audio: 1, + type: JSON.stringify(["text"]), + }, + { + id: 17, + manufacturer: "vidu", + model: "viduq3-pro", + durationResolutionMap: JSON.stringify([ + { duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify([]), + audio: 1, + type: JSON.stringify(["singleImage"]), + }, + { + id: 18, + manufacturer: "vidu", + model: "viduq2-pro-fast", + durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "startEndRequired"]), + }, + { + id: 19, + manufacturer: "vidu", + model: "viduq2-pro", + durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 20, + manufacturer: "vidu", + model: "viduq2-pro", + durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), + }, + { + id: 21, + manufacturer: "vidu", + model: "viduq2-turbo", + durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 22, + manufacturer: "vidu", + model: "viduq2-turbo", + durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), + }, + { + id: 23, + manufacturer: "vidu", + model: "viduq1", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 24, + manufacturer: "vidu", + model: "viduq1", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), + }, + { + id: 25, + manufacturer: "vidu", + model: "viduq1-classic", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "startEndRequired"]), + }, + { + id: 26, + manufacturer: "vidu", + model: "vidu2.0", + durationResolutionMap: JSON.stringify([ + { duration: [4], resolution: ["360p", "720p", "1080p"] }, + { duration: [8], resolution: ["720p"] }, + ]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), + }, + { + id: 27, + manufacturer: "wan", + model: "wan2.6-t2v", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1", "4:3", "3:4"]), + audio: 1, + type: JSON.stringify(["text"]), + }, + { + id: 28, + manufacturer: "wan", + model: "wan2.5-t2v-preview", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1", "4:3", "3:4"]), + audio: 1, + type: JSON.stringify(["text"]), + }, + { + id: 29, + manufacturer: "wan", + model: "wan2.2-t2v-plus", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1", "4:3", "3:4"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 30, + manufacturer: "wan", + model: "wanx2.1-t2v-turbo", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1", "4:3", "3:4"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 31, + manufacturer: "wan", + model: "wanx2.1-t2v-plus", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16", "1:1", "4:3", "3:4"]), + audio: 0, + type: JSON.stringify(["text"]), + }, + { + id: 32, + manufacturer: "wan", + model: "wan2.6-i2v-flash", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 1, + type: JSON.stringify(["singleImage"]), + }, + { + id: 33, + manufacturer: "wan", + model: "wan2.6-i2v", + durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 1, + type: JSON.stringify(["singleImage"]), + }, + { + id: 34, + manufacturer: "wan", + model: "wan2.5-i2v-preview", + durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 1, + type: JSON.stringify(["singleImage"]), + }, + { + id: 35, + manufacturer: "wan", + model: "wan2.2-i2v-flash", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage"]), + }, + { + id: 36, + manufacturer: "wan", + model: "wan2.2-i2v-plus", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage"]), + }, + { + id: 37, + manufacturer: "wan", + model: "wanx2.1-i2v-plus", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage"]), + }, + { + id: 38, + manufacturer: "wan", + model: "wanx2.1-i2v-turbo", + durationResolutionMap: JSON.stringify([{ duration: [3, 4, 5], resolution: ["480p", "720p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["singleImage"]), + }, + { + id: 39, + manufacturer: "wan", + model: "wan2.2-kf2v-flash", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 40, + manufacturer: "wan", + model: "wanx2.1-kf2v-plus", + durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), + aspectRatio: JSON.stringify([]), + audio: 0, + type: JSON.stringify(["startEndRequired"]), + }, + { + id: 41, + manufacturer: "gemini", + model: "veo-3.1-generate-preview", + durationResolutionMap: JSON.stringify([ + { duration: [4, 6], resolution: ["720p"] }, + { duration: [8], resolution: ["720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 1, + type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]), + }, + { + id: 42, + manufacturer: "gemini", + model: "veo-3.1-fast-generate-preview", + durationResolutionMap: JSON.stringify([ + { duration: [4, 6], resolution: ["720p"] }, + { duration: [8], resolution: ["720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 1, + type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]), + }, + { + id: 43, + manufacturer: "gemini", + model: "veo-3.0-generate-preview", + durationResolutionMap: JSON.stringify([ + { duration: [4, 6], resolution: ["720p"] }, + { duration: [8], resolution: ["720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 1, + type: JSON.stringify(["text", "singleImage"]), + }, + { + id: 44, + manufacturer: "gemini", + model: "veo-3.0-fast-generate-preview", + durationResolutionMap: JSON.stringify([ + { duration: [4, 6], resolution: ["720p"] }, + { duration: [8], resolution: ["720p", "1080p"] }, + ]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 1, + type: JSON.stringify(["text", "singleImage"]), + }, + { + id: 45, + manufacturer: "gemini", + model: "veo-2.0-generate-001", + durationResolutionMap: JSON.stringify([{ duration: [5, 6, 7, 8], resolution: ["720p"] }]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["text", "singleImage"]), + }, + { + id: 46, + manufacturer: "runninghub", + model: "sora-2", + durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["singleImage", "text"]), + }, + { + id: 47, + manufacturer: "runninghub", + model: "sora-2-pro", + durationResolutionMap: JSON.stringify([{ duration: [15, 25], resolution: [] }]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["singleImage", "text"]), + }, + ]); + }, + }, ]; for (const t of tables) { diff --git a/src/router.ts b/src/router.ts index abef8f6..9e089fd 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash a5e432459af85c08bbc13a86444f292c +// @routes-hash 88e9c15b913a8fd111d3adf162583c91 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -48,37 +48,39 @@ 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/generateShotImage"; -import route57 from "./routes/storyboard/generateStoryboardApi"; -import route58 from "./routes/storyboard/generateVideoPrompt"; -import route59 from "./routes/storyboard/getStoryboard"; -import route60 from "./routes/storyboard/keepStoryboard"; -import route61 from "./routes/storyboard/saveStoryboard"; -import route62 from "./routes/storyboard/uploadImage"; -import route63 from "./routes/task/getTaskApi"; -import route64 from "./routes/task/taskDetails"; -import route65 from "./routes/user/getUser"; -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"; +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/generateShotImage"; +import route59 from "./routes/storyboard/generateStoryboardApi"; +import route60 from "./routes/storyboard/generateVideoPrompt"; +import route61 from "./routes/storyboard/getStoryboard"; +import route62 from "./routes/storyboard/keepStoryboard"; +import route63 from "./routes/storyboard/saveStoryboard"; +import route64 from "./routes/storyboard/uploadImage"; +import route65 from "./routes/task/getTaskApi"; +import route66 from "./routes/task/taskDetails"; +import route67 from "./routes/user/getUser"; +import route68 from "./routes/video/addVideo"; +import route69 from "./routes/video/addVideoConfig"; +import route70 from "./routes/video/deleteVideoConfig"; +import route71 from "./routes/video/generatePrompt"; +import route72 from "./routes/video/generateVideo"; +import route73 from "./routes/video/getManufacturer"; +import route74 from "./routes/video/getVideo"; +import route75 from "./routes/video/getVideoConfigs"; +import route76 from "./routes/video/getVideoModel"; +import route77 from "./routes/video/getVideoStoryboards"; +import route78 from "./routes/video/reviseVideoStoryboards"; +import route79 from "./routes/video/saveVideo"; +import route80 from "./routes/video/upDateVideoConfig"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -128,35 +130,37 @@ 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/generateShotImage", route56); - app.use("/storyboard/generateStoryboardApi", route57); - app.use("/storyboard/generateVideoPrompt", route58); - app.use("/storyboard/getStoryboard", route59); - app.use("/storyboard/keepStoryboard", route60); - app.use("/storyboard/saveStoryboard", route61); - app.use("/storyboard/uploadImage", route62); - app.use("/task/getTaskApi", route63); - app.use("/task/taskDetails", route64); - app.use("/user/getUser", 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); + 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/generateShotImage", route58); + app.use("/storyboard/generateStoryboardApi", route59); + app.use("/storyboard/generateVideoPrompt", route60); + app.use("/storyboard/getStoryboard", route61); + app.use("/storyboard/keepStoryboard", route62); + app.use("/storyboard/saveStoryboard", route63); + app.use("/storyboard/uploadImage", route64); + app.use("/task/getTaskApi", route65); + app.use("/task/taskDetails", route66); + app.use("/user/getUser", route67); + app.use("/video/addVideo", route68); + app.use("/video/addVideoConfig", route69); + app.use("/video/deleteVideoConfig", route70); + app.use("/video/generatePrompt", route71); + app.use("/video/generateVideo", route72); + app.use("/video/getManufacturer", route73); + app.use("/video/getVideo", route74); + app.use("/video/getVideoConfigs", route75); + app.use("/video/getVideoModel", route76); + app.use("/video/getVideoStoryboards", route77); + app.use("/video/reviseVideoStoryboards", route78); + app.use("/video/saveVideo", route79); + app.use("/video/upDateVideoConfig", route80); } diff --git a/src/routes/assets/generateAssets.ts b/src/routes/assets/generateAssets.ts index e510a2c..3cdc1c3 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 { error, success } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; import sharp from "sharp"; const router = express.Router(); @@ -124,60 +124,67 @@ export default router.post( assetsId: id, }); const apiConfig = await u.getPromptAi("assetsImage"); + try { + const contentStr = await u.ai.image( + { + systemPrompt, + prompt: userPrompt, + imageBase64: base64 ? [base64] : [], + size: "2K", + aspectRatio: "16:9", + }, + apiConfig, + ); - const contentStr = await u.ai.image( - { - systemPrompt, - prompt: userPrompt, - imageBase64: base64 ? [base64] : [], - size: "2K", - aspectRatio: "16:9", - }, - apiConfig, - ); + let insertType; + const match = contentStr.match(/base64,([A-Za-z0-9+/=]+)/); + let buffer = Buffer.from(match && match.length >= 2 ? match[1]! : contentStr!, "base64"); - let insertType; - const match = contentStr.match(/base64,([A-Za-z0-9+/=]+)/); - let buffer = Buffer.from(match && match.length >= 2 ? match[1]! : contentStr!, "base64"); + if (type != "storyboard") { + //添加文本 + // buffer = await imageAddText(name, buffer); + } + let imagePath; + if (type == "role") { + insertType = "角色"; + imagePath = `/${projectId}/role/${uuidv4()}.jpg`; + } + if (type == "scene") { + insertType = "场景"; + imagePath = `/${projectId}/scene/${uuidv4()}.jpg`; + } + if (type == "props") { + insertType = "道具"; + imagePath = `/${projectId}/props/${uuidv4()}.jpg`; + } + if (type == "storyboard") { + insertType = "分镜"; + imagePath = `/${projectId}/storyboard/${uuidv4()}.jpg`; + } - if (type != "storyboard") { - //添加文本 - // buffer = await imageAddText(name, buffer); - } - let imagePath; - if (type == "role") { - insertType = "角色"; - imagePath = `/${projectId}/role/${uuidv4()}.jpg`; - } - if (type == "scene") { - insertType = "场景"; - imagePath = `/${projectId}/scene/${uuidv4()}.jpg`; - } - if (type == "props") { - insertType = "道具"; - imagePath = `/${projectId}/props/${uuidv4()}.jpg`; - } - if (type == "storyboard") { - insertType = "分镜"; - imagePath = `/${projectId}/storyboard/${uuidv4()}.jpg`; - } + await u.oss.writeFile(imagePath!, buffer); + const imageData = await u.db("t_image").where("id", imageId).select("*").first(); + if (imageData) { + await u.db("t_image").where("id", imageId).update({ + state: "生成成功", + filePath: imagePath, + type: insertType, + }); - await u.oss.writeFile(imagePath!, buffer); - const imageData = await u.db("t_image").where("id", imageId).select("*").first(); - if (imageData) { + const path = await u.oss.getFileUrl(imagePath!); + + // const state = await u.db("t_assets").where("id", id).select("state").first(); + + return res.status(200).send(success({ path, assetsId: id })); + } else { + return res.status(500).send("资产已被删除"); + } + } catch (e) { await u.db("t_image").where("id", imageId).update({ - state: "生成成功", - filePath: imagePath, - type: insertType, + state: "生成失败", }); - - const path = await u.oss.getFileUrl(imagePath!); - - // const state = await u.db("t_assets").where("id", id).select("state").first(); - - return res.status(200).send(success({ path, assetsId: id })); - } else { - return res.status(500).send("资产已被删除"); + const msg = u.error(e).message || "图片生成失败"; + return res.status(400).send(error(msg)); } }, ); diff --git a/src/routes/other/testVideo.ts b/src/routes/other/testVideo.ts index 745ee97..b51dbd3 100644 --- a/src/routes/other/testVideo.ts +++ b/src/routes/other/testVideo.ts @@ -27,6 +27,7 @@ export default router.post( resolution: "720p", aspectRatio: "16:9", audio: false, + mode: "single", }, { model: modelName, diff --git a/src/routes/setting/getAiModelList.ts b/src/routes/setting/getAiModelList.ts new file mode 100644 index 0000000..313d9dd --- /dev/null +++ b/src/routes/setting/getAiModelList.ts @@ -0,0 +1,33 @@ +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({ + type: z.enum(["text", "image", "video"]), + }), + async (req, res) => { + const { type } = req.body; + const sqlTableMap = { + text: "t_textModel", + image: "t_imageModel", + video: "t_videoModel", + }; + const modelLists = await u + .db(sqlTableMap[type as "image" | "text" | "video"]) + .whereNot("manufacturer", "other") + .select("id", "manufacturer", "model"); + const result: Record = {}; + for (const row of modelLists) { + if (!result[row.manufacturer]) { + result[row.manufacturer] = []; + } + result[row.manufacturer].push({ label: row.model, value: row.model }); + } + res.status(200).send(success(result)); + }, +); diff --git a/src/routes/setting/getVideoModelDetail.ts b/src/routes/setting/getVideoModelDetail.ts new file mode 100644 index 0000000..3905fba --- /dev/null +++ b/src/routes/setting/getVideoModelDetail.ts @@ -0,0 +1,31 @@ +import express from "express"; +import u from "@/utils"; +import { success } from "@/lib/responseFormat"; +const router = express.Router(); + +export default router.post("/", async (req, res) => { + const videoData = await u.db("t_videoModel").select("*"); + const allData = videoData.map((i) => { + const durationResolutionMap = JSON.parse(i.durationResolutionMap ?? "[]"); + const aspectRatio = JSON.parse(i.aspectRatio ?? "[]"); + const type = JSON.parse(i.type ?? "[]"); + return { + ...i, + durationResolutionMap, + aspectRatio, + type, + audio: i.audio === 1, + }; + }); + + const otherConfig = { + manufacturer: "other", + model: "", + durationResolutionMap: [{ duration: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["480p", "720p", "1080p"] }], + aspectRatio: ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"], + type: ["text", "endFrameOptional", "singleImage", "multiImage"], + audio: true, + }; + const returnData = [otherConfig, ...allData]; + res.status(200).send(success(returnData)); +}); diff --git a/src/routes/video/generateVideo.ts b/src/routes/video/generateVideo.ts index e0b1b5b..1564441 100644 --- a/src/routes/video/generateVideo.ts +++ b/src/routes/video/generateVideo.ts @@ -119,7 +119,7 @@ export default router.post( res.status(200).send(success({ id: videoId, configId: configId || null })); // 异步生成视频 - generateVideoAsync(videoId, projectId, fileUrl, savePath, prompt, duration, resolution, audioEnabled, aiConfigData); + generateVideoAsync(videoId, projectId, fileUrl, savePath, prompt, duration, resolution, audioEnabled, aiConfigData, mode); }, ); @@ -134,6 +134,7 @@ async function generateVideoAsync( resolution: string, audioEnabled: boolean, aiConfigData: t_config, + mode: string, ) { try { const projectData = await u.db("t_project").where("id", projectId).select("artStyle", "videoRatio").first(); @@ -175,6 +176,7 @@ ${prompt} aspectRatio: projectData?.videoRatio as any, resolution: resolution as any, audio: audioEnabled, + mode: mode as any, }, { baseURL: aiConfigData?.baseUrl!, diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 78e03b1..25cd1ff 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,6 +1,20 @@ -// @db-hash 8ef9e37c14c453b2d95832b971baca8a +// @db-hash ab4e3e93bfba304164daa7d28c804eaf //该文件由脚本自动生成,请勿手动修改 +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; @@ -39,7 +53,6 @@ export interface t_config { 'manufacturer'?: string | null; 'model'?: string | null; 'modelType'?: string | null; - 'name'?: string | null; 'type'?: string | null; 'userId'?: number | null; } @@ -53,6 +66,20 @@ 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; + 'manufacturer'?: string | null; + 'model'?: string | null; + 'type'?: string | null; +} export interface t_novel { 'chapter'?: string | null; 'chapterData'?: string | null; @@ -118,6 +145,24 @@ 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; + 'manufacturer'?: string | null; + 'model'?: string | null; + 'responseFormat'?: string | null; + 'think'?: number | null; + 'tool'?: number | null; +} export interface t_user { 'id'?: number; 'name'?: string | null; @@ -139,6 +184,7 @@ export interface t_video { 'time'?: number | null; } export interface t_videoConfig { + 'aiConfigId'?: number | null; 'audioEnabled'?: number | null; 'createTime'?: number | null; 'duration'?: number | null; @@ -155,13 +201,25 @@ export interface t_videoConfig { 'startFrame'?: string | null; 'updateTime'?: number | null; } +export interface t_videoModel { + 'aspectRatio'?: string | null; + 'audio'?: number | null; + 'durationResolutionMap'?: string | null; + 'id'?: number; + 'manufacturer'?: string | null; + 'model'?: string | null; + 'type'?: string | null; +} 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; "t_project": t_project; @@ -170,7 +228,10 @@ 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; "t_videoConfig": t_videoConfig; + "t_videoModel": t_videoModel; } diff --git a/src/utils/ai/image/index.ts b/src/utils/ai/image/index.ts index 3054ebd..3826c08 100644 --- a/src/utils/ai/image/index.ts +++ b/src/utils/ai/image/index.ts @@ -10,6 +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" }); @@ -25,20 +26,20 @@ const modelInstance = { vidu: vidu, runninghub: runninghub, // apimart: apimart, + modelScope, other, } as const; export default async (input: ImageConfig, config: AIConfig) => { - console.log("%c Line:32 🥪 config", "background:#33a5ff", config); const { model, apiKey, baseURL, manufacturer } = { ...config }; if (!config || !config?.model || !config?.apiKey || !config?.manufacturer) throw new Error("请检查模型配置是否正确"); 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") { + // 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..a324586 100644 --- a/src/utils/ai/image/modelList.ts +++ b/src/utils/ai/image/modelList.ts @@ -59,13 +59,6 @@ const modelList: Owned[] = [ grid: true, type: "ti2i", }, - //ApiMart - { - manufacturer: "apimart", - model: "nanobanana", - grid: true, - type: "ti2i", - }, ]; export default modelList; 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/text/index.ts b/src/utils/ai/text/index.ts index bfc45d7..a2dfdf5 100644 --- a/src/utils/ai/text/index.ts +++ b/src/utils/ai/text/index.ts @@ -3,7 +3,7 @@ import { generateText, streamText, Output, stepCountIs, ModelMessage, LanguageMo import { wrapLanguageModel } from "ai"; import { devToolsMiddleware } from "@ai-sdk/devtools"; import { parse } from "best-effort-json-parser"; -import modelList from "./modelList"; +import { getModelList } from "./modelList"; import { z } from "zod"; import { OpenAIProvider } from "@ai-sdk/openai"; interface AIInput | undefined = undefined> { @@ -26,12 +26,15 @@ 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; + const modelList = await getModelList(); if (manufacturer == "other") { owned = modelList.find((m) => m.manufacturer === manufacturer); } else { owned = modelList.find((m) => m.model === model); + if (!owned) owned = modelList.find((m) => m.manufacturer === manufacturer); } - if (!owned) throw new Error("不支持的模型或厂商"); + if (!owned) throw new Error("不支持的厂商"); + console.log("%c Line:36 🥛 owned", "background:#6ec1c2", owned); const modelInstance = owned.instance({ apiKey, baseURL: baseURL!, name: "xixixi" }); @@ -52,7 +55,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 = ["volcengine", "other", "openai"]; const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!); return { config: { @@ -76,6 +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; @@ -92,6 +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 421885a..ea1789c 100644 --- a/src/utils/ai/text/modelList.ts +++ b/src/utils/ai/text/modelList.ts @@ -1,11 +1,12 @@ -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 { 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"; +import db from "@/utils/db"; interface Owned { manufacturer: string; @@ -23,11 +24,24 @@ interface Owned { | typeof createAnthropic | typeof createOpenAICompatible; } +const instanceMap = { + deepSeek: createDeepSeek, + volcengine: createOpenAI, + openai: createOpenAI, + zhipu: createZhipu, + qwen: createQwen, + gemini: createGoogleGenerativeAI, + + anthropic: createAnthropic, + modelScope: (options: OpenAIProviderSettings) => createOpenAI({ ...options, headers: { ...options?.headers, "X-ModelScope-Async-Mode": "true" } }), + xai: createXai, + other: createOpenAI, +}; const modelList: Owned[] = [ // DeepSeek { - manufacturer: "deepseek", + manufacturer: "deepSeek", model: "deepseek-chat", responseFormat: "schema", image: false, @@ -36,7 +50,7 @@ const modelList: Owned[] = [ tool: true, }, { - manufacturer: "deepseek", + manufacturer: "deepSeek", model: "deepseek-reasoner", responseFormat: "schema", image: false, @@ -47,7 +61,16 @@ const modelList: Owned[] = [ // 豆包 { - manufacturer: "doubao", + manufacturer: "volcengine", + model: "doubao-seed-2-0-mini-260215", + responseFormat: "object", + image: true, + think: false, + instance: createOpenAI, + tool: true, + }, + { + manufacturer: "volcengine", model: "doubao-seed-1-8-251228", responseFormat: "schema", image: true, @@ -56,7 +79,7 @@ const modelList: Owned[] = [ tool: true, }, { - manufacturer: "doubao", + manufacturer: "volcengine", model: "doubao-seed-1-6-251015", responseFormat: "schema", image: true, @@ -65,7 +88,7 @@ const modelList: Owned[] = [ tool: true, }, { - manufacturer: "doubao", + manufacturer: "volcengine", model: "doubao-seed-1-6-lite-251015", responseFormat: "schema", image: true, @@ -74,7 +97,7 @@ const modelList: Owned[] = [ tool: true, }, { - manufacturer: "doubao", + manufacturer: "volcengine", model: "doubao-seed-1-6-flash-250828", responseFormat: "schema", image: true, @@ -413,7 +436,7 @@ const modelList: Owned[] = [ tool: true, }, //xai - { + { manufacturer: "xai", model: "grok-3", responseFormat: "schema", @@ -422,7 +445,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4", responseFormat: "schema", @@ -431,7 +454,7 @@ const modelList: Owned[] = [ instance: createXai, tool: true, }, - { + { manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", @@ -444,12 +467,24 @@ const modelList: Owned[] = [ { manufacturer: "other", model: "gpt-4.1", - responseFormat: "schema", + responseFormat: "object", image: true, think: false, instance: createOpenAI, tool: true, }, ]; - +export const getModelList = async () => { + const modelLists = await db("t_textModel").select("*"); + const resultInstaceList = modelLists.map((model) => { + return { + ...model, + tool: model.tool == 1 ? true : false, + think: model.think == 1 ? true : false, + image: model.image == 1 ? true : false, + instance: instanceMap[model.manufacturer as keyof typeof instanceMap], + }; + }); + return resultInstaceList as Owned[]; +}; export default modelList; diff --git a/src/utils/ai/utils.ts b/src/utils/ai/utils.ts index d03aa2e..e38da30 100644 --- a/src/utils/ai/utils.ts +++ b/src/utils/ai/utils.ts @@ -1,5 +1,5 @@ import modelList from "./video/modelList"; - +import { db } from "../db"; interface ValidateResult { owned: (typeof modelList)[number]; images: string[]; @@ -80,3 +80,5 @@ export const pollTask = async ( } throw new Error(`任务轮询超时,已尝试 ${maxAttempts} 次`); }; + + diff --git a/src/utils/ai/video/index.ts b/src/utils/ai/video/index.ts index ad39c9a..1524b07 100644 --- a/src/utils/ai/video/index.ts +++ b/src/utils/ai/video/index.ts @@ -29,8 +29,8 @@ export default async (input: VideoConfig, config?: AIConfig) => { const manufacturerFn = modelInstance[manufacturer as keyof typeof modelInstance]; if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的视频厂商"); - const owned = modelList.find((m) => m.model === model); - if (!owned) throw new Error("不支持的模型"); + // const owned = modelList.find((m) => m.model === model); + // if (!owned) throw new Error("不支持的模型"); // 补充图片的 base64 内容类型字符串 if (input.imageBase64 && input.imageBase64.length > 0) { diff --git a/src/utils/ai/video/owned/gemini.ts b/src/utils/ai/video/owned/gemini.ts index ab01e03..7c5beea 100644 --- a/src/utils/ai/video/owned/gemini.ts +++ b/src/utils/ai/video/owned/gemini.ts @@ -10,7 +10,7 @@ export default async (input: VideoConfig, config: AIConfig) => { if (!config.model) throw new Error("缺少Model名称"); if (!config.apiKey) throw new Error("缺少API Key"); - const { owned, images, hasStartEndType } = validateVideoConfig(input, config); + // const { owned, images, hasStartEndType } = validateVideoConfig(input, config); const defaultBaseUrl = [ "https://generativelanguage.googleapis.com/v1beta/models/{model}:predictLongRunning", @@ -18,8 +18,7 @@ export default async (input: VideoConfig, config: AIConfig) => { ].join("|"); const [submitUrl, queryUrl] = (config.baseURL || defaultBaseUrl).split("|"); - - + const headers = { "x-goog-api-key": config.apiKey }; const instance: Record = { prompt: input.prompt }; @@ -30,17 +29,17 @@ export default async (input: VideoConfig, config: AIConfig) => { }; // 根据图片数量和模型能力决定图片用法 - const len = images.length; - const hasRef = owned.type.includes("reference"); - const hasSingle = owned.type.includes("singleImage"); - + const len = input.imageBase64 ? input.imageBase64.length : 0; + const hasRef = input.mode == "multi"; + const hasSingle = input.mode == "single"; + const hasStartEndType = input.mode === "startEnd"; if (len === 2 && hasStartEndType) { - instance.image = buildInlineImage(images[0]); - parameters.lastFrame = buildInlineImage(images[1]); + instance.image = buildInlineImage(input.imageBase64![0]); + parameters.lastFrame = buildInlineImage(input.imageBase64![1]); } else if (len === 1 && (hasSingle || hasStartEndType)) { - instance.image = buildInlineImage(images[0]); + instance.image = buildInlineImage(input.imageBase64![0]); } else if (len >= 1 && len <= 3 && hasRef) { - parameters.referenceImages = images.map((img) => ({ image: buildInlineImage(img), referenceType: "asset" })); + parameters.referenceImages = input.imageBase64!.map((img) => ({ image: buildInlineImage(img), referenceType: "asset" })); } const { data } = await axios.post( @@ -53,15 +52,14 @@ export default async (input: VideoConfig, config: AIConfig) => { return pollTask(async () => { const { data: status } = await axios.get(queryUrl.replace("{name}", data.name), { headers }); - + const { done, response, error } = status; - if (!done) return { completed: false }; if (error) return { completed: false, error: `任务失败: ${error.message || JSON.stringify(error)}` }; const videoUri = response?.generateVideoResponse?.generatedSamples?.[0]?.video?.uri; - + if (!videoUri) return { completed: false, error: "未获取到视频下载地址" }; const videoRes = await axios.get(videoUri, { headers, responseType: "arraybuffer", maxRedirects: 5 }); diff --git a/src/utils/ai/video/owned/kling.ts b/src/utils/ai/video/owned/kling.ts index bb3c539..ce766a7 100644 --- a/src/utils/ai/video/owned/kling.ts +++ b/src/utils/ai/video/owned/kling.ts @@ -6,7 +6,7 @@ export default async (input: VideoConfig, config: AIConfig) => { if (!config.apiKey) throw new Error("缺少API Key"); if (!config.baseURL) throw new Error("缺少baseURL配置"); - const { images } = validateVideoConfig(input, config); + // const { images } = validateVideoConfig(input, config); // 解析URL配置:图生视频|文生视频|查询地址 const defaultBaseUrl = @@ -24,7 +24,7 @@ export default async (input: VideoConfig, config: AIConfig) => { const mode = modelMatch ? (modelMatch[2].toLowerCase() as "std" | "pro") : "std"; // 判断是图生视频还是文生视频 - const hasImage = images.length > 0; + const hasImage = input.imageBase64 ? input.imageBase64.length > 0 : false; const createUrl = hasImage ? image2videoUrl : text2videoUrl; // 去除图片的内容类型前缀(kling要求纯base64) @@ -41,9 +41,9 @@ export default async (input: VideoConfig, config: AIConfig) => { if (hasImage) { // 图生视频:首帧和尾帧 - body.image = stripDataUrl(images[0]); - if (images.length > 1) { - body.image_tail = stripDataUrl(images[1]); + body.image = stripDataUrl(input.imageBase64![0]); + if (input.imageBase64!.length > 1) { + body.image_tail = stripDataUrl(input.imageBase64![1]); } } diff --git a/src/utils/ai/video/owned/runninghub.ts b/src/utils/ai/video/owned/runninghub.ts index 1a4d6c2..cbec950 100644 --- a/src/utils/ai/video/owned/runninghub.ts +++ b/src/utils/ai/video/owned/runninghub.ts @@ -7,7 +7,7 @@ import { pollTask, validateVideoConfig } from "@/utils/ai/utils"; export default async (input: VideoConfig, config: AIConfig) => { if (!config.apiKey) throw new Error("缺少API Key"); - const { owned, images, hasTextType } = validateVideoConfig(input, config); + // const { owned, images, hasTextType } = validateVideoConfig(input, config); const defaultBaseUrl = [ "https://www.runninghub.cn/openapi/v2/rhart-video-s/image-to-video", @@ -19,8 +19,8 @@ export default async (input: VideoConfig, config: AIConfig) => { ].join("|"); const [image2videoUrl, image2videoProUrl, text2videoUrl, text2videoProUrl, queryUrl, uploadUrl] = (config.baseURL || defaultBaseUrl).split("|"); - - const isPro = owned.model === "sora-2-pro"; + const hasTextType = input.mode == "text"; + const isPro = config.model === "sora-2-pro"; const authorization = `Bearer ${config.apiKey}`; // 上传 base64 图片 @@ -65,20 +65,19 @@ export default async (input: VideoConfig, config: AIConfig) => { return { taskId: data.taskId, status: data.status, url: data.results?.[0]?.url }; }; - const isTextToVideo = images.length === 0 && hasTextType; + const isTextToVideo = (!input.imageBase64 || input.imageBase64.length === 0) && hasTextType; const submitUrl = isTextToVideo ? (isPro ? text2videoProUrl : text2videoUrl) : isPro ? image2videoProUrl : image2videoUrl; const requestBody: Record = { prompt: input.prompt, duration: String(input.duration), aspectRatio: input.aspectRatio, - ...(isTextToVideo ? {} : { imageUrl: await uploadImage(images[0]) }), + ...(isTextToVideo ? {} : { imageUrl: await uploadImage(input.imageBase64![0]) }), }; const { taskId } = await submitTask(submitUrl, requestBody); return await pollTask(async () => { - const { data } = await axios.post( queryUrl, { diff --git a/src/utils/ai/video/owned/vidu.ts b/src/utils/ai/video/owned/vidu.ts index 86cac52..368a7a1 100644 --- a/src/utils/ai/video/owned/vidu.ts +++ b/src/utils/ai/video/owned/vidu.ts @@ -20,30 +20,30 @@ export default async (input: VideoConfig, config: AIConfig) => { const hasImages = input.imageBase64 && input.imageBase64.length > 0; // 根据是否有图片,查找匹配的模型配置 - const customOwned = modelList.find((m) => { - if (m.manufacturer !== "vidu") return false; - if (m.model !== config.model) return false; - if (hasImages) { - return m.type.some((t) => t !== "text"); - } else { - return m.type.includes("text"); - } - }); + // const customOwned = modelList.find((m) => { + // if (m.manufacturer !== "vidu") return false; + // if (m.model !== config.model) return false; + // if (hasImages) { + // return m.type.some((t) => t !== "text"); + // } else { + // return m.type.includes("text"); + // } + // }); - if (!customOwned) { - throw new Error(`未找到匹配的模型配置: ${config.model}`); - } + // if (!customOwned) { + // throw new Error(`未找到匹配的模型配置: ${config.model}`); + // } // 使用统一校验函数 - const { owned, images } = validateVideoConfig(input, config, customOwned); + // const { owned, images } = validateVideoConfig(input, config, customOwned); // 判断生成类型 - const genType: "text" | "image" = images.length === 0 ? "text" : "image"; + const genType: "text" | "image" = input.imageBase64 && input.imageBase64.length === 0 ? "text" : "image"; - // 校验宽高比(仅文生视频需要) - if (genType === "text" && owned.aspectRatio.length > 0 && !owned.aspectRatio.includes(input.aspectRatio as `${number}:${number}`)) { - throw new Error(`模型 ${owned.model} 不支持宽高比 ${input.aspectRatio},支持的宽高比:${owned.aspectRatio.join("、")}`); - } + // // 校验宽高比(仅文生视频需要) + // if (genType === "text" && owned.aspectRatio.length > 0 && !owned.aspectRatio.includes(input.aspectRatio as `${number}:${number}`)) { + // throw new Error(`模型 ${owned.model} 不支持宽高比 ${input.aspectRatio},支持的宽高比:${owned.aspectRatio.join("、")}`); + // } // 创建任务 let taskId: string; @@ -51,13 +51,13 @@ export default async (input: VideoConfig, config: AIConfig) => { if (genType === "text") { // 文生视频 const requestBody: Record = { - model: owned.model, + model: config.model, prompt: input.prompt, duration: input.duration, resolution: input.resolution, aspect_ratio: input.aspectRatio, }; - if (owned.audio && input.audio !== undefined) { + if (input.audio && input.audio !== undefined) { requestBody.audio = input.audio; } @@ -71,15 +71,15 @@ export default async (input: VideoConfig, config: AIConfig) => { } else { // 图生视频 const requestBody: Record = { - model: owned.model, - images: images, + model: config.model, + images: input.imageBase64, duration: input.duration, resolution: input.resolution, }; if (input.prompt) { requestBody.prompt = input.prompt; } - if (owned.audio && input.audio !== undefined) { + if (input.audio && input.audio !== undefined) { requestBody.audio = input.audio; } diff --git a/src/utils/ai/video/owned/volcengine.ts b/src/utils/ai/video/owned/volcengine.ts index 328e031..b84fd44 100644 --- a/src/utils/ai/video/owned/volcengine.ts +++ b/src/utils/ai/video/owned/volcengine.ts @@ -5,11 +5,11 @@ import { pollTask, validateVideoConfig } from "@/utils/ai/utils"; export default async (input: VideoConfig, config: AIConfig) => { if (!config.apiKey) throw new Error("缺少API Key"); - const { owned, images, hasStartEndType } = validateVideoConfig(input, config); - + // const { owned, images, hasStartEndType } = validateVideoConfig(input, config); + const hasStartEndType = input.mode === "startEnd"; const authorization = "Bearer " + config.apiKey.replace(/^Bearer\s*/i, "").trim(); const baseUrl = config.baseURL ?? "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks"; - + const images = input.imageBase64 || []; // 判断是否为首尾帧模式(需要两张图且类型支持首尾帧) const isStartEndMode = images.length === 2 && hasStartEndType; @@ -35,7 +35,7 @@ export default async (input: VideoConfig, config: AIConfig) => { }; // 仅当模型支持音频时才添加 generate_audio 字段 - if (owned.audio) { + if (input?.audio) { requestBody.generate_audio = input.audio ?? false; } // 创建视频生成任务 diff --git a/src/utils/ai/video/owned/wan.ts b/src/utils/ai/video/owned/wan.ts index e319ad6..a64d00d 100644 --- a/src/utils/ai/video/owned/wan.ts +++ b/src/utils/ai/video/owned/wan.ts @@ -39,8 +39,10 @@ const getSizeFromConfig = (resolution: string, aspectRatio: string): string => { export default async (input: VideoConfig, config: AIConfig) => { if (!config.apiKey) throw new Error("缺少API Key"); - const { owned, images, hasStartEndType, hasTextType } = validateVideoConfig(input, config); - + // const { owned, images, hasStartEndType, hasTextType } = validateVideoConfig(input, config); + const hasStartEndType = input.mode === "startEnd"; + const hasTextType = input.mode === "text"; + const images = input.imageBase64 || []; const defaultBaseUrl = [ "https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis", "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis", @@ -49,7 +51,7 @@ export default async (input: VideoConfig, config: AIConfig) => { const [i2vUrl, kf2vUrl, queryUrl] = (config.baseURL || defaultBaseUrl).split("|"); - const types = owned.type; + // const types = owned.type; const authorization = `Bearer ${config.apiKey}`; // 确定端点和构建请求体 @@ -69,7 +71,7 @@ export default async (input: VideoConfig, config: AIConfig) => { duration: input.duration, }, }; - } else if (types.includes("singleImage")) { + } else if (input.mode == 'single' && images.length === 1) { // 图生视频 submitUrl = i2vUrl; body = { @@ -84,7 +86,7 @@ export default async (input: VideoConfig, config: AIConfig) => { }, }; // audio参数仅部分模型支持 - if (owned.audio && input.audio !== undefined) { + if (input.audio && input.audio !== undefined) { body.parameters.audio = input.audio; } } else if (hasStartEndType) { @@ -95,9 +97,7 @@ export default async (input: VideoConfig, config: AIConfig) => { first_frame_url: images[0], }; // 尾帧处理 - if (types.includes("startEndRequired")) { - inputObj.last_frame_url = images[1]; - } else if ((types.includes("endFrameOptional") || types.includes("startFrameOptional")) && images.length >= 2) { + if (hasStartEndType && images.length >= 2) { inputObj.last_frame_url = images[1]; } body = { @@ -109,7 +109,7 @@ export default async (input: VideoConfig, config: AIConfig) => { }, }; } else { - throw new Error(`不支持的视频生成类型: ${types.join(", ")}`); + throw new Error(`不支持的视频生成类型: ${hasStartEndType ? "startEnd" : hasTextType ? "text" : "single"}`); } // 提交任务 diff --git a/src/utils/ai/video/type.ts b/src/utils/ai/video/type.ts index 4c38699..499681a 100644 --- a/src/utils/ai/video/type.ts +++ b/src/utils/ai/video/type.ts @@ -6,6 +6,7 @@ interface VideoConfig { savePath: string; imageBase64?: string[]; audio?: boolean; + mode: "startEnd" | "multi" | "single" | "text"; } interface AIConfig { From 2f3bbb0f1e13d3beb2e6ba21045c31cb1c231b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Sat, 28 Feb 2026 10:00:34 +0800 Subject: [PATCH 08/17] no message --- src/router.ts | 134 +++++++++++++++++++++------------------- src/types/database.d.ts | 37 +---------- 2 files changed, 71 insertions(+), 100 deletions(-) diff --git a/src/router.ts b/src/router.ts index 23eb89b..5830e05 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash bf59be4347a649430bc8b6067c3cf9ef +// @routes-hash e13311bd461bd8de8701383106557048 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -48,38 +48,40 @@ 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/video/addVideo"; +import route70 from "./routes/video/addVideoConfig"; +import route71 from "./routes/video/deleteVideoConfig"; +import route72 from "./routes/video/generatePrompt"; +import route73 from "./routes/video/generateVideo"; +import route74 from "./routes/video/getManufacturer"; +import route75 from "./routes/video/getVideo"; +import route76 from "./routes/video/getVideoConfigs"; +import route77 from "./routes/video/getVideoModel"; +import route78 from "./routes/video/getVideoStoryboards"; +import route79 from "./routes/video/reviseVideoStoryboards"; +import route80 from "./routes/video/saveVideo"; +import route81 from "./routes/video/upDateVideoConfig"; export default async (app: Express) => { app.use("/assets/addAssets", route1); @@ -129,36 +131,38 @@ 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("/video/addVideo", route69); + app.use("/video/addVideoConfig", route70); + app.use("/video/deleteVideoConfig", route71); + app.use("/video/generatePrompt", route72); + app.use("/video/generateVideo", route73); + app.use("/video/getManufacturer", route74); + app.use("/video/getVideo", route75); + app.use("/video/getVideoConfigs", route76); + app.use("/video/getVideoModel", route77); + app.use("/video/getVideoStoryboards", route78); + app.use("/video/reviseVideoStoryboards", route79); + app.use("/video/saveVideo", route80); + app.use("/video/upDateVideoConfig", route81); } diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 25cd1ff..e412c1c 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,20 +1,6 @@ -// @db-hash ab4e3e93bfba304164daa7d28c804eaf +// @db-hash c54a70dc90b32388fcd8927df6bd8c03 //该文件由脚本自动生成,请勿手动修改 -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; @@ -53,6 +39,7 @@ export interface t_config { 'manufacturer'?: string | null; 'model'?: string | null; 'modelType'?: string | null; + 'name'?: string | null; 'type'?: string | null; 'userId'?: number | null; } @@ -66,13 +53,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 +125,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; @@ -184,7 +155,6 @@ export interface t_video { 'time'?: number | null; } export interface t_videoConfig { - 'aiConfigId'?: number | null; 'audioEnabled'?: number | null; 'createTime'?: number | null; 'duration'?: 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; From 173d179ea4907974f248449345f940bd4dcf0d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Sat, 28 Feb 2026 10:51:36 +0800 Subject: [PATCH 09/17] no message --- src/types/database.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/database.d.ts b/src/types/database.d.ts index e412c1c..47862e0 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,4 @@ -// @db-hash c54a70dc90b32388fcd8927df6bd8c03 +// @db-hash 0f9789bd5ad2eebd79bd502988efcb4e //该文件由脚本自动生成,请勿手动修改 export interface t_aiModelMap { @@ -39,7 +39,6 @@ export interface t_config { 'manufacturer'?: string | null; 'model'?: string | null; 'modelType'?: string | null; - 'name'?: string | null; 'type'?: string | null; 'userId'?: number | null; } @@ -155,6 +154,7 @@ export interface t_video { 'time'?: number | null; } export interface t_videoConfig { + 'aiConfigId'?: number | null; 'audioEnabled'?: number | null; 'createTime'?: number | null; 'duration'?: number | null; From fea860e1bbf453f12f54a88ab7d1f1ab06512d1b Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Sat, 28 Feb 2026 11:20:22 +0800 Subject: [PATCH 10/17] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E9=85=8D=E7=BD=AE=20=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E4=B8=A2=E5=A4=B1=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=AD=94=E5=A1=94=E9=85=8D=E7=BD=AE=EF=BC=8C=E5=88=86=E9=95=9C?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D=E6=B7=BB=E5=8A=A0=E5=8F=B0=E8=AF=8D?= =?UTF-8?q?=EF=BC=88=E5=BE=85=E6=B5=8B=E8=AF=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/agents/storyboard/index.ts | 11 +- src/lib/fixDB.ts | 9 +- src/lib/initDB.ts | 21 ++-- src/router.ts | 136 +++++++++++++------------ src/routes/other/testAI.ts | 1 + src/routes/script/generateScriptApi.ts | 20 ++-- src/routes/user/saveUser.ts | 24 +++++ src/routes/video/deleteVideoConfig.ts | 6 +- src/types/database.d.ts | 35 +------ src/utils/ai/image/owned/other.ts | 20 ++-- src/utils/ai/image/owned/volcengine.ts | 16 ++- src/utils/ai/text/index.ts | 8 +- src/utils/ai/text/modelList.ts | 2 +- yarn.lock | 50 ++++----- 15 files changed, 185 insertions(+), 176 deletions(-) create mode 100644 src/routes/user/saveUser.ts 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" From 4a98783922cd79712e088b897e1c5d5866fecc11 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Sat, 28 Feb 2026 11:23:24 +0800 Subject: [PATCH 11/17] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=86=E9=95=9C?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/fixDB.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/fixDB.ts b/src/lib/fixDB.ts index 1b9371a..77ae973 100644 --- a/src/lib/fixDB.ts +++ b/src/lib/fixDB.ts @@ -49,6 +49,12 @@ export default async (knex: Knex): Promise => { 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"); + + await knex("t_prompts") + .update({ + defaultValue:'你是一位专业的电影分镜师,负责根据剧本片段生成具有电影感的分镜提示词。\n\n---\n\n## 📋 工作流程\n\n1. **调用 getAssets** - 获取资产列表(角色、道具、场景及其详情)\n2. **调用 getScript** - 获取剧本内容,深入理解故事背景\n3. **调用 getSegments** - 获取当前片段数据\n4. **识别任务参数** - 从任务描述中提取片段序号和镜头数量\n5. **生成分镜提示词** - 创作电影级分镜描述\n6. **保存分镜** - 调用 addShots(新建)或 updateShots(修改)\n\n---\n\n## ⚠️ 核心原则\n\n### 🎯 剧本忠实原则\n- ✅ 分镜**严格基于剧本内容**,不得凭空编造情节\n- ✅ 角色关系、场景细节、人物称呼**必须与剧本一致**\n- ✅ **对话内容逐字引用**,不得改写或省略\n- ✅ 人物情绪、动作必须符合剧本上下文逻辑\n\n### 🏷️ 资产名称强制规则\n- ✅ 角色、道具、场景名称**原封不动**使用 getAssets 返回的名称\n- ❌ 禁止缩写(王林 ≠ 小王)\n- ❌ 禁止近义词替换(老槐树 ≠ 大树)\n- ❌ 禁止添加修饰前缀(木匠家小院 ≠ 破旧小院)\n\n---\n\n## 🎬 电影分镜提示词生成规则\n\n### 📐 镜头数量\n- **默认:4个镜头/片段**\n- **以用户指定为准**(支持4格、6格、12格等任意数量)\n\n---\n\n### 🎥 镜头语言要素(每个提示词必须包含)\n\n#### 1️⃣ 景别(必选其一)\n| 景别 | 用途 | 画面范围 |\n|------|------|----------|\n| **大远景** | 宏大场景,建立世界观 | 人物渺小,环境主导 |\n| **远景** | 环境关系,场景交代 | 人物全身,环境占70% |\n| **全景** | 动作展示,空间关系 | 人物全身清晰可见 |\n| **中景** | 肢体互动,日常叙事 | 膝盖以上 |\n| **近景** | 表情神态,情绪传递 | 胸部以上 |\n| **特写** | 情绪爆发,细节强调 | 面部或关键物件 |\n| **大特写** | 极致情绪,符号化表达 | 眼睛/手指等局部 |\n\n#### 2️⃣ 机位角度(必选其一)\n- **平视**:客观叙事,日常对话\n- **俯拍**:压迫感、脆弱感、上帝视角\n- **仰拍**:崇高感、威胁感、角色主观感受\n- **斜角/荷兰角**:不安、紧张、混乱\n- **过肩镜头**:对话场景,展现互动\n- **主观视角**:角色第一人称,沉浸体验\n\n#### 3️⃣ 光线设计(必选)\n**光源方向**:\n- 顺光(平面感)\n- 侧光(立体感)\n- 逆光(轮廓光)\n- 顶光(神秘感)\n- 底光(恐怖感)\n\n**光线质感**:\n- 硬光:强烈阴影,戏剧张力\n- 柔光:柔和过渡,温馨自然\n\n**光线色温**:\n- 暖光:金黄/橙红(温暖、怀旧)\n- 冷光:蓝调/青白(冷漠、科技)\n\n**特殊光效**:\n- 丁达尔效应(神圣感)\n- 轮廓光(分离主体)\n- 眼神光(点亮眼睛)\n\n#### 4️⃣ 构图法则(选择适用)\n- **三分法**:主体置于三分线交点,平衡稳定\n- **中心构图**:对称庄重,仪式感\n- **对角线构图**:动态张力,引导视线\n- **框架构图**:门窗形成画框,突出主体\n- **引导线构图**:道路栏杆引导视线\n- **前景遮挡**:增加层次和纵深\n\n#### 5️⃣ 景深与焦点\n- **浅景深**:主体清晰,背景虚化 → 突出人物\n- **深景深**:前后清晰 → 交代环境关系\n- **焦点位置**:明确对焦目标\n\n#### 6️⃣ 色彩基调\n- **整体色调**:暖调/冷调/中性\n- **主色调**:画面主导颜色\n- **对比色**:视觉冲击,情绪对立\n\n#### 7️⃣ 氛围情绪词\n- 孤寂、温馨、紧张、压抑、希望、绝望、诡异、宁静、躁动、忧郁...\n\n---\n\n### 👤 人物要素(涉及人物时必须包含)\n\n#### 1️⃣ 人物站位与空间关系\n- **画面位置**:左侧/右侧/中央/前景/背景\n- **人物朝向**:面向镜头/背对镜头/侧面/四分之三侧面\n- **多人关系**:对峙/并肩/一前一后/围坐\n\n#### 2️⃣ 肢体语言\n- **姿态**:站立/坐姿/蹲踞/躺卧/倚靠\n- **手部动作**:具体描述(握拳/摊手/指向/抚摸)\n- **身体倾向**:前倾(关注)/后仰(抗拒)/侧身(回避)\n\n#### 3️⃣ 表情神态\n- **眼神**:凝视/游离/低垂/上扬/眯眼/空洞/坚毅\n- **面部表情**:微笑/皱眉/咬牙/嘴角上扬\n- **微表情**:眉头、嘴角、鼻翼的细微变化\n\n#### 4️⃣ 服装状态\n- **整洁度**:整齐/凌乱/破损/沾染污渍\n- **穿着细节**:衣领/袖口/下摆状态\n\n---\n\n### 🌍 环境要素\n\n#### 1️⃣ 时间氛围\n- **时段**:黎明/清晨/正午/午后/黄昏/夜晚/深夜\n- **天气**:晴/阴/雨/雪/雾/风\n\n#### 2️⃣ 环境细节\n- **前景元素**:增加画面层次(树枝/栏杆/窗框)\n- **背景元素**:交代环境信息(山峦/建筑/人群)\n- **环境道具**:与剧情相关的物件\n\n#### 3️⃣ 空气介质\n- 烟雾/尘埃/雨丝/雪花/光束中的微粒\n\n---\n\n## 💬 对话处理规则(重要新增)\n\n### 对话镜头设计原则\n1. **对话必须完整呈现**:逐字引用剧本台词,不得省略或改写\n2. **说话者镜头**:展示说话人的表情、口型、情绪\n3. **倾听者镜头**:捕捉听者的反应、表情变化\n4. **过肩镜头**:交替使用,展现对话互动\n5. **环境音效提示**:注明对话时的环境音(如有必要)\n\n### 对话镜头格式\n```\n镜头X: [景别][机位][构图],[人物]位于画面[位置],[表情动作],\n正在说话,口型清晰,台词:"完整对话内容",\n[场景][光线][色调][氛围]\n\n或\n\n镜头X: [景别][机位][构图],[人物]位于画面[位置],[倾听表情],\n听到台词:"对方说的话",眼神[反应描述],\n[场景][光线][色调][氛围]\n```\n\n### 对话场景镜头分配建议\n- **短对话(1-2句)**:2个镜头(说话者+倾听者)\n- **中等对话(3-5句)**:3-4个镜头(交替过肩+反应镜头)\n- **长对话(6句以上)**:5-8个镜头(景别变化+特写插入)\n\n---\n\n## 📝 提示词模板结构\n\n### 标准镜头模板\n```\n[景别][机位角度],[构图方式],\n[人物名称]位于画面[位置],[朝向],[姿态],[具体动作],\n[表情神态],[眼神描述],\n[服装状态描述],\n[场景名称],[时间氛围],[环境细节],\n[光线设计:光源+质感+色温],\n[景深设置],[色彩基调],\n[氛围情绪词]\n```\n\n### 对话镜头模板\n```\n[景别][机位角度],[构图方式],\n[人物名称]位于画面[位置],[朝向],[表情],\n正在说话/倾听,台词:"完整对话内容",\n[嘴部动作/眼神反应],\n[服装状态],\n[场景名称],[时间氛围],\n[光线设计],[景深],[色调],\n[对话氛围词]\n```\n\n---\n\n## 🎯 分镜序列设计原则\n\n### 叙事节奏\n1. **建立镜头(Establishing Shot)**:远景/大远景交代环境\n2. **发展镜头(Development Shot)**:中景展现动作互动\n3. **情绪镜头(Emotional Shot)**:近景/特写捕捉情感高点\n4. **过渡镜头(Transition Shot)**:连接场景或时间\n5. **收尾镜头(Closing Shot)**:呼应或留白\n\n### 对话场景特殊节奏\n1. **开场建立**:全景展示对话双方位置关系\n2. **对话展开**:过肩镜头交替(正反打)\n3. **情绪递进**:逐步推近至近景/特写\n4. **高潮反应**:特写捕捉关键情绪\n5. **收尾**:拉远重新建立环境\n\n### 景别变化规律\n- ❌ 避免连续相同景别\n- ✅ 情绪递进时逐步推近(远→中→近→特写)\n- ✅ 场景转换时拉远重新建立\n- ✅ 对话场景使用"正反打"技法(过肩镜头交替)\n\n### 视线连贯(180度轴线法则)\n- ✅ 人物视线方向要有呼应\n- ✅ 动作方向保持连贯\n- ✅ 对话场景不跨越轴线(避免方向混乱)\n\n---\n\n## 📤 输出格式\n\n```\n【片段 X】片段描述...\n(如有对话,标注对话人物和台词数量)\n\n镜头1: [完整提示词]\n镜头2: [完整提示词]\n镜头3: [完整提示词]\n...\n\n---\n✅ 已调用 addShots/updateShots 保存分镜\n```\n\n---\n\n## 💡 示例\n\n### 示例1:无对话场景\n\n**片段描述**:"黄昏小院,王林独坐老槐树下望天,父亲唤其回屋吃饭"\n\n**镜头1**: 大远景,平视,三分法构图,乡村木匠家小院位于画面右侧三分之一处,黄昏时分,夕阳西斜,暖橙色光线斜射,老槐树剪影投下长影,炊烟袅袅升起,远山层叠,深景深,暖褐色调,宁静悠远\n\n**镜头2**: 全景,平视,框架构图,老槐树枝干形成自然画框,王林坐于树下石凳,双手搭膝,微微仰头,目光投向远方天际,乡村木匠家小院,黄昏柔光,侧光照亮半边脸庞,中等景深,暖橙色调,若有所思\n\n**镜头3**: 近景,平视,中心构图,王林面部占据画面中央,仰望天际,眼神中带着憧憬与迷惘,嘴角微抿,额前发丝被微风轻拂,黄昏天空作为背景,逆光形成发丝轮廓光,浅景深,暖金色调,青春迷惘\n\n**镜头4**: 中景,过肩镜头,从王林肩后望向院门方向,父亲身影出现在门框中,正在招手呼唤,王林肩背作为前景虚化,乡村木匠家小院,黄昏光线从门内透出,中等景深,暖黄色调,温情呼唤\n\n---\n\n### 示例2:对话场景(新增)\n\n**片段描述**:"深夜书房,李梅质问丈夫张强关于加班的真相"\n\n**对话内容**:\n- 李梅:"这么晚才回来,又是加班?"\n- 张强:"嗯...项目赶工,没办法。"\n- 李梅:"你衬衫上的口红印怎么解释?"\n\n---\n\n**镜头1**: 全景,平视,三分法构图,书房内李梅站在书桌旁画面左侧,双臂抱胸,面向画面右侧,张强站在门口画面右侧,提着公文包,两人相距三米形成对峙,深夜昏黄台灯光从书桌洒出,侧光在李梅脸上形成明暗对比,深景深,冷暖色调对比(暖黄台灯vs冷蓝月光),紧张压抑\n\n**镜头2**: 中景,过肩镜头,从李梅肩后看向张强,李梅肩部作为前景虚化占据画面左侧,张强位于画面中央,表情闪躲,眼神飘忽不定,正在说话,台词:"这么晚才回来,又是加班?",嘴唇微启,语气冰冷,书房,台灯侧光在张强脸上形成不安阴影,中等景深,冷色调,质问压迫\n\n**镜头3**: 近景,过肩镜头,从张强肩后看向李梅,张强西装肩部作为前景,李梅位于画面中央,眉头紧锁,眼神锐利直视,正在倾听张强的回答,听到台词:"嗯...项目赶工,没办法。",嘴角微微下沉,眼神中透露不信任,书房,台灯光从侧面照亮李梅半边脸庞,浅景深背景虚化,暖黄转冷的色调,怀疑审视\n\n**镜头4**: 特写,平视,中心构图,张强面部占据画面,四分之三侧面,眼神躲闪向下,额头渗出细密汗珠,喉结滚动,听到李梅的质问:"你衬衫上的口红印怎么解释?",瞳孔瞬间放大,嘴唇微微颤抖,深夜书房背景虚化,侧光形成脸部强烈明暗对比,极浅景深,冷蓝色调,恐慌心虚\n\n**镜头5**: 特写,微俯拍,张强衬衫领口特写,白色衬衫上清晰可见鲜艳的口红印记,周围布料微微皱褶,台灯光直射形成强烈对比,极浅景深,冷白色调中口红印呈现刺眼红色,证据确凿\n\n**镜头6**: 近景,平视,中心构图,李梅面部占据画面,正面直视镜头,眼眶泛红,眼神从愤怒转为失望,嘴角紧抿,下巴微微颤抖,深夜书房,台灯光从下方映照,在眼眶处形成泪光反射,浅景深,冷蓝色调,心碎绝望\n\n---\n\n## 🛠️ 可用工具\n\n| 工具 | 用途 | 调用时机 |\n|------|------|----------|\n| **getAssets** | 获取角色/道具/场景资产列表 | ⚠️ 必须首先调用 |\n| **getScript** | 获取完整剧本内容 | ⚠️ 必须调用 |\n| **getSegments** | 获取当前片段数据 | 生成分镜前调用 |\n| **addShots** | 添加新分镜(首次生成) | 完成提示词后 |\n| **updateShots** | 更新已有分镜(修改) | 修改现有分镜时 |\n| **deleteShots** | 删除分镜 | 需要删除时 |\n\n---\n\n## ✅ 输出要求\n\n1. **工具调用规则**:\n - 首次生成 → `addShots`\n - 修改已有分镜 → `updateShots`\n\n2. **镜头数量**:\n - 默认 4 个/片段\n - 以用户指定为准\n - 对话场景根据台词量灵活调整\n\n3. **语言要求**:\n - 提示词使用**中文**\n - 专业术语准确\n - 台词**逐字引用**剧本原文\n\n4. **回复风格**:\n - 简洁专业\n - 适当使用 emoji 增强可读性 🎬📸✨\n - 关键信息**加粗**或标注 ⚠️' + }) + .where("code", "storyboard-shot"); const videoText = await knex("t_prompts").where("code", "video-text").first(); if (!videoText) { await knex("t_prompts").insert({ From 1b7d2b9f8e9d3b9da530d2102942b0dcc59cc330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Sat, 28 Feb 2026 16:36:38 +0800 Subject: [PATCH 12/17] no message --- src/router.ts | 56 ++++++++++--------- .../storyboard/generateStoryboardApi.ts | 4 +- src/utils/editImage.ts | 4 +- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/router.ts b/src/router.ts index 5830e05..cd4946e 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash e13311bd461bd8de8701383106557048 +// @routes-hash c97cf72361299980ea4b0c43549a0de8 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -69,19 +69,20 @@ 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/video/addVideo"; -import route70 from "./routes/video/addVideoConfig"; -import route71 from "./routes/video/deleteVideoConfig"; -import route72 from "./routes/video/generatePrompt"; -import route73 from "./routes/video/generateVideo"; -import route74 from "./routes/video/getManufacturer"; -import route75 from "./routes/video/getVideo"; -import route76 from "./routes/video/getVideoConfigs"; -import route77 from "./routes/video/getVideoModel"; -import route78 from "./routes/video/getVideoStoryboards"; -import route79 from "./routes/video/reviseVideoStoryboards"; -import route80 from "./routes/video/saveVideo"; -import route81 from "./routes/video/upDateVideoConfig"; +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); @@ -152,17 +153,18 @@ export default async (app: Express) => { app.use("/task/getTaskApi", route66); app.use("/task/taskDetails", route67); app.use("/user/getUser", route68); - app.use("/video/addVideo", route69); - app.use("/video/addVideoConfig", route70); - app.use("/video/deleteVideoConfig", route71); - app.use("/video/generatePrompt", route72); - app.use("/video/generateVideo", route73); - app.use("/video/getManufacturer", route74); - app.use("/video/getVideo", route75); - app.use("/video/getVideoConfigs", route76); - app.use("/video/getVideoModel", route77); - app.use("/video/getVideoStoryboards", route78); - app.use("/video/reviseVideoStoryboards", route79); - app.use("/video/saveVideo", route80); - app.use("/video/upDateVideoConfig", route81); + 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/storyboard/generateStoryboardApi.ts b/src/routes/storyboard/generateStoryboardApi.ts index 1ce5e2c..2c946de 100644 --- a/src/routes/storyboard/generateStoryboardApi.ts +++ b/src/routes/storyboard/generateStoryboardApi.ts @@ -16,8 +16,10 @@ export default router.post( }), async (req, res) => { const { filePath, prompt, projectId, assetsId } = req.body; + //拿到图片尺寸 + const projectInfo = await u.db("t_project").where({ id: projectId }).first(); - let data = await u.editImage(filePath, prompt, projectId); + let data = await u.editImage(filePath, prompt, projectId,projectInfo?.videoRatio!); const returnData: { id: number | null; url: string | null; diff --git a/src/utils/editImage.ts b/src/utils/editImage.ts index 1139621..2de8f6d 100644 --- a/src/utils/editImage.ts +++ b/src/utils/editImage.ts @@ -77,7 +77,7 @@ async function convertDirectiveAndImages(images: Record, directi * "将@图10中圈起来的部分换成@图8" * ); */ -export default async (images: Record, directive: string, projectId: number) => { +export default async (images: Record, directive: string, projectId: number, aspectRatio: string | null) => { const { prompt, images: base64Images } = await convertDirectiveAndImages(images, directive); const apiConfig = await u.getPromptAi("editImage"); @@ -86,7 +86,7 @@ export default async (images: Record, directive: string, project systemPrompt: "根据用户提供的具体修改指令,对上传的图片进行智能编辑。", prompt: prompt, imageBase64: base64Images, - aspectRatio: "16:9", + aspectRatio: aspectRatio!, size: "1K", }, apiConfig, From e82b032b49639db1d9a6ae79010184c5d3b38a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683> Date: Sat, 28 Feb 2026 16:37:20 +0800 Subject: [PATCH 13/17] no message --- src/utils/editImage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/editImage.ts b/src/utils/editImage.ts index 2de8f6d..175bc0e 100644 --- a/src/utils/editImage.ts +++ b/src/utils/editImage.ts @@ -86,7 +86,7 @@ export default async (images: Record, directive: string, project systemPrompt: "根据用户提供的具体修改指令,对上传的图片进行智能编辑。", prompt: prompt, imageBase64: base64Images, - aspectRatio: aspectRatio!, + aspectRatio: aspectRatio ? aspectRatio : "16:9", size: "1K", }, apiConfig, From bc36f6599e989578ecf56cc81cff833f6e9b2cc0 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Sat, 28 Feb 2026 20:12:04 +0800 Subject: [PATCH 14/17] =?UTF-8?q?=E6=8E=A5=E5=85=A5grsai?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/initDB.ts | 66 ++++++++++++++++++ src/router.ts | 56 ++++++++-------- src/routes/assets/generateAssets.ts | 1 + src/routes/other/testAI.ts | 1 - src/routes/storyboard/delStoryboard.ts | 1 - src/utils/ai/image/index.ts | 2 + src/utils/ai/image/owned/grsai.ts | 92 ++++++++++++++++++++++++++ src/utils/ai/image/owned/modelScope.ts | 1 - src/utils/ai/image/owned/runninghub.ts | 3 +- src/utils/ai/image/owned/volcengine.ts | 4 +- src/utils/ai/text/index.ts | 4 +- src/utils/ai/text/modelList.ts | 3 +- src/utils/ai/video/index.ts | 5 +- src/utils/ai/video/owned/grsai.ts | 76 +++++++++++++++++++++ src/utils/ai/video/owned/other.ts | 49 ++++++++------ 15 files changed, 306 insertions(+), 58 deletions(-) create mode 100644 src/utils/ai/image/owned/grsai.ts create mode 100644 src/utils/ai/video/owned/grsai.ts diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index 9672b57..03542e2 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -644,6 +644,11 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => { 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" }, + { manufacturer: "grsai", model: "nano-banana-fast", grid: 1, type: "ti2i" }, + { manufacturer: "grsai", model: "nano-banana-pro", grid: 1, type: "ti2i" }, + { manufacturer: "grsai", model: "nano-banana", grid: 1, type: "ti2i" }, + { manufacturer: "grsai", model: "nano-banana-2", grid: 1, type: "ti2i" }, + ]); }, }, @@ -1103,6 +1108,67 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => audio: 0, type: JSON.stringify(["singleImage", "text"]), }, + { + id: 48, + manufacturer: "grsai", + model: "sora-2", + durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["singleImage", "text"]), + }, + { + id: 49, + manufacturer: "grsai", + model: "veo3.1-pro", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + }, + + { + id: 50, + manufacturer: "grsai", + model: "veo3.1-pro-1080p", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + },{ + id: 51, + manufacturer: "grsai", + model: "veo3.1-pro-4k", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + },{ + id: 52, + manufacturer: "grsai", + model: "veo3.1-fast", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + }, + { + id: 53, + manufacturer: "grsai", + model: "veo3.1-fast-1080p", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + },{ + id: 54, + manufacturer: "grsai", + model: "veo3.1-fast-4k", + durationResolutionMap: JSON.stringify([]), + aspectRatio: JSON.stringify(["16:9", "9:16"]), + audio: 0, + type: JSON.stringify(["startEndRequired", "text"]), + }, ]); }, }, diff --git a/src/router.ts b/src/router.ts index 5830e05..cd4946e 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash e13311bd461bd8de8701383106557048 +// @routes-hash c97cf72361299980ea4b0c43549a0de8 import { Express } from "express"; import route1 from "./routes/assets/addAssets"; @@ -69,19 +69,20 @@ 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/video/addVideo"; -import route70 from "./routes/video/addVideoConfig"; -import route71 from "./routes/video/deleteVideoConfig"; -import route72 from "./routes/video/generatePrompt"; -import route73 from "./routes/video/generateVideo"; -import route74 from "./routes/video/getManufacturer"; -import route75 from "./routes/video/getVideo"; -import route76 from "./routes/video/getVideoConfigs"; -import route77 from "./routes/video/getVideoModel"; -import route78 from "./routes/video/getVideoStoryboards"; -import route79 from "./routes/video/reviseVideoStoryboards"; -import route80 from "./routes/video/saveVideo"; -import route81 from "./routes/video/upDateVideoConfig"; +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); @@ -152,17 +153,18 @@ export default async (app: Express) => { app.use("/task/getTaskApi", route66); app.use("/task/taskDetails", route67); app.use("/user/getUser", route68); - app.use("/video/addVideo", route69); - app.use("/video/addVideoConfig", route70); - app.use("/video/deleteVideoConfig", route71); - app.use("/video/generatePrompt", route72); - app.use("/video/generateVideo", route73); - app.use("/video/getManufacturer", route74); - app.use("/video/getVideo", route75); - app.use("/video/getVideoConfigs", route76); - app.use("/video/getVideoModel", route77); - app.use("/video/getVideoStoryboards", route78); - app.use("/video/reviseVideoStoryboards", route79); - app.use("/video/saveVideo", route80); - app.use("/video/upDateVideoConfig", route81); + 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/assets/generateAssets.ts b/src/routes/assets/generateAssets.ts index 3cdc1c3..883416e 100644 --- a/src/routes/assets/generateAssets.ts +++ b/src/routes/assets/generateAssets.ts @@ -124,6 +124,7 @@ export default router.post( assetsId: id, }); const apiConfig = await u.getPromptAi("assetsImage"); + try { const contentStr = await u.ai.image( { diff --git a/src/routes/other/testAI.ts b/src/routes/other/testAI.ts index 8296f83..4fe5d85 100644 --- a/src/routes/other/testAI.ts +++ b/src/routes/other/testAI.ts @@ -48,7 +48,6 @@ 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/storyboard/delStoryboard.ts b/src/routes/storyboard/delStoryboard.ts index 4f467c3..7045b4b 100644 --- a/src/routes/storyboard/delStoryboard.ts +++ b/src/routes/storyboard/delStoryboard.ts @@ -12,7 +12,6 @@ export default router.post( }), async (req, res) => { const { id } = req.body; - console.log("%c Line:15 🍕 id", "background:#f5ce50", id); await u.db("t_assets").where("id", id).delete(); res.status(200).send(success("分镜删除成功")); }, diff --git a/src/utils/ai/image/index.ts b/src/utils/ai/image/index.ts index 3826c08..ae1dfdf 100644 --- a/src/utils/ai/image/index.ts +++ b/src/utils/ai/image/index.ts @@ -11,6 +11,7 @@ import apimart from "./owned/apimart"; import other from "./owned/other"; import gemini from "./owned/gemini"; import modelScope from "./owned/modelScope"; +import grsai from "./owned/grsai"; const urlToBase64 = async (url: string): Promise => { const res = await axios.get(url, { responseType: "arraybuffer" }); @@ -28,6 +29,7 @@ const modelInstance = { // apimart: apimart, modelScope, other, + grsai } as const; export default async (input: ImageConfig, config: AIConfig) => { diff --git a/src/utils/ai/image/owned/grsai.ts b/src/utils/ai/image/owned/grsai.ts new file mode 100644 index 0000000..4bc2b10 --- /dev/null +++ b/src/utils/ai/image/owned/grsai.ts @@ -0,0 +1,92 @@ +import axios from "axios"; +import u from "@/utils"; +import { pollTask } from "@/utils/ai/utils"; +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 processImages(imageBase64: string[]): Promise> { + let images = imageBase64.filter((img) => img?.trim()); + if (images.length === 0) return []; + + // 压缩所有图片到10MB以内 + images = await Promise.all(images.map((img) => u.imageTools.compressImage(img, "10mb"))); + + // 参考主体数量和参考图片数量之和不得超过10 + if (images.length > 6) { + const mergeImageList = images.splice(5); + const mergedImage = await u.imageTools.mergeImages(mergeImageList, "10mb"); + images.push(mergedImage); + } + + return images; +} + +export default async (input: ImageConfig, config: AIConfig): Promise => { + if (!config.apiKey) throw new Error("缺少API Key"); + const apiKey = config.apiKey.replace("Bearer ", ""); + + const defaultBaseURL = "https://grsai.dakka.com.cn/v1/draw/nano-banana|https://grsai.dakka.com.cn/v1/draw/result"; + + const { requestUrl, queryUrl } = getApiUrl(config.baseURL! || defaultBaseURL); + // 构建完整的提示词 + const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt; + + let mergedImage = await processImages(input.imageBase64 || []); + + const taskBody: Record = { + model: config.model, + prompt: fullPrompt, + imageSize: input.size, + aspectRatio: input.aspectRatio, + ...(mergedImage && mergedImage.length ? { urls: mergedImage } : {}), + webHook: "-1", + }; + + try { + + const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}` } }); + + + if (data.code != 0) throw new Error(`任务提交失败: ${data ? JSON.stringify(data, null, 2) : "未知错误"}`); + + return await pollTask(async () => { + const { data: queryData } = await axios.post( + queryUrl, + { + id: data.data.id, + }, + { + headers: { Authorization: `Bearer ${apiKey}` }, + }, + ); + + if (queryData.code != 0) throw new Error(`查询任务失败: ${queryData ? JSON.stringify(queryData, null, 2) : "未知错误"}`); + const { status, results, error, failure_reason } = queryData.data || {}; + + if (status === "failed") { + return { completed: false, error: failure_reason + "\n" + error || "图片生成失败" }; + } + + if (status === "succeeded") { + return { completed: true, url: results?.[0].url }; + } + + return { completed: false }; + }); + } catch (error: any) { + const msg = u.error(error).message || "图片生成失败"; + throw new Error(msg); + } +}; diff --git a/src/utils/ai/image/owned/modelScope.ts b/src/utils/ai/image/owned/modelScope.ts index 4a13dee..6b4cfad 100644 --- a/src/utils/ai/image/owned/modelScope.ts +++ b/src/utils/ai/image/owned/modelScope.ts @@ -119,7 +119,6 @@ export default async (input: ImageConfig, config: AIConfig): Promise => 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); } diff --git a/src/utils/ai/image/owned/runninghub.ts b/src/utils/ai/image/owned/runninghub.ts index 79a00d5..59b9f84 100644 --- a/src/utils/ai/image/owned/runninghub.ts +++ b/src/utils/ai/image/owned/runninghub.ts @@ -68,11 +68,12 @@ export default async (input: ImageConfig, config: AIConfig): Promise => const apiKey = config.apiKey.replace("Bearer ", ""); const baseURL = "https://www.runninghub.cn"; const imageUrls = await Promise.all(input.imageBase64.map((base64Image) => uploadBase64ToRunninghub(base64Image, apiKey, baseURL))); + const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt; const endpoint = input.imageBase64.length === 0 ? "/openapi/v2/rhart-image-n-pro/text-to-image" : "/openapi/v2/rhart-image-n-pro/edit"; const taskRes = await axios.post( `https://www.runninghub.cn${endpoint}`, - { prompt: input.prompt, resolution: input.size, aspectRatio: input.aspectRatio, ...(imageUrls.length > 0 && { imageUrls }) }, + { prompt: fullPrompt, resolution: input.size, aspectRatio: input.aspectRatio, ...(imageUrls.length > 0 && { imageUrls }) }, { headers: { Authorization: "Bearer " + apiKey } }, ); const taskId = taskRes.data.taskId; diff --git a/src/utils/ai/image/owned/volcengine.ts b/src/utils/ai/image/owned/volcengine.ts index 919dbfb..d6a0458 100644 --- a/src/utils/ai/image/owned/volcengine.ts +++ b/src/utils/ai/image/owned/volcengine.ts @@ -18,9 +18,11 @@ export default async (input: ImageConfig, config: AIConfig): Promise => "4K": "2304x4096", }, }; + const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt; + const body: Record = { model: config.model, - prompt: input.prompt, + prompt: fullPrompt, size: sizeMap[input.aspectRatio][size], response_format: "url", sequential_image_generation: "disabled", diff --git a/src/utils/ai/text/index.ts b/src/utils/ai/text/index.ts index 3dd97f7..a967cec 100644 --- a/src/utils/ai/text/index.ts +++ b/src/utils/ai/text/index.ts @@ -30,7 +30,7 @@ const buildOptions = async (input: AIInput, config: AIConfig = {}) => { if (manufacturer == "other") { owned = modelList.find((m) => m.manufacturer === manufacturer); } else { - owned = modelList.find((m) => m.model === model); + owned = modelList.find((m) => m.model === model && m.manufacturer === manufacturer); if (!owned) owned = modelList.find((m) => m.manufacturer === manufacturer); } if (!owned) throw new Error("不支持的厂商"); @@ -54,7 +54,7 @@ const buildOptions = async (input: AIInput, config: AIConfig = {}) => { }; const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null; - const chatModelManufacturer = ["volcengine", "other", "openai", "modelScope"]; + const chatModelManufacturer = ["volcengine", "other", "openai", "modelScope","grsai"]; const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!); return { diff --git a/src/utils/ai/text/modelList.ts b/src/utils/ai/text/modelList.ts index a3c102c..c80edfe 100644 --- a/src/utils/ai/text/modelList.ts +++ b/src/utils/ai/text/modelList.ts @@ -30,13 +30,12 @@ const instanceMap = { openai: createOpenAI, zhipu: createZhipu, qwen: createQwen, - gemini: createGoogleGenerativeAI, - anthropic: createAnthropic, modelScope: (options: OpenAIProviderSettings) => createOpenAI({ ...options, headers: { ...options?.headers, "X-ModelScope-Async-Mode": "true" } }), xai: createXai, other: createOpenAI, + grsai:createOpenAI }; const modelList: Owned[] = [ // DeepSeek diff --git a/src/utils/ai/video/index.ts b/src/utils/ai/video/index.ts index 1524b07..6a7d07e 100644 --- a/src/utils/ai/video/index.ts +++ b/src/utils/ai/video/index.ts @@ -11,7 +11,7 @@ import runninghub from "./owned/runninghub"; import gemini from "./owned/gemini"; import apimart from "./owned/apimart"; import other from "./owned/other"; - +import grsai from "./owned/grsai"; const modelInstance = { volcengine: volcengine, kling: kling, @@ -20,7 +20,8 @@ const modelInstance = { gemini: gemini, runninghub: runninghub, apimart: apimart, - // other: other, + other: other, + grsai:grsai } as const; export default async (input: VideoConfig, config?: AIConfig) => { diff --git a/src/utils/ai/video/owned/grsai.ts b/src/utils/ai/video/owned/grsai.ts new file mode 100644 index 0000000..3121c38 --- /dev/null +++ b/src/utils/ai/video/owned/grsai.ts @@ -0,0 +1,76 @@ +import "../type"; +import fs from "fs"; +import path from "path"; +import axios from "axios"; +import { pollTask, validateVideoConfig } from "@/utils/ai/utils"; + +const buildInlineImage = (data: string) => ({ inlineData: { mimeType: "image/png", data } }); + +export default async (input: VideoConfig, config: AIConfig) => { + if (!config.model) throw new Error("缺少Model名称"); + if (!config.apiKey) throw new Error("缺少API Key"); + + // const { owned, images, hasStartEndType } = validateVideoConfig(input, config); + + const defaultBaseUrl = ["https://grsai.dakka.com.cn/v1/video/{model}", "https://grsai.dakka.com.cn/v1/draw/result"].join("|"); + + const [submitUrl, queryUrl] = (config.baseURL || defaultBaseUrl).split("|"); + + const headers = { Authorization: "Bearer " + config.apiKey }; + let inputObj: Record = {}; + let taskUrl = submitUrl.replace("{model}", config.model); + if (config.model.includes("veo")) { + inputObj = { + model: config.model, + prompt: input.prompt, + firstFrameUrl: "", + lastFrameUrl: "", + aspectRatio: input.aspectRatio, + webHook: "-1", + }; + inputObj.firstFrameUrl = input.imageBase64?.[0] ?? ""; + inputObj.lastFrameUrl = input.imageBase64?.[1] ?? ""; + + taskUrl = submitUrl.replace("{model}", "veo"); + } else { + inputObj = { + model: config.model, + prompt: input.prompt, + url: "", + aspectRatio: input.aspectRatio, + duration: +input.duration, + webHook: "-1", + }; + inputObj.url = input.imageBase64?.[0] ?? ""; + + taskUrl = submitUrl.replace("{model}", "sora-video"); + } + + const { data } = await axios.post(taskUrl, { ...inputObj }, { headers: { ...headers, "Content-Type": "application/json" } }); + + if (data.code != 0) throw new Error(`任务提交失败: ${data ? JSON.stringify(data, null, 2) : "未知错误"}`); + + return await pollTask(async () => { + const { data: queryData } = await axios.post( + queryUrl, + { + id: data.data.id, + }, + { + headers: { Authorization: `Bearer ${config.apiKey}` }, + }, + ); + if (queryData.code != 0) throw new Error(`查询任务失败: ${queryData ? JSON.stringify(queryData, null, 2) : "未知错误"}`); + const { status, error, failure_reason, url } = queryData.data || {}; + + if (status === "failed") { + return { completed: false, error: failure_reason + "\n" + error || "图片生成失败" }; + } + + if (status === "succeeded") { + return { completed: true, url: url }; + } + + return { completed: false }; + }); +}; diff --git a/src/utils/ai/video/owned/other.ts b/src/utils/ai/video/owned/other.ts index 3d4004d..fdc2f86 100644 --- a/src/utils/ai/video/owned/other.ts +++ b/src/utils/ai/video/owned/other.ts @@ -4,12 +4,11 @@ import sharp from "sharp"; import FormData from "form-data"; import { pollTask, validateVideoConfig } from "@/utils/ai/utils"; import { createOpenAI } from "@ai-sdk/openai"; - +import { experimental_generateVideo as generateVideo } from "ai"; export default async (input: VideoConfig, config: AIConfig) => { if (!config.apiKey) throw new Error("缺少API Key"); if (!config.baseURL) throw new Error("缺少baseURL"); // const { owned, images, hasTextType } = validateVideoConfig(input, config); - const [requestUrl, queryUrl] = config.baseURL.split("|"); const authorization = `Bearer ${config.apiKey}`; @@ -21,30 +20,40 @@ export default async (input: VideoConfig, config: AIConfig) => { // 根据 aspectRatio 设置 size const sizeMap: Record = { - "16:9": "1920x1080", - "9:16": "1080x1920", + "16:9": "1280x720", + "9:16": "720x1280", }; formData.append("size", sizeMap[input.aspectRatio] || "1920x1080"); + if (input.imageBase64 && input.imageBase64.length) { const base64Data = input.imageBase64[0]!.replace(/^data:image\/\w+;base64,/, ""); const buffer = Buffer.from(base64Data, "base64"); formData.append("input_reference", buffer, { filename: "image.jpg", contentType: "image/jpeg" }); } - const { data } = await axios.post(requestUrl, formData, { - headers: { "Content-Type": "application/json", Authorization: authorization, ...formData.getHeaders() }, - }); - if (data.status === "FAILED") throw new Error(`任务提交失败: ${data.errorMessage || "未知错误"}`); - const taskId = data.id; - return await pollTask(async () => { - const { data } = await axios.get(`${queryUrl.replace("{id}", taskId)}`, { - headers: { Authorization: authorization }, - }); - if (data.status === "SUCCESS") { - return data.results?.length ? { completed: true, url: data.results[0].url } : { completed: false, error: "任务成功但未返回视频链接" }; - } - if (data.status === "FAILED") return { completed: false, error: `任务失败: ${data.errorMessage || "未知错误"}` }; - if (data.status === "QUEUED" || data.status === "RUNNING") return { completed: false }; - return { completed: false, error: `未知状态: ${data.status}` }; - }); + const body = { + model: config.model, + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: input.prompt, + }, + ], + }, + ], + }; + const { data } = await axios.post( + config.baseURL, + { ...body }, + { + headers: { "Content-Type": "application/json", Authorization: authorization }, + }, + ); + + console.log("%c Line:49 🥓 data", "background:#ffdd4d", data); + + if (data.status === "FAILED") throw new Error(`任务提交失败: ${data.errorMessage || "未知错误"}`); }; From 9e13c8378de24c33af1f8f3984ed68fee42e5e25 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Sat, 28 Feb 2026 22:15:38 +0800 Subject: [PATCH 15/17] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=88=901.0.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 43 +- electron-builder.yml | 32 +- scripts/main.ts | 31 +- scripts/web/index.html | 2556 ++++++++++++++++++------ src/app.ts | 15 +- src/lib/fixDB.ts | 23 +- src/lib/initDB.ts | 76 +- src/types/database.d.ts | 3 +- src/utils/ai/video/owned/volcengine.ts | 10 +- 9 files changed, 2061 insertions(+), 728 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c6a118e..b45e4b6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,8 +78,41 @@ jobs: dist/*.zip retention-days: 30 + build-linux: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "24" + cache: "yarn" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build application + run: yarn build + + - name: Build Linux installer + run: yarn dist:linux + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: linux-builds + path: | + dist/*.AppImage + dist/*.deb + retention-days: 30 + release: - needs: [build-windows, build-macos] + needs: [build-windows, build-macos, build-linux] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') @@ -99,6 +132,12 @@ jobs: name: macos-builds path: dist + - name: Download Linux artifacts + uses: actions/download-artifact@v4 + with: + name: linux-builds + path: dist + - name: Create Release uses: softprops/action-gh-release@v2 with: @@ -110,5 +149,7 @@ jobs: dist/*.exe dist/*.zip dist/*.dmg + dist/*.AppImage + dist/*.deb env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/electron-builder.yml b/electron-builder.yml index 0ebf062..ec20581 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -24,8 +24,14 @@ asar: true win: target: - - nsis - - portable + - target: nsis + arch: + - x64 + - arm64 + - target: portable + arch: + - x64 + - arm64 icon: ./scripts/logo.ico artifactName: ${productName}-${version}-${os}-${arch}.${ext} @@ -34,22 +40,34 @@ nsis: allowToChangeInstallationDirectory: true perMachine: true shortcutName: ${productName} - artifactName: ${productName}-Setup-${version}.${ext} + artifactName: ${productName}-Setup-${version}-${arch}.${ext} installerIcon: './scripts/logo.ico' uninstallerIcon: './scripts/logo.ico' mac: target: - - dmg - - zip + - target: dmg + arch: + - x64 + - arm64 + - target: zip + arch: + - x64 + - arm64 icon: ./scripts/logo.icns category: public.app-category.developer-tools artifactName: ${productName}-${version}-${os}-${arch}.${ext} linux: target: - - AppImage - - deb + - target: AppImage + arch: + - x64 + - arm64 + - target: deb + arch: + - x64 + - arm64 icon: ./scripts/logo.png category: Development artifactName: ${productName}-${version}-${os}-${arch}.${ext} diff --git a/scripts/main.ts b/scripts/main.ts index a97fb0e..d39b1c9 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -1,8 +1,12 @@ import { app, BrowserWindow } from "electron"; import path from "path"; import startServe, { closeServe } from "src/app"; +import { number } from "zod"; -function createMainWindow(): void { +// 默认端口配置 +const defaultPort = 60000; + +function createMainWindow(port: any): void { const win = new BrowserWindow({ width: 900, height: 600, @@ -14,14 +18,28 @@ function createMainWindow(): void { const htmlPath = isDev ? path.join(process.cwd(), "scripts", "web", "index.html") : path.join(app.getAppPath(), "scripts", "web", "index.html"); - void win.loadFile(htmlPath); + + // 使用实际端口构建地址 + const baseUrl = `http://localhost:${port}`; + const wsBaseUrl = `ws://localhost:${port}`; + + // 构建带有 query 参数的 URL + const url = new URL(`file://${htmlPath}`); + url.searchParams.set("baseUrl", baseUrl); + url.searchParams.set("wsBaseUrl", wsBaseUrl); + + console.log("%c Line:30 🥓 url", "background:#33a5ff", url.toString()); + + void win.loadURL(url.toString()); } app.whenReady().then(async () => { - createMainWindow(); try { - await startServe(); + const port = await startServe(false); + createMainWindow(60000); } catch (err) { console.error("[服务启动失败]:", err); + // 如果服务启动失败,使用默认端口创建窗口 + createMainWindow(defaultPort); } }); @@ -30,7 +48,10 @@ app.on("window-all-closed", () => { }); app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) createMainWindow(); + if (BrowserWindow.getAllWindows().length === 0) { + // 重新激活时使用默认端口 + createMainWindow(defaultPort); + } }); app.on("before-quit", async (event) => { diff --git a/scripts/web/index.html b/scripts/web/index.html index f3e04d1..9d58ef3 100644 --- a/scripts/web/index.html +++ b/scripts/web/index.html @@ -1,60 +1,1296 @@ - + - - - + + + Toonflow - - +`)}else he.securityLevel!=="loose"&&(Oi=oA().sanitize(Oi,{ADD_TAGS:["foreignobject"],ADD_ATTR:["dominant-baseline"]}));if(P!==void 0)switch(An){case"flowchart":case"flowchart-v2":P(Oi,Wa.bindFunctions);break;case"gantt":P(Oi,Zk.bindFunctions);break;case"class":case"classDiagram":P(Oi,u0.bindFunctions);break;default:P(Oi)}else a.debug("CB = undefined!");fe.forEach(function(Ln){Ln()}),fe=[];var Kn=he.securityLevel==="sandbox"?"#i"+b:"#d"+b,Rn=pr(Kn).node();return Rn!==null&&typeof Rn.remove=="function"&&pr(Kn).node().remove(),Oi},parse:function(b){b+=` +`;var w=Ai(),P=ga.detectInit(b,w);P&&a.info("reinit ",P);var G,$=ga.detectType(b,w);switch(a.debug("Type "+$),$){case"gitGraph":I5.clear(),(G=UO()).parser.yy=I5;break;case"flowchart":case"flowchart-v2":Wa.clear(),(G=Ix()).parser.yy=Wa;break;case"sequence":q.clear(),(G=$O()).parser.yy=q;break;case"gantt":(G=Lne()).parser.yy=Zk;break;case"class":case"classDiagram":(G=fz()).parser.yy=u0;break;case"state":case"stateDiagram":(G=np()).parser.yy=Md;break;case"info":a.debug("info info info"),(G=YO()).parser.yy=B5;break;case"pie":a.debug("pie"),(G=N5()).parser.yy=qO;break;case"er":a.debug("er"),(G=yx()).parser.yy=Fu;break;case"journey":a.debug("Journey"),(G=Mat()).parser.yy=f8e;break;case"requirement":case"requirementDiagram":a.debug("RequirementDiagram"),(G=Mne()).parser.yy=D3}return G.parser.yy.graphType=$,G.parser.yy.parseError=function(de,he){throw{str:de,hash:he}},G.parse(b),G},parseDirective:function(b,w,P,G){try{if(w!==void 0)switch(w=w.trim(),P){case"open_directive":ip={};break;case"type_directive":ip.type=w.toLowerCase();break;case"arg_directive":ip.args=JSON.parse(w);break;case"close_directive":(function($,de,he){switch(a.debug("Directive type=".concat(de.type," with args:"),de.args),de.type){case"init":case"initialize":["config"].forEach(function(we){de.args[we]!==void 0&&(he==="flowchart-v2"&&(he="flowchart"),de.args[he]=de.args[we],delete de.args[we])}),a.debug("sanitize in handleDirective",de.args),dA(de.args),a.debug("sanitize in handleDirective (done)",de.args),de.args,cO(de.args);break;case"wrap":case"nowrap":$&&$.setWrap&&$.setWrap(de.type==="wrap");break;case"themeCss":a.warn("themeCss encountered");break;default:a.warn("Unhandled directive: source: '%%{".concat(de.type,": ").concat(JSON.stringify(de.args?de.args:{}),"}%%"),de)}})(b,ip,G),ip=null}}catch($){a.error("Error while rendering sequenceDiagram directive: ".concat(w," jison context: ").concat(P)),a.error($.message)}},initialize:function(b){b&&b.fontFamily&&(b.themeVariables&&b.themeVariables.fontFamily||(b.themeVariables={fontFamily:b.fontFamily})),function(P){Vk=xd({},P)}(b),b&&b.theme&&_k[b.theme]?b.themeVariables=_k[b.theme].getThemeVariables(b.themeVariables):b&&(b.themeVariables=_k.default.getThemeVariables(b.themeVariables));var w=Wne(b)==="object"?function(P){return ud=xd({},L5),ud=xd(ud,P),P.theme&&_k[P.theme]&&(ud.themeVariables=_k[P.theme].getThemeVariables(P.themeVariables)),E5=ux(ud,x5),ud}(b):sO();y8e(w),s(w.logLevel)},reinitialize:function(){},getConfig:Ai,setConfig:function(b){return xd(E5,b),Ai()},getSiteConfig:sO,updateSiteConfig:function(b){return ud=xd(ud,b),ux(ud,x5),ud},reset:function(){fA()},globalReset:function(){fA(),y8e(Ai())},defaultConfig:L5});s(Ai().logLevel),fA(Ai());const Td=Pat;var Bat=function(){var b,w,P=Td.getConfig();arguments.length>=2?(arguments[0]!==void 0&&(a2.sequenceConfig=arguments[0]),b=arguments[1]):b=arguments[0],typeof arguments[arguments.length-1]=="function"?(w=arguments[arguments.length-1],a.debug("Callback function found")):P.mermaid!==void 0&&(typeof P.mermaid.callback=="function"?(w=P.mermaid.callback,a.debug("Callback function found")):a.debug("No Callback function found")),b=b===void 0?document.querySelectorAll(".mermaid"):typeof b=="string"?document.querySelectorAll(b):b instanceof window.Node?[b]:b,a.debug("Start On Load before: "+a2.startOnLoad),a2.startOnLoad!==void 0&&(a.debug("Start On Load inner: "+a2.startOnLoad),Td.updateSiteConfig({startOnLoad:a2.startOnLoad})),a2.ganttConfig!==void 0&&Td.updateSiteConfig({gantt:a2.ganttConfig});for(var G,$=new ga.initIdGeneratior(P.deterministicIds,P.deterministicIDSeed),de=function(we){var Te=b[we];if(Te.getAttribute("data-processed"))return"continue";Te.setAttribute("data-processed",!0);var Me="mermaid-".concat($.next());G=Te.innerHTML,G=ga.entityDecode(G).trim().replace(//gi,"
");var Je=ga.detectInit(G);Je&&a.debug("Detected early reinit: ",Je),Td.render(Me,G,function(gt,mt){Te.innerHTML=gt,w!==void 0&&w(Me),mt&&mt(Te)},Te)},he=0;he{e.exports={graphlib:n(6614),dagre:n(1463),intersect:n(8114),render:n(5787),util:n(8355),version:n(5689)}},9144:(e,t,n)=>{var i=n(8355);function r(l,a,s,c){var u=l.append("marker").attr("id",a).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").style("stroke-width",1).style("stroke-dasharray","1,0");i.applyStyle(u,s[c+"Style"]),s[c+"Class"]&&u.attr("class",s[c+"Class"])}e.exports={default:r,normal:r,vee:function(l,a,s,c){var u=l.append("marker").attr("id",a).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 L 4 5 z").style("stroke-width",1).style("stroke-dasharray","1,0");i.applyStyle(u,s[c+"Style"]),s[c+"Class"]&&u.attr("class",s[c+"Class"])},undirected:function(l,a,s,c){var u=l.append("marker").attr("id",a).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 5 L 10 5").style("stroke-width",1).style("stroke-dasharray","1,0");i.applyStyle(u,s[c+"Style"]),s[c+"Class"]&&u.attr("class",s[c+"Class"])}}},5632:(e,t,n)=>{var i=n(8355),r=n(4322),l=n(1322);e.exports=function(a,s){var c,u=s.nodes().filter(function(f){return i.isSubgraph(s,f)}),d=a.selectAll("g.cluster").data(u,function(f){return f});return d.selectAll("*").remove(),d.enter().append("g").attr("class","cluster").attr("id",function(f){return s.node(f).id}).style("opacity",0),d=a.selectAll("g.cluster"),i.applyTransition(d,s).style("opacity",1),d.each(function(f){var h=s.node(f),k=r.select(this);r.select(this).append("rect");var v=k.append("g").attr("class","label");l(v,h,h.clusterLabelPos)}),d.selectAll("rect").each(function(f){var h=s.node(f),k=r.select(this);i.applyStyle(k,h.style)}),c=d.exit?d.exit():d.selectAll(null),i.applyTransition(c,s).style("opacity",0).remove(),d}},6315:(e,t,n)=>{var i=n(1034),r=n(1322),l=n(8355),a=n(4322);e.exports=function(s,c){var u,d=s.selectAll("g.edgeLabel").data(c.edges(),function(f){return l.edgeToId(f)}).classed("update",!0);return d.exit().remove(),d.enter().append("g").classed("edgeLabel",!0).style("opacity",0),(d=s.selectAll("g.edgeLabel")).each(function(f){var h=a.select(this);h.select(".label").remove();var k=c.edge(f),v=r(h,c.edge(f),0,0).classed("label",!0),g=v.node().getBBox();k.labelId&&v.attr("id",k.labelId),i.has(k,"width")||(k.width=g.width),i.has(k,"height")||(k.height=g.height)}),u=d.exit?d.exit():d.selectAll(null),l.applyTransition(u,c).style("opacity",0).remove(),d}},940:(e,t,n)=>{var i=n(1034),r=n(3042),l=n(8355),a=n(4322);function s(c,u){var d=(a.line||a.svg.line)().x(function(f){return f.x}).y(function(f){return f.y});return(d.curve||d.interpolate)(c.curve),d(u)}e.exports=function(c,u,d){var f=c.selectAll("g.edgePath").data(u.edges(),function(v){return l.edgeToId(v)}).classed("update",!0),h=function(v,g){var m=v.enter().append("g").attr("class","edgePath").style("opacity",0);return m.append("path").attr("class","path").attr("d",function(C){var A=g.edge(C),y=g.node(C.v).elem;return s(A,i.range(A.points.length).map(function(){return E=(x=y).getBBox(),{x:(S=x.ownerSVGElement.getScreenCTM().inverse().multiply(x.getScreenCTM()).translate(E.width/2,E.height/2)).e,y:S.f};var x,E,S}))}),m.append("defs"),m}(f,u);(function(v,g){var m=v.exit();l.applyTransition(m,g).style("opacity",0).remove()})(f,u);var k=f.merge!==void 0?f.merge(h):f;return l.applyTransition(k,u).style("opacity",1),k.each(function(v){var g=a.select(this),m=u.edge(v);m.elem=this,m.id&&g.attr("id",m.id),l.applyClass(g,m.class,(g.classed("update")?"update ":"")+"edgePath")}),k.selectAll("path.path").each(function(v){var g=u.edge(v);g.arrowheadId=i.uniqueId("arrowhead");var m=a.select(this).attr("marker-end",function(){return"url("+(C=location.href,A=g.arrowheadId,C.split("#")[0]+"#"+A+")");var C,A}).style("fill","none");l.applyTransition(m,u).attr("d",function(C){return function(A,y){var x=A.edge(y),E=A.node(y.v),S=A.node(y.w),M=x.points.slice(1,x.points.length-1);return M.unshift(r(E,M[0])),M.push(r(S,M[M.length-1])),s(x,M)}(u,C)}),l.applyStyle(m,g.style)}),k.selectAll("defs *").remove(),k.selectAll("defs").each(function(v){var g=u.edge(v);(0,d[g.arrowhead])(a.select(this),g.arrowheadId,g,"arrowhead")}),k}},607:(e,t,n)=>{var i=n(1034),r=n(1322),l=n(8355),a=n(4322);e.exports=function(s,c,u){var d,f=c.nodes().filter(function(k){return!l.isSubgraph(c,k)}),h=s.selectAll("g.node").data(f,function(k){return k}).classed("update",!0);return h.exit().remove(),h.enter().append("g").attr("class","node").style("opacity",0),(h=s.selectAll("g.node")).each(function(k){var v=c.node(k),g=a.select(this);l.applyClass(g,v.class,(g.classed("update")?"update ":"")+"node"),g.select("g.label").remove();var m=g.append("g").attr("class","label"),C=r(m,v),A=u[v.shape],y=i.pick(C.node().getBBox(),"width","height");v.elem=this,v.id&&g.attr("id",v.id),v.labelId&&m.attr("id",v.labelId),i.has(v,"width")&&(y.width=v.width),i.has(v,"height")&&(y.height=v.height),y.width+=v.paddingLeft+v.paddingRight,y.height+=v.paddingTop+v.paddingBottom,m.attr("transform","translate("+(v.paddingLeft-v.paddingRight)/2+","+(v.paddingTop-v.paddingBottom)/2+")");var x=a.select(this);x.select(".label-container").remove();var E=A(x,y,v).classed("label-container",!0);l.applyStyle(E,v.style);var S=E.node().getBBox();v.width=S.width,v.height=S.height}),d=h.exit?h.exit():h.selectAll(null),l.applyTransition(d,c).style("opacity",0).remove(),h}},4322:(e,t,n)=>{var i;if(!i)try{i=n(7188)}catch{}i||(i=window.d3),e.exports=i},1463:(e,t,n)=>{var i;try{i=n(681)}catch{}i||(i=window.dagre),e.exports=i},6614:(e,t,n)=>{var i;try{i=n(8282)}catch{}i||(i=window.graphlib),e.exports=i},8114:(e,t,n)=>{e.exports={node:n(3042),circle:n(6587),ellipse:n(3260),polygon:n(5337),rect:n(8049)}},6587:(e,t,n)=>{var i=n(3260);e.exports=function(r,l,a){return i(r,l,l,a)}},3260:e=>{e.exports=function(t,n,i,r){var l=t.x,a=t.y,s=l-r.x,c=a-r.y,u=Math.sqrt(n*n*c*c+i*i*s*s),d=Math.abs(n*i*s/u);r.x{function t(n,i){return n*i>0}e.exports=function(n,i,r,l){var a,s,c,u,d,f,h,k,v,g,m,C,A;if(a=i.y-n.y,c=n.x-i.x,d=i.x*n.y-n.x*i.y,v=a*r.x+c*r.y+d,g=a*l.x+c*l.y+d,!(v!==0&&g!==0&&t(v,g)||(s=l.y-r.y,u=r.x-l.x,f=l.x*r.y-r.x*l.y,h=s*n.x+u*n.y+f,k=s*i.x+u*i.y+f,h!==0&&k!==0&&t(h,k)||(m=a*u-s*c)==0)))return C=Math.abs(m/2),{x:(A=c*f-u*d)<0?(A-C)/m:(A+C)/m,y:(A=s*d-a*f)<0?(A-C)/m:(A+C)/m}}},3042:e=>{e.exports=function(t,n){return t.intersect(n)}},5337:(e,t,n)=>{var i=n(6808);e.exports=function(r,l,a){var s=r.x,c=r.y,u=[],d=Number.POSITIVE_INFINITY,f=Number.POSITIVE_INFINITY;l.forEach(function(A){d=Math.min(d,A.x),f=Math.min(f,A.y)});for(var h=s-r.width/2-d,k=c-r.height/2-f,v=0;v1&&u.sort(function(A,y){var x=A.x-a.x,E=A.y-a.y,S=Math.sqrt(x*x+E*E),M=y.x-a.x,T=y.y-a.y,D=Math.sqrt(M*M+T*T);return S{e.exports=function(t,n){var i,r,l=t.x,a=t.y,s=n.x-l,c=n.y-a,u=t.width/2,d=t.height/2;return Math.abs(c)*u>Math.abs(s)*d?(c<0&&(d=-d),i=c===0?0:d*s/c,r=d):(s<0&&(u=-u),i=u,r=s===0?0:u*c/s),{x:l+i,y:a+r}}},8284:(e,t,n)=>{var i=n(8355);e.exports=function(r,l){var a=r.append("foreignObject").attr("width","100000"),s=a.append("xhtml:div");s.attr("xmlns","http://www.w3.org/1999/xhtml");var c=l.label;switch(typeof c){case"function":s.insert(c);break;case"object":s.insert(function(){return c});break;default:s.html(c)}i.applyStyle(s,l.labelStyle),s.style("display","inline-block"),s.style("white-space","nowrap");var u=s.node().getBoundingClientRect();return a.attr("width",u.width).attr("height",u.height),a}},1322:(e,t,n)=>{var i=n(7318),r=n(8284),l=n(8287);e.exports=function(a,s,c){var u=s.label,d=a.append("g");s.labelType==="svg"?l(d,s):typeof u!="string"||s.labelType==="html"?r(d,s):i(d,s);var f,h=d.node().getBBox();switch(c){case"top":f=-s.height/2;break;case"bottom":f=s.height/2-h.height;break;default:f=-h.height/2}return d.attr("transform","translate("+-h.width/2+","+f+")"),d}},8287:(e,t,n)=>{var i=n(8355);e.exports=function(r,l){var a=r;return a.node().appendChild(l.label),i.applyStyle(a,l.labelStyle),a}},7318:(e,t,n)=>{var i=n(8355);e.exports=function(r,l){for(var a=r.append("text"),s=function(u){for(var d,f="",h=!1,k=0;k{var i;try{i={defaults:n(1747),each:n(6073),isFunction:n(3560),isPlainObject:n(8630),pick:n(9722),has:n(8721),range:n(6026),uniqueId:n(3955)}}catch{}i||(i=window._),e.exports=i},6381:(e,t,n)=>{var i=n(8355),r=n(4322);e.exports=function(l,a){var s=l.filter(function(){return!r.select(this).classed("update")});function c(u){var d=a.node(u);return"translate("+d.x+","+d.y+")"}s.attr("transform",c),i.applyTransition(l,a).style("opacity",1).attr("transform",c),i.applyTransition(s.selectAll("rect"),a).attr("width",function(u){return a.node(u).width}).attr("height",function(u){return a.node(u).height}).attr("x",function(u){return-a.node(u).width/2}).attr("y",function(u){return-a.node(u).height/2})}},4577:(e,t,n)=>{var i=n(8355),r=n(4322),l=n(1034);e.exports=function(a,s){function c(u){var d=s.edge(u);return l.has(d,"x")?"translate("+d.x+","+d.y+")":""}a.filter(function(){return!r.select(this).classed("update")}).attr("transform",c),i.applyTransition(a,s).style("opacity",1).attr("transform",c)}},4849:(e,t,n)=>{var i=n(8355),r=n(4322);e.exports=function(l,a){function s(c){var u=a.node(c);return"translate("+u.x+","+u.y+")"}l.filter(function(){return!r.select(this).classed("update")}).attr("transform",s),i.applyTransition(l,a).style("opacity",1).attr("transform",s)}},5787:(e,t,n)=>{var i=n(1034),r=n(4322),l=n(1463).layout;e.exports=function(){var u=n(607),d=n(5632),f=n(6315),h=n(940),k=n(4849),v=n(4577),g=n(6381),m=n(4418),C=n(9144),A=function(y,x){(function(W){W.nodes().forEach(function(p){var H=W.node(p);i.has(H,"label")||W.children(p).length||(H.label=p),i.has(H,"paddingX")&&i.defaults(H,{paddingLeft:H.paddingX,paddingRight:H.paddingX}),i.has(H,"paddingY")&&i.defaults(H,{paddingTop:H.paddingY,paddingBottom:H.paddingY}),i.has(H,"padding")&&i.defaults(H,{paddingLeft:H.padding,paddingRight:H.padding,paddingTop:H.padding,paddingBottom:H.padding}),i.defaults(H,a),i.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],function(I){H[I]=Number(H[I])}),i.has(H,"width")&&(H._prevWidth=H.width),i.has(H,"height")&&(H._prevHeight=H.height)}),W.edges().forEach(function(p){var H=W.edge(p);i.has(H,"label")||(H.label=""),i.defaults(H,s)})})(x);var E=c(y,"output"),S=c(E,"clusters"),M=c(E,"edgePaths"),T=f(c(E,"edgeLabels"),x),D=u(c(E,"nodes"),x,m);l(x),k(D,x),v(T,x),h(M,x,C);var O=d(S,x);g(O,x),function(W){i.each(W.nodes(),function(p){var H=W.node(p);i.has(H,"_prevWidth")?H.width=H._prevWidth:delete H.width,i.has(H,"_prevHeight")?H.height=H._prevHeight:delete H.height,delete H._prevWidth,delete H._prevHeight})}(x)};return A.createNodes=function(y){return arguments.length?(u=y,A):u},A.createClusters=function(y){return arguments.length?(d=y,A):d},A.createEdgeLabels=function(y){return arguments.length?(f=y,A):f},A.createEdgePaths=function(y){return arguments.length?(h=y,A):h},A.shapes=function(y){return arguments.length?(m=y,A):m},A.arrows=function(y){return arguments.length?(C=y,A):C},A};var a={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},s={arrowhead:"normal",curve:r.curveLinear};function c(u,d){var f=u.select("g."+d);return f.empty()&&(f=u.append("g").attr("class",d)),f}},4418:(e,t,n)=>{var i=n(8049),r=n(3260),l=n(6587),a=n(5337);e.exports={rect:function(s,c,u){var d=s.insert("rect",":first-child").attr("rx",u.rx).attr("ry",u.ry).attr("x",-c.width/2).attr("y",-c.height/2).attr("width",c.width).attr("height",c.height);return u.intersect=function(f){return i(u,f)},d},ellipse:function(s,c,u){var d=c.width/2,f=c.height/2,h=s.insert("ellipse",":first-child").attr("x",-c.width/2).attr("y",-c.height/2).attr("rx",d).attr("ry",f);return u.intersect=function(k){return r(u,d,f,k)},h},circle:function(s,c,u){var d=Math.max(c.width,c.height)/2,f=s.insert("circle",":first-child").attr("x",-c.width/2).attr("y",-c.height/2).attr("r",d);return u.intersect=function(h){return l(u,d,h)},f},diamond:function(s,c,u){var d=c.width*Math.SQRT2/2,f=c.height*Math.SQRT2/2,h=[{x:0,y:-f},{x:-d,y:0},{x:0,y:f},{x:d,y:0}],k=s.insert("polygon",":first-child").attr("points",h.map(function(v){return v.x+","+v.y}).join(" "));return u.intersect=function(v){return a(u,h,v)},k}}},8355:(e,t,n)=>{var i=n(1034);e.exports={isSubgraph:function(a,s){return!!a.children(s).length},edgeToId:function(a){return l(a.v)+":"+l(a.w)+":"+l(a.name)},applyStyle:function(a,s){s&&a.attr("style",s)},applyClass:function(a,s,c){s&&a.attr("class",s).attr("class",c+" "+a.attr("class"))},applyTransition:function(a,s){var c=s.graph();if(i.isPlainObject(c)){var u=c.transition;if(i.isFunction(u))return u(a)}return a}};var r=/:/g;function l(a){return a?String(a).replace(r,"\\:"):""}},5689:e=>{e.exports="0.6.4"},7188:(e,t,n)=>{n.r(t),n.d(t,{FormatSpecifier:()=>Ik,active:()=>y7,arc:()=>Wm,area:()=>Ex,areaRadial:()=>LO,ascending:()=>r,autoType:()=>O$,axisBottom:()=>Be,axisLeft:()=>Fe,axisRight:()=>Pe,axisTop:()=>Re,bisect:()=>u,bisectLeft:()=>c,bisectRight:()=>s,bisector:()=>l,blob:()=>Y$,brush:()=>rm,brushSelection:()=>eC,brushX:()=>l3,brushY:()=>Vf,buffer:()=>Q$,chord:()=>st,clientPoint:()=>Sk,cluster:()=>Kee,color:()=>Xc,contourDensity:()=>yD,contours:()=>S7,create:()=>fne,creator:()=>zt,cross:()=>h,csv:()=>K$,csvFormat:()=>UR,csvFormatBody:()=>GR,csvFormatRow:()=>x$,csvFormatRows:()=>L$,csvFormatValue:()=>E$,csvParse:()=>VR,csvParseRows:()=>y$,cubehelix:()=>zs,curveBasis:()=>DO,curveBasisClosed:()=>TA,curveBasisOpen:()=>jO,curveBundle:()=>OO,curveCardinal:()=>Rx,curveCardinalClosed:()=>pO,curveCardinalOpen:()=>zz,curveCatmullRom:()=>IO,curveCatmullRomClosed:()=>_z,curveCatmullRomOpen:()=>p5,curveLinear:()=>f1,curveLinearClosed:()=>Vz,curveMonotoneX:()=>m1,curveMonotoneY:()=>Lne,curveNatural:()=>Gz,curveStep:()=>Fx,curveStepAfter:()=>b1,curveStepBefore:()=>xne,customEvent:()=>yo,descending:()=>k,deviation:()=>m,dispatch:()=>et,drag:()=>w$,dragDisable:()=>ya,dragEnable:()=>gl,dsv:()=>q$,dsvFormat:()=>M7,easeBack:()=>oH,easeBackIn:()=>iH,easeBackInOut:()=>oH,easeBackOut:()=>V$,easeBounce:()=>tC,easeBounceIn:()=>nH,easeBounceInOut:()=>_$,easeBounceOut:()=>tC,easeCircle:()=>tH,easeCircleIn:()=>z$,easeCircleInOut:()=>tH,easeCircleOut:()=>F$,easeCubic:()=>l4,easeCubicIn:()=>I9,easeCubicInOut:()=>l4,easeCubicOut:()=>P9,easeElastic:()=>rH,easeElasticIn:()=>U$,easeElasticInOut:()=>G$,easeElasticOut:()=>rH,easeExp:()=>eH,easeExpIn:()=>H$,easeExpInOut:()=>eH,easeExpOut:()=>W$,easeLinear:()=>QR,easePoly:()=>KR,easePolyIn:()=>qR,easePolyInOut:()=>KR,easePolyOut:()=>B$,easeQuad:()=>ZR,easeQuadIn:()=>I$,easeQuadInOut:()=>ZR,easeQuadOut:()=>P$,easeSin:()=>xD,easeSinIn:()=>N$,easeSinInOut:()=>xD,easeSinOut:()=>R$,entries:()=>_r,event:()=>Yn,extent:()=>C,forceCenter:()=>fH,forceCollide:()=>oee,forceLink:()=>lee,forceManyBody:()=>see,forceRadial:()=>cee,forceSimulation:()=>aee,forceX:()=>uee,forceY:()=>dee,format:()=>X9,formatDefaultLocale:()=>AH,formatLocale:()=>CH,formatPrefix:()=>I7,formatSpecifier:()=>nC,geoAlbers:()=>qH,geoAlbersUsa:()=>Wee,geoArea:()=>kee,geoAzimuthalEqualArea:()=>zee,geoAzimuthalEqualAreaRaw:()=>dj,geoAzimuthalEquidistant:()=>Fee,geoAzimuthalEquidistantRaw:()=>fj,geoBounds:()=>TH,geoCentroid:()=>VD,geoCircle:()=>yee,geoClipAntimeridian:()=>J7,geoClipCircle:()=>PH,geoClipExtent:()=>xee,geoClipRectangle:()=>AC,geoConicConformal:()=>Vee,geoConicConformalRaw:()=>$H,geoConicEqualArea:()=>yL,geoConicEqualAreaRaw:()=>ZH,geoConicEquidistant:()=>Gee,geoConicEquidistantRaw:()=>eW,geoContains:()=>jee,geoDistance:()=>iL,geoEqualEarth:()=>Yee,geoEqualEarthRaw:()=>hj,geoEquirectangular:()=>Uee,geoEquirectangularRaw:()=>u5,geoGnomonic:()=>gj,geoGnomonicRaw:()=>kj,geoGraticule:()=>FH,geoGraticule10:()=>Oee,geoIdentity:()=>Xee,geoInterpolate:()=>pee,geoLength:()=>QD,geoMercator:()=>_ee,geoMercatorRaw:()=>BC,geoNaturalEarth1:()=>tW,geoNaturalEarth1Raw:()=>vj,geoOrthographic:()=>nW,geoOrthographicRaw:()=>xL,geoPath:()=>b3,geoProjection:()=>h4,geoProjectionMutator:()=>wL,geoRotation:()=>q7,geoStereographic:()=>Qee,geoStereographicRaw:()=>mj,geoStream:()=>$1,geoTransform:()=>mL,geoTransverseMercator:()=>Zee,geoTransverseMercatorRaw:()=>bj,gray:()=>pl,hcl:()=>au,hierarchy:()=>Cj,histogram:()=>_,hsl:()=>Zn,html:()=>$$,image:()=>cH,interpolate:()=>G1,interpolateArray:()=>Nc,interpolateBasis:()=>no,interpolateBasisClosed:()=>mo,interpolateBlues:()=>rne,interpolateBrBG:()=>kA,interpolateBuGn:()=>ene,interpolateBuPu:()=>tne,interpolateCividis:()=>cne,interpolateCool:()=>Uk,interpolateCubehelix:()=>Em,interpolateCubehelixDefault:()=>bA,interpolateCubehelixLong:()=>Sm,interpolateDate:()=>o4,interpolateDiscrete:()=>IL,interpolateGnBu:()=>T5,interpolateGreens:()=>mx,interpolateGreys:()=>lne,interpolateHcl:()=>zC,interpolateHclLong:()=>FC,interpolateHsl:()=>mte,interpolateHslLong:()=>PL,interpolateHue:()=>vte,interpolateInferno:()=>dne,interpolateLab:()=>WC,interpolateMagma:()=>tf,interpolateNumber:()=>Ya,interpolateNumberArray:()=>ru,interpolateObject:()=>U1,interpolateOrRd:()=>nne,interpolateOranges:()=>wz,interpolatePRGn:()=>fx,interpolatePiYG:()=>gO,interpolatePlasma:()=>Ax,interpolatePuBu:()=>gx,interpolatePuBuGn:()=>bO,interpolatePuOr:()=>gA,interpolatePuRd:()=>ine,interpolatePurples:()=>ane,interpolateRainbow:()=>bx,interpolateRdBu:()=>dz,interpolateRdGy:()=>Jte,interpolateRdPu:()=>one,interpolateRdYlBu:()=>$te,interpolateRdYlGn:()=>S3,interpolateReds:()=>sne,interpolateRgb:()=>Yr,interpolateRgbBasis:()=>Bc,interpolateRgbBasisClosed:()=>ps,interpolateRound:()=>xj,interpolateSinebow:()=>Lz,interpolateSpectral:()=>hz,interpolateString:()=>vf,interpolateTransformCss:()=>Fb,interpolateTransformSvg:()=>_b,interpolateTurbo:()=>une,interpolateViridis:()=>Cx,interpolateWarm:()=>CA,interpolateYlGn:()=>zu,interpolateYlGnBu:()=>xh,interpolateYlOrBr:()=>Es,interpolateYlOrRd:()=>vz,interpolateZoom:()=>AW,interrupt:()=>od,interval:()=>_x,isoFormat:()=>Eh,isoParse:()=>pA,json:()=>J$,keys:()=>Fr,lab:()=>ws,lch:()=>Au,line:()=>EA,lineRadial:()=>Ox,linkHorizontal:()=>mne,linkRadial:()=>bne,linkVertical:()=>Oz,local:()=>Ez,map:()=>pi,matcher:()=>ot,max:()=>U,mean:()=>Q,median:()=>Y,merge:()=>J,min:()=>Z,mouse:()=>Hf,namespace:()=>ut,namespaces:()=>ft,nest:()=>so,now:()=>Ht,pack:()=>ote,packEnclose:()=>oW,packSiblings:()=>ite,pairs:()=>d,partition:()=>rte,path:()=>Mn,permute:()=>K,pie:()=>Tx,piecewise:()=>VC,pointRadial:()=>MA,polygonArea:()=>Sj,polygonCentroid:()=>bte,polygonContains:()=>Tj,polygonHull:()=>Cte,polygonLength:()=>LW,precisionFixed:()=>wH,precisionPrefix:()=>yH,precisionRound:()=>LH,quadtree:()=>j7,quantile:()=>j,quantize:()=>wW,radialArea:()=>LO,radialLine:()=>Ox,randomBates:()=>r0,randomExponential:()=>w3,randomIrwinHall:()=>o0,randomLogNormal:()=>Dj,randomNormal:()=>UC,randomUniform:()=>Ate,range:()=>M,rgb:()=>ac,ribbon:()=>In,scaleBand:()=>pj,scaleDiverging:()=>sz,scaleDivergingLog:()=>cO,scaleDivergingPow:()=>hA,scaleDivergingSqrt:()=>uO,scaleDivergingSymlog:()=>fA,scaleIdentity:()=>TW,scaleImplicit:()=>jj,scaleLinear:()=>MW,scaleLog:()=>HL,scaleOrdinal:()=>Oj,scalePoint:()=>Ij,scalePow:()=>FL,scaleQuantile:()=>zj,scaleQuantize:()=>_L,scaleSequential:()=>L5,scaleSequentialLog:()=>ud,scaleSequentialPow:()=>E5,scaleSequentialQuantile:()=>sO,scaleSequentialSqrt:()=>ux,scaleSequentialSymlog:()=>x5,scaleSqrt:()=>IW,scaleSymlog:()=>zL,scaleThreshold:()=>VL,scaleTime:()=>xd,scaleUtc:()=>ga,scan:()=>te,schemeAccent:()=>c0,schemeBlues:()=>mA,schemeBrBG:()=>S5,schemeBuGn:()=>hx,schemeBuPu:()=>kz,schemeCategory10:()=>m4,schemeDark2:()=>b4,schemeGnBu:()=>mO,schemeGreens:()=>mz,schemeGreys:()=>AO,schemeOrRd:()=>kx,schemeOranges:()=>Az,schemePRGn:()=>dx,schemePaired:()=>C4,schemePastel1:()=>A4,schemePastel2:()=>dO,schemePiYG:()=>kO,schemePuBu:()=>vA,schemePuBuGn:()=>Lh,schemePuOr:()=>uz,schemePuRd:()=>CO,schemePurples:()=>bz,schemeRdBu:()=>vO,schemeRdGy:()=>u0,schemeRdPu:()=>gz,schemeRdYlBu:()=>M5,schemeRdYlGn:()=>Wu,schemeReds:()=>Cz,schemeSet1:()=>fO,schemeSet2:()=>hO,schemeSet3:()=>dd,schemeSpectral:()=>fz,schemeTableau10:()=>cz,schemeYlGn:()=>wf,schemeYlGnBu:()=>vx,schemeYlOrBr:()=>w4,schemeYlOrRd:()=>l2,select:()=>nl,selectAll:()=>Sz,selection:()=>Cl,selector:()=>Ot,selectorAll:()=>yt,set:()=>zr,shuffle:()=>ae,stack:()=>f0,stackOffsetDiverging:()=>jA,stackOffsetExpand:()=>Yz,stackOffsetNone:()=>of,stackOffsetSilhouette:()=>Xz,stackOffsetWiggle:()=>Qz,stackOrderAppearance:()=>zO,stackOrderAscending:()=>FO,stackOrderDescending:()=>VO,stackOrderInsideOut:()=>I5,stackOrderNone:()=>Kk,stackOrderReverse:()=>Ene,stratify:()=>cte,style:()=>Xt,sum:()=>ie,svg:()=>MD,symbol:()=>TO,symbolCircle:()=>EO,symbolCross:()=>pz,symbolDiamond:()=>Pz,symbolSquare:()=>Rz,symbolStar:()=>Nz,symbolTriangle:()=>Hz,symbolWye:()=>MO,symbols:()=>yne,text:()=>D7,thresholdFreedmanDiaconis:()=>B,thresholdScott:()=>N,thresholdSturges:()=>I,tickFormat:()=>SW,tickIncrement:()=>p,tickStep:()=>H,ticks:()=>W,timeDay:()=>x3,timeDays:()=>GW,timeFormat:()=>$L,timeFormatDefaultLocale:()=>Hm,timeFormatLocale:()=>XW,timeFriday:()=>zW,timeFridays:()=>Rk,timeHour:()=>Uj,timeHours:()=>Ste,timeInterval:()=>sd,timeMillisecond:()=>eA,timeMilliseconds:()=>tA,timeMinute:()=>Gj,timeMinutes:()=>Yj,timeMonday:()=>$C,timeMondays:()=>Lte,timeMonth:()=>BW,timeMonths:()=>yte,timeParse:()=>Nm,timeSaturday:()=>FW,timeSaturdays:()=>Ete,timeSecond:()=>m5,timeSeconds:()=>b5,timeSunday:()=>JC,timeSundays:()=>_W,timeThursday:()=>L3,timeThursdays:()=>VW,timeTuesday:()=>HW,timeTuesdays:()=>xte,timeWednesday:()=>WW,timeWednesdays:()=>Nk,timeWeek:()=>JC,timeWeeks:()=>_W,timeYear:()=>Tm,timeYears:()=>wte,timeout:()=>mr,timer:()=>Ki,timerFlush:()=>uo,touch:()=>Zc,touches:()=>Mz,transition:()=>p9,transpose:()=>le,tree:()=>hte,treemap:()=>kte,treemapBinary:()=>gte,treemapDice:()=>HC,treemapResquarify:()=>bW,treemapSlice:()=>pL,treemapSliceDice:()=>i0,treemapSquarify:()=>mW,tsv:()=>sH,tsvFormat:()=>S$,tsvFormatBody:()=>M$,tsvFormatRow:()=>D$,tsvFormatRows:()=>T$,tsvFormatValue:()=>j$,tsvParse:()=>YR,tsvParseRows:()=>XR,utcDay:()=>JL,utcDays:()=>Tte,utcFormat:()=>ex,utcFriday:()=>xu,utcFridays:()=>qL,utcHour:()=>cx,utcHours:()=>lz,utcMillisecond:()=>eA,utcMilliseconds:()=>tA,utcMinute:()=>dA,utcMinutes:()=>az,utcMonday:()=>E3,utcMondays:()=>Mte,utcMonth:()=>rz,utcMonths:()=>Kte,utcParse:()=>oA,utcSaturday:()=>pm,utcSaturdays:()=>Qj,utcSecond:()=>m5,utcSeconds:()=>b5,utcSunday:()=>nA,utcSundays:()=>QL,utcThursday:()=>Ld,utcThursdays:()=>ZL,utcTuesday:()=>Om,utcTuesdays:()=>a0,utcWednesday:()=>Xj,utcWednesdays:()=>Im,utcWeek:()=>nA,utcWeeks:()=>QL,utcYear:()=>Pm,utcYears:()=>Dte,values:()=>Jo,variance:()=>g,version:()=>i,voronoi:()=>NA,window:()=>Ut,xml:()=>dH,zip:()=>ke,zoom:()=>tp,zoomIdentity:()=>Ym,zoomTransform:()=>ep});var i="5.16.0";function r(L,R){return LR?1:L>=R?0:NaN}function l(L){var R;return L.length===1&&(R=L,L=function(X,q){return r(R(X),q)}),{left:function(X,q,fe,be){for(fe==null&&(fe=0),be==null&&(be=X.length);fe>>1;L(X[Se],q)<0?fe=Se+1:be=Se}return fe},right:function(X,q,fe,be){for(fe==null&&(fe=0),be==null&&(be=X.length);fe>>1;L(X[Se],q)>0?be=Se:fe=Se+1}return fe}}}var a=l(r),s=a.right,c=a.left;const u=s;function d(L,R){R==null&&(R=f);for(var X=0,q=L.length-1,fe=L[0],be=new Array(q<0?0:q);XL?1:R>=L?0:NaN}function v(L){return L===null?NaN:+L}function g(L,R){var X,q,fe=L.length,be=0,Se=-1,Ee=0,Oe=0;if(R==null)for(;++Se1)return Oe/(be-1)}function m(L,R){var X=g(L,R);return X&&Math.sqrt(X)}function C(L,R){var X,q,fe,be=L.length,Se=-1;if(R==null){for(;++Se=X)for(q=fe=X;++SeX&&(q=X),fe=X)for(q=fe=X;++SeX&&(q=X),fe0)return[L];if((q=R0)for(L=Math.ceil(L/Se),R=Math.floor(R/Se),be=new Array(fe=Math.ceil(R-L+1));++Ee=0?(be>=T?10:be>=D?5:be>=O?2:1)*Math.pow(10,fe):-Math.pow(10,-fe)/(be>=T?10:be>=D?5:be>=O?2:1)}function H(L,R,X){var q=Math.abs(R-L)/Math.max(0,X),fe=Math.pow(10,Math.floor(Math.log(q)/Math.LN10)),be=q/fe;return be>=T?fe*=10:be>=D?fe*=5:be>=O&&(fe*=2),Rvt;)nt.pop(),--It;var Nt,Jt=new Array(It+1);for(be=0;be<=It;++be)(Nt=Jt[be]=[]).x0=be>0?nt[be-1]:rt,Nt.x1=be=1)return+X(L[q-1],q-1,L);var q,fe=(q-1)*R,be=Math.floor(fe),Se=+X(L[be],be,L);return Se+(+X(L[be+1],be+1,L)-Se)*(fe-be)}}function B(L,R,X){return L=x.call(L,v).sort(r),Math.ceil((X-R)/(2*(j(L,.75)-j(L,.25))*Math.pow(L.length,-1/3)))}function N(L,R,X){return Math.ceil((X-R)/(3.5*m(L)*Math.pow(L.length,-1/3)))}function U(L,R){var X,q,fe=L.length,be=-1;if(R==null){for(;++be=X)for(q=X;++beq&&(q=X)}else for(;++be=X)for(q=X;++beq&&(q=X);return q}function Q(L,R){var X,q=L.length,fe=q,be=-1,Se=0;if(R==null)for(;++be=0;)for(R=(q=L[fe]).length;--R>=0;)X[--Se]=q[R];return X}function Z(L,R){var X,q,fe=L.length,be=-1;if(R==null){for(;++be=X)for(q=X;++beX&&(q=X)}else for(;++be=X)for(q=X;++beX&&(q=X);return q}function K(L,R){for(var X=R.length,q=new Array(X);X--;)q[X]=L[R[X]];return q}function te(L,R){if(X=L.length){var X,q,fe=0,be=0,Se=L[be];for(R==null&&(R=r);++fe=0&&(q=X.slice(fe+1),X=X.slice(0,fe)),X&&!R.hasOwnProperty(X))throw new Error("unknown type: "+X);return{type:X,name:q}})}function dt(L,R){for(var X,q=0,fe=L.length;q0)for(var X,q,fe=new Array(X),be=0;beR?1:L>=R?0:NaN}at.prototype={constructor:at,appendChild:function(L){return this._parent.insertBefore(L,this._next)},insertBefore:function(L,R){return this._parent.insertBefore(L,R)},querySelector:function(L){return this._parent.querySelector(L)},querySelectorAll:function(L){return this._parent.querySelectorAll(L)}};var Ye="http://www.w3.org/1999/xhtml";const ft={svg:"http://www.w3.org/2000/svg",xhtml:Ye,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function ut(L){var R=L+="",X=R.indexOf(":");return X>=0&&(R=L.slice(0,X))!=="xmlns"&&(L=L.slice(X+1)),ft.hasOwnProperty(R)?{space:ft[R],local:L}:L}function Dt(L){return function(){this.removeAttribute(L)}}function Ft(L){return function(){this.removeAttributeNS(L.space,L.local)}}function At(L,R){return function(){this.setAttribute(L,R)}}function bt(L,R){return function(){this.setAttributeNS(L.space,L.local,R)}}function Qe(L,R){return function(){var X=R.apply(this,arguments);X==null?this.removeAttribute(L):this.setAttribute(L,X)}}function wt(L,R){return function(){var X=R.apply(this,arguments);X==null?this.removeAttributeNS(L.space,L.local):this.setAttributeNS(L.space,L.local,X)}}function Ut(L){return L.ownerDocument&&L.ownerDocument.defaultView||L.document&&L||L.defaultView}function Zt(L){return function(){this.style.removeProperty(L)}}function $t(L,R,X){return function(){this.style.setProperty(L,R,X)}}function Yt(L,R,X){return function(){var q=R.apply(this,arguments);q==null?this.style.removeProperty(L):this.style.setProperty(L,q,X)}}function Xt(L,R){return L.style.getPropertyValue(R)||Ut(L).getComputedStyle(L,null).getPropertyValue(R)}function mn(L){return function(){delete this[L]}}function En(L,R){return function(){this[L]=R}}function ti(L,R){return function(){var X=R.apply(this,arguments);X==null?delete this[L]:this[L]=X}}function wi(L){return L.trim().split(/^|\s+/)}function to(L){return L.classList||new Ni(L)}function Ni(L){this._node=L,this._names=wi(L.getAttribute("class")||"")}function sn(L,R){for(var X=to(L),q=-1,fe=R.length;++q=0&&(this._names.splice(R,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(L){return this._names.indexOf(L)>=0}};var ci={},Yn=null;function si(L,R,X){return L=Wi(L,R,X),function(q){var fe=q.relatedTarget;fe&&(fe===this||8&fe.compareDocumentPosition(this))||L.call(this,q)}}function Wi(L,R,X){return function(q){var fe=Yn;Yn=q;try{L.call(this,this.__data__,R,X)}finally{Yn=fe}}}function wn(L){return L.trim().split(/^|\s+/).map(function(R){var X="",q=R.indexOf(".");return q>=0&&(X=R.slice(q+1),R=R.slice(0,q)),{type:R,name:X}})}function Bo(L){return function(){var R=this.__on;if(R){for(var X,q=0,fe=-1,be=R.length;q=fi&&(fi=Dn+1);!(un=Vt[fi])&&++fi=0;)(q=fe[be])&&(Se&&4^q.compareDocumentPosition(Se)&&Se.parentNode.insertBefore(q,Se),Se=q);return this},sort:function(L){function R(vt,nt){return vt&&nt?L(vt.__data__,nt.__data__):!vt-!nt}L||(L=Ge);for(var X=this._groups,q=X.length,fe=new Array(q),be=0;be1?this.each((R==null?Zt:typeof R=="function"?Yt:$t)(L,R,X??"")):Xt(this.node(),L)},property:function(L,R){return arguments.length>1?this.each((R==null?mn:typeof R=="function"?ti:En)(L,R)):this.node()[L]},classed:function(L,R){var X=wi(L+"");if(arguments.length<2){for(var q=to(this.node()),fe=-1,be=X.length;++fe>8&15|R>>4&240,R>>4&15|240&R,(15&R)<<4|15&R,1):X===8?ja(R>>24&255,R>>16&255,R>>8&255,(255&R)/255):X===4?ja(R>>12&15|R>>8&240,R>>8&15|R>>4&240,R>>4&15|240&R,((15&R)<<4|15&R)/255):null):(R=po.exec(L))?new La(R[1],R[2],R[3],1):(R=lo.exec(L))?new La(255*R[1]/100,255*R[2]/100,255*R[3]/100,1):(R=ll.exec(L))?ja(R[1],R[2],R[3],R[4]):(R=vl.exec(L))?ja(255*R[1]/100,255*R[2]/100,255*R[3]/100,R[4]):(R=wl.exec(L))?xc(R[1],R[2]/100,R[3]/100,1):(R=ul.exec(L))?xc(R[1],R[2]/100,R[3]/100,R[4]):Js.hasOwnProperty(L)?Pc(Js[L]):L==="transparent"?new La(NaN,NaN,NaN,0):null}function Pc(L){return new La(L>>16&255,L>>8&255,255&L,1)}function ja(L,R,X,q){return q<=0&&(L=R=X=NaN),new La(L,R,X,q)}function ou(L){return L instanceof Al||(L=Xc(L)),L?new La((L=L.rgb()).r,L.g,L.b,L.opacity):new La}function ac(L,R,X,q){return arguments.length===1?ou(L):new La(L,R,X,q??1)}function La(L,R,X,q){this.r=+L,this.g=+R,this.b=+X,this.opacity=+q}function Gd(){return"#"+Yd(this.r)+Yd(this.g)+Yd(this.b)}function Qc(){var L=this.opacity;return((L=isNaN(L)?1:Math.max(0,Math.min(1,L)))===1?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(L===1?")":", "+L+")")}function Yd(L){return((L=Math.max(0,Math.min(255,Math.round(L)||0)))<16?"0":"")+L.toString(16)}function xc(L,R,X,q){return q<=0?L=R=X=NaN:X<=0||X>=1?L=R=NaN:R<=0&&(L=NaN),new ui(L,R,X,q)}function Rt(L){if(L instanceof ui)return new ui(L.h,L.s,L.l,L.opacity);if(L instanceof Al||(L=Xc(L)),!L)return new ui;if(L instanceof ui)return L;var R=(L=L.rgb()).r/255,X=L.g/255,q=L.b/255,fe=Math.min(R,X,q),be=Math.max(R,X,q),Se=NaN,Ee=be-fe,Oe=(be+fe)/2;return Ee?(Se=R===be?(X-q)/Ee+6*(X0&&Oe<1?0:Se,new ui(Se,Ee,Oe,L.opacity)}function Zn(L,R,X,q){return arguments.length===1?Rt(L):new ui(L,R,X,q??1)}function ui(L,R,X,q){this.h=+L,this.s=+R,this.l=+X,this.opacity=+q}function ei(L,R,X){return 255*(L<60?R+(X-R)*L/60:L<180?X:L<240?R+(X-R)*(240-L)/60:R)}function Ao(L,R,X,q,fe){var be=L*L,Se=be*L;return((1-3*L+3*be-Se)*R+(4-6*be+3*Se)*X+(1+3*L+3*be-3*Se)*q+Se*fe)/6}function no(L){var R=L.length-1;return function(X){var q=X<=0?X=0:X>=1?(X=1,R-1):Math.floor(X*R),fe=L[q],be=L[q+1],Se=q>0?L[q-1]:2*fe-be,Ee=q180||X<-180?X-360*Math.round(X/360):X):So(isNaN(L)?R:L)}function kr(L,R){var X=R-L;return X?Si(L,X):So(isNaN(L)?R:L)}na(Al,Xc,{copy:function(L){return Object.assign(new this.constructor,this,L)},displayable:function(){return this.rgb().displayable()},hex:oa,formatHex:oa,formatHsl:function(){return Rt(this).formatHsl()},formatRgb:qa,toString:qa}),na(La,ac,ia(Al,{brighter:function(L){return L=L==null?ns:Math.pow(ns,L),new La(this.r*L,this.g*L,this.b*L,this.opacity)},darker:function(L){return L=L==null?Ul:Math.pow(Ul,L),new La(this.r*L,this.g*L,this.b*L,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Gd,formatHex:Gd,formatRgb:Qc,toString:Qc})),na(ui,Zn,ia(Al,{brighter:function(L){return L=L==null?ns:Math.pow(ns,L),new ui(this.h,this.s,this.l*L,this.opacity)},darker:function(L){return L=L==null?Ul:Math.pow(Ul,L),new ui(this.h,this.s,this.l*L,this.opacity)},rgb:function(){var L=this.h%360+360*(this.h<0),R=isNaN(L)||isNaN(this.s)?0:this.s,X=this.l,q=X+(X<.5?X:1-X)*R,fe=2*X-q;return new La(ei(L>=240?L-240:L+120,fe,q),ei(L,fe,q),ei(L<120?L+240:L-120,fe,q),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var L=this.opacity;return((L=isNaN(L)?1:Math.max(0,Math.min(1,L)))===1?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(L===1?")":", "+L+")")}}));const Yr=function L(R){var X=function(fe){return(fe=+fe)==1?kr:function(be,Se){return Se-be?function(Ee,Oe,Ue){return Ee=Math.pow(Ee,Ue),Oe=Math.pow(Oe,Ue)-Ee,Ue=1/Ue,function(rt){return Math.pow(Ee+rt*Oe,Ue)}}(be,Se,fe):So(isNaN(be)?Se:be)}}(R);function q(fe,be){var Se=X((fe=ac(fe)).r,(be=ac(be)).r),Ee=X(fe.g,be.g),Oe=X(fe.b,be.b),Ue=kr(fe.opacity,be.opacity);return function(rt){return fe.r=Se(rt),fe.g=Ee(rt),fe.b=Oe(rt),fe.opacity=Ue(rt),fe+""}}return q.gamma=L,q}(1);function Ga(L){return function(R){var X,q,fe=R.length,be=new Array(fe),Se=new Array(fe),Ee=new Array(fe);for(X=0;Xbe&&(fe=R.slice(be,fe),Ee[Se]?Ee[Se]+=fe:Ee[++Se]=fe),(X=X[0])===(q=q[0])?Ee[Se]?Ee[Se]+=q:Ee[++Se]=q:(Ee[++Se]=null,Oe.push({i:Se,x:Ya(X,q)})),be=r4.lastIndex;return be=0&&R._call.call(null,L),R=R._next;--Nu}function Qo(){Ru=(Xd=pe.now())+Kl,Nu=Rc=0;try{uo()}finally{Nu=0,function(){for(var L,R,X=gh,q=1/0;X;)X._call?(q>X._time&&(q=X._time),L=X,X=X._next):(R=X._next,X._next=null,X=L?L._next=R:gh=R);Wf=L,nr(q)}(),Ru=0}}function qo(){var L=pe.now(),R=L-Xd;R>1e3&&(Kl-=R,Xd=L)}function nr(L){Nu||(Rc&&(Rc=clearTimeout(Rc)),L-Ru>24?(L<1/0&&(Rc=setTimeout(Qo,L-pe.now()-Kl)),mf&&(mf=clearInterval(mf))):(mf||(Xd=pe.now(),mf=setInterval(qo,1e3)),Nu=1,ht(Qo)))}function mr(L,R,X){var q=new xi;return R=R==null?0:+R,q.restart(function(fe){q.stop(),L(fe+R)},R,X),q}xi.prototype=Ki.prototype={constructor:xi,restart:function(L,R,X){if(typeof L!="function")throw new TypeError("callback is not a function");X=(X==null?Ht():+X)+(R==null?0:+R),this._next||Wf===this||(Wf?Wf._next=this:gh=this,Wf=this),this._call=L,this._time=X,nr()},stop:function(){this._call&&(this._call=null,this._time=1/0,nr())}};var kl=et("start","end","cancel","interrupt"),Jr=[];function Xa(L,R,X,q,fe,be){var Se=L.__transition;if(Se){if(X in Se)return}else L.__transition={};(function(Ee,Oe,Ue){var rt,vt=Ee.__transition;function nt(Jt){var Kt,Vt,gn,un;if(Ue.state!==1)return Nt();for(Kt in vt)if((un=vt[Kt]).name===Ue.name){if(un.state===3)return mr(nt);un.state===4?(un.state=6,un.timer.stop(),un.on.call("interrupt",Ee,Ee.__data__,un.index,un.group),delete vt[Kt]):+Kt0)throw new Error("too late; already scheduled");return X}function ds(L,R){var X=Ra(L,R);if(X.state>3)throw new Error("too late; already running");return X}function Ra(L,R){var X=L.__transition;if(!X||!(X=X[R]))throw new Error("transition not found");return X}function od(L,R){var X,q,fe,be=L.__transition,Se=!0;if(be){for(fe in R=R==null?null:R+"",be)(X=be[fe]).name===R?(q=X.state>2&&X.state<5,X.state=6,X.timer.stop(),X.on.call(q?"interrupt":"cancel",L,L.__data__,X.index,X.group),delete be[fe]):Se=!1;Se&&delete L.__transition}}var Y1,i1,Jv,$v,vh=180/Math.PI,em={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function i3(L,R,X,q,fe,be){var Se,Ee,Oe;return(Se=Math.sqrt(L*L+R*R))&&(L/=Se,R/=Se),(Oe=L*X+R*q)&&(X-=L*Oe,q-=R*Oe),(Ee=Math.sqrt(X*X+q*q))&&(X/=Ee,q/=Ee,Oe/=Ee),L*q180?rt+=360:rt-Ue>180&&(Ue+=360),nt.push({i:vt.push(fe(vt)+"rotate(",null,q)-2,x:Ya(Ue,rt)})):rt&&vt.push(fe(vt)+"rotate("+rt+q)}(be.rotate,Se.rotate,Ee,Oe),function(Ue,rt,vt,nt){Ue!==rt?nt.push({i:vt.push(fe(vt)+"skewX(",null,q)-2,x:Ya(Ue,rt)}):rt&&vt.push(fe(vt)+"skewX("+rt+q)}(be.skewX,Se.skewX,Ee,Oe),function(Ue,rt,vt,nt,It,Nt){if(Ue!==vt||rt!==nt){var Jt=It.push(fe(It)+"scale(",null,",",null,")");Nt.push({i:Jt-4,x:Ya(Ue,vt)},{i:Jt-2,x:Ya(rt,nt)})}else vt===1&&nt===1||It.push(fe(It)+"scale("+vt+","+nt+")")}(be.scaleX,be.scaleY,Se.scaleX,Se.scaleY,Ee,Oe),be=Se=null,function(Ue){for(var rt,vt=-1,nt=Oe.length;++vt=0&&(Ee=Ee.slice(0,Oe)),!Ee||Ee==="start"})}(R)?sa:ds;return function(){var Se=be(this,L),Ee=Se.on;Ee!==q&&(fe=(q=Ee).copy()).on(R,X),Se.on=fe}}var Cu=Cl.prototype.constructor;function o1(L){return function(){this.style.removeProperty(L)}}function X1(L,R,X){return function(q){this.style.setProperty(L,R.call(this,q),X)}}function j9(L,R,X){var q,fe;function be(){var Se=R.apply(this,arguments);return Se!==fe&&(q=(fe=Se)&&X1(L,Se,X)),q}return be._value=R,be}function O9(L){return function(R){this.textContent=L.call(this,R)}}function bD(L){var R,X;function q(){var fe=L.apply(this,arguments);return fe!==X&&(R=(X=fe)&&O9(fe)),R}return q._value=L,q}var CD=0;function Q1(L,R,X,q){this._groups=L,this._parents=R,this._name=X,this._id=q}function p9(L){return Cl().transition(L)}function Zb(){return++CD}var Z1=Cl.prototype;function I9(L){return L*L*L}function P9(L){return--L*L*L+1}function l4(L){return((L*=2)<=1?L*L*L:(L-=2)*L*L+2)/2}Q1.prototype=p9.prototype={constructor:Q1,select:function(L){var R=this._name,X=this._id;typeof L!="function"&&(L=Ot(L));for(var q=this._groups,fe=q.length,be=new Array(fe),Se=0;Se1&&X.name===R)return new Q1([[L]],Tk,R,+q)}return null}function _f(L){return function(){return L}}function s4(L,R,X){this.target=L,this.type=R,this.selection=X}function B9(){Yn.stopImmediatePropagation()}function qb(){Yn.preventDefault(),Yn.stopImmediatePropagation()}var L7={},N9={name:"space"},q1={name:"handle"},Dk={name:"center"};function r1(L){return[+L[0],+L[1]]}function K1(L){return[r1(L[0]),r1(L[1])]}function om(L){return function(R){return Zc(R,Yn.touches,L)}}var R9={name:"x",handles:["w","e"].map(Qd),input:function(L,R){return L==null?null:[[+L[0],R[0][1]],[+L[1],R[1][1]]]},output:function(L){return L&&[L[0][0],L[1][0]]}},c4={name:"y",handles:["n","s"].map(Qd),input:function(L,R){return L==null?null:[[R[0][0],+L[0]],[R[1][0],+L[1]]]},output:function(L){return L&&[L[0][1],L[1][1]]}},rd={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Qd),input:function(L){return L==null?null:K1(L)},output:function(L){return L}},l1={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Kb={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},H9={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},x7={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},E7={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Qd(L){return{type:L}}function W9(){return!Yn.ctrlKey&&!Yn.button}function z9(){var L=this.ownerSVGElement||this;return L.hasAttribute("viewBox")?[[(L=L.viewBox.baseVal).x,L.y],[L.x+L.width,L.y+L.height]]:[[0,0],[L.width.baseVal.value,L.height.baseVal.value]]}function Jb(){return navigator.maxTouchPoints||"ontouchstart"in this}function F9(L){for(;!L.__brush;)if(!(L=L.parentNode))return;return L.__brush}function $b(L){return L[0][0]===L[1][0]||L[0][1]===L[1][1]}function eC(L){var R=L.__brush;return R?R.dim.output(R.selection):null}function l3(){return jk(R9)}function Vf(){return jk(c4)}function rm(){return jk(rd)}function jk(L){var R,X=z9,q=W9,fe=Jb,be=!0,Se=et("start","brush","end"),Ee=6;function Oe(Kt){var Vt=Kt.property("__brush",Jt).selectAll(".overlay").data([Qd("overlay")]);Vt.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",l1.overlay).merge(Vt).each(function(){var un=F9(this).extent;nl(this).attr("x",un[0][0]).attr("y",un[0][1]).attr("width",un[1][0]-un[0][0]).attr("height",un[1][1]-un[0][1])}),Kt.selectAll(".selection").data([Qd("selection")]).enter().append("rect").attr("class","selection").attr("cursor",l1.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var gn=Kt.selectAll(".handle").data(L.handles,function(un){return un.type});gn.exit().remove(),gn.enter().append("rect").attr("class",function(un){return"handle handle--"+un.type}).attr("cursor",function(un){return l1[un.type]}),Kt.each(Ue).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",nt).filter(fe).on("touchstart.brush",nt).on("touchmove.brush",It).on("touchend.brush touchcancel.brush",Nt).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function Ue(){var Kt=nl(this),Vt=F9(this).selection;Vt?(Kt.selectAll(".selection").style("display",null).attr("x",Vt[0][0]).attr("y",Vt[0][1]).attr("width",Vt[1][0]-Vt[0][0]).attr("height",Vt[1][1]-Vt[0][1]),Kt.selectAll(".handle").style("display",null).attr("x",function(gn){return gn.type[gn.type.length-1]==="e"?Vt[1][0]-Ee/2:Vt[0][0]-Ee/2}).attr("y",function(gn){return gn.type[0]==="s"?Vt[1][1]-Ee/2:Vt[0][1]-Ee/2}).attr("width",function(gn){return gn.type==="n"||gn.type==="s"?Vt[1][0]-Vt[0][0]+Ee:Ee}).attr("height",function(gn){return gn.type==="e"||gn.type==="w"?Vt[1][1]-Vt[0][1]+Ee:Ee})):Kt.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function rt(Kt,Vt,gn){var un=Kt.__brush.emitter;return!un||gn&&un.clean?new vt(Kt,Vt,gn):un}function vt(Kt,Vt,gn){this.that=Kt,this.args=Vt,this.state=Kt.__brush,this.active=0,this.clean=gn}function nt(){if((!R||Yn.touches)&&q.apply(this,arguments)){var Kt,Vt,gn,un,Dn,fi,Mi,Ri,wo,vi,Ji,Tn=this,Qn=Yn.target.__data__.type,zi=(be&&Yn.metaKey?Qn="overlay":Qn)==="selection"?L7:be&&Yn.altKey?Dk:q1,Pi=L===c4?null:x7[Qn],Gi=L===R9?null:E7[Qn],or=F9(Tn),Lr=or.extent,ml=or.selection,Ei=Lr[0][0],Ro=Lr[0][1],Wr=Lr[1][0],za=Lr[1][1],Dl=0,El=0,Ka=Pi&&Gi&&be&&Yn.shiftKey,Sd=Yn.touches?om(Yn.changedTouches[0].identifier):Hf,Kc=Sd(Tn),x4=Kc,Mh=rt(Tn,arguments,!0).beforestart();Qn==="overlay"?(ml&&(wo=!0),or.selection=ml=[[Kt=L===c4?Ei:Kc[0],gn=L===R9?Ro:Kc[1]],[Dn=L===c4?Wr:Kt,Mi=L===R9?za:gn]]):(Kt=ml[0][0],gn=ml[0][1],Dn=ml[1][0],Mi=ml[1][1]),Vt=Kt,un=gn,fi=Dn,Ri=Mi;var FA=nl(Tn).attr("pointer-events","none"),tg=FA.selectAll(".overlay").attr("cursor",l1[Qn]);if(Yn.touches)Mh.moved=np,Mh.ended=_A;else{var F5=nl(Yn.view).on("mousemove.brush",np,!0).on("mouseup.brush",_A,!0);be&&F5.on("keydown.brush",Ux,!0).on("keyup.brush",jne,!0),ya(Yn.view)}B9(),od(Tn),Ue.call(Tn),Mh.start()}function np(){var qf=Sd(Tn);!Ka||vi||Ji||(Math.abs(qf[0]-x4[0])>Math.abs(qf[1]-x4[1])?Ji=!0:vi=!0),x4=qf,wo=!0,qb(),j3()}function j3(){var qf;switch(Dl=x4[0]-Kc[0],El=x4[1]-Kc[1],zi){case N9:case L7:Pi&&(Dl=Math.max(Ei-Kt,Math.min(Wr-Dn,Dl)),Vt=Kt+Dl,fi=Dn+Dl),Gi&&(El=Math.max(Ro-gn,Math.min(za-Mi,El)),un=gn+El,Ri=Mi+El);break;case q1:Pi<0?(Dl=Math.max(Ei-Kt,Math.min(Wr-Kt,Dl)),Vt=Kt+Dl,fi=Dn):Pi>0&&(Dl=Math.max(Ei-Dn,Math.min(Wr-Dn,Dl)),Vt=Kt,fi=Dn+Dl),Gi<0?(El=Math.max(Ro-gn,Math.min(za-gn,El)),un=gn+El,Ri=Mi):Gi>0&&(El=Math.max(Ro-Mi,Math.min(za-Mi,El)),un=gn,Ri=Mi+El);break;case Dk:Pi&&(Vt=Math.max(Ei,Math.min(Wr,Kt-Dl*Pi)),fi=Math.max(Ei,Math.min(Wr,Dn+Dl*Pi))),Gi&&(un=Math.max(Ro,Math.min(za,gn-El*Gi)),Ri=Math.max(Ro,Math.min(za,Mi+El*Gi)))}fi0&&(Kt=Vt-Dl),Gi<0?Mi=Ri-El:Gi>0&&(gn=un-El),zi=N9,tg.attr("cursor",l1.selection),j3());break;default:return}qb()}function jne(){switch(Yn.keyCode){case 16:Ka&&(vi=Ji=Ka=!1,j3());break;case 18:zi===Dk&&(Pi<0?Dn=fi:Pi>0&&(Kt=Vt),Gi<0?Mi=Ri:Gi>0&&(gn=un),zi=q1,j3());break;case 32:zi===N9&&(Yn.altKey?(Pi&&(Dn=fi-Dl*Pi,Kt=Vt+Dl*Pi),Gi&&(Mi=Ri-El*Gi,gn=un+El*Gi),zi=Dk):(Pi<0?Dn=fi:Pi>0&&(Kt=Vt),Gi<0?Mi=Ri:Gi>0&&(gn=un),zi=q1),tg.attr("cursor",l1[Qn]),j3());break;default:return}qb()}}function It(){rt(this,arguments).moved()}function Nt(){rt(this,arguments).ended()}function Jt(){var Kt=this.__brush||{selection:null};return Kt.extent=K1(X.apply(this,arguments)),Kt.dim=L,Kt}return Oe.move=function(Kt,Vt){Kt.selection?Kt.on("start.brush",function(){rt(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){rt(this,arguments).end()}).tween("brush",function(){var gn=this,un=gn.__brush,Dn=rt(gn,arguments),fi=un.selection,Mi=L.input(typeof Vt=="function"?Vt.apply(this,arguments):Vt,un.extent),Ri=G1(fi,Mi);function wo(vi){un.selection=vi===1&&Mi===null?null:Ri(vi),Ue.call(gn),Dn.brush()}return fi!==null&&Mi!==null?wo:wo(1)}):Kt.each(function(){var gn=this,un=arguments,Dn=gn.__brush,fi=L.input(typeof Vt=="function"?Vt.apply(gn,un):Vt,Dn.extent),Mi=rt(gn,un).beforestart();od(gn),Dn.selection=fi===null?null:fi,Ue.call(gn),Mi.start().brush().end()})},Oe.clear=function(Kt){Oe.move(Kt,null)},vt.prototype={beforestart:function(){return++this.active==1&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return--this.active==0&&(delete this.state.emitter,this.emit("end")),this},emit:function(Kt){yo(new s4(Oe,Kt,L.output(this.state.selection)),Se.apply,Se,[Kt,this.that,this.args])}},Oe.extent=function(Kt){return arguments.length?(X=typeof Kt=="function"?Kt:_f(K1(Kt)),Oe):X},Oe.filter=function(Kt){return arguments.length?(q=typeof Kt=="function"?Kt:_f(!!Kt),Oe):q},Oe.touchable=function(Kt){return arguments.length?(fe=typeof Kt=="function"?Kt:_f(!!Kt),Oe):fe},Oe.handleSize=function(Kt){return arguments.length?(Ee=+Kt,Oe):Ee},Oe.keyModifiers=function(Kt){return arguments.length?(be=!!Kt,Oe):be},Oe.on=function(){var Kt=Se.on.apply(Se,arguments);return Kt===Se?Oe:Kt},Oe}var _9=Math.cos,a3=Math.sin,u4=Math.PI,me=u4/2,je=2*u4,ze=Math.max;function $e(L){return function(R,X){return L(R.source.value+R.target.value,X.source.value+X.target.value)}}function st(){var L=0,R=null,X=null,q=null;function fe(be){var Se,Ee,Oe,Ue,rt,vt,nt=be.length,It=[],Nt=M(nt),Jt=[],Kt=[],Vt=Kt.groups=new Array(nt),gn=new Array(nt*nt);for(Se=0,rt=-1;++rtGt)if(Math.abs(rt*Ee-Oe*Ue)>Gt&&fe){var nt=X-be,It=q-Se,Nt=Ee*Ee+Oe*Oe,Jt=nt*nt+It*It,Kt=Math.sqrt(Nt),Vt=Math.sqrt(vt),gn=fe*Math.tan((Mt-Math.acos((Nt+vt-Jt)/(2*Kt*Vt)))/2),un=gn/Vt,Dn=gn/Kt;Math.abs(un-1)>Gt&&(this._+="L"+(L+un*Ue)+","+(R+un*rt)),this._+="A"+fe+","+fe+",0,0,"+ +(rt*nt>Ue*It)+","+(this._x1=L+Dn*Ee)+","+(this._y1=R+Dn*Oe)}else this._+="L"+(this._x1=L)+","+(this._y1=R)},arc:function(L,R,X,q,fe,be){L=+L,R=+R,be=!!be;var Se=(X=+X)*Math.cos(q),Ee=X*Math.sin(q),Oe=L+Se,Ue=R+Ee,rt=1^be,vt=be?q-fe:fe-q;if(X<0)throw new Error("negative radius: "+X);this._x1===null?this._+="M"+Oe+","+Ue:(Math.abs(this._x1-Oe)>Gt||Math.abs(this._y1-Ue)>Gt)&&(this._+="L"+Oe+","+Ue),X&&(vt<0&&(vt=vt%Pt+Pt),vt>Qt?this._+="A"+X+","+X+",0,1,"+rt+","+(L-Se)+","+(R-Ee)+"A"+X+","+X+",0,1,"+rt+","+(this._x1=Oe)+","+(this._y1=Ue):vt>Gt&&(this._+="A"+X+","+X+",0,"+ +(vt>=Mt)+","+rt+","+(this._x1=L+X*Math.cos(fe))+","+(this._y1=R+X*Math.sin(fe))))},rect:function(L,R,X,q){this._+="M"+(this._x0=this._x1=+L)+","+(this._y0=this._y1=+R)+"h"+ +X+"v"+ +q+"h"+-X+"Z"},toString:function(){return this._}};const Mn=an;function Pn(L){return L.source}function fn(L){return L.target}function Vn(L){return L.radius}function zn(L){return L.startAngle}function qn(L){return L.endAngle}function In(){var L=Pn,R=fn,X=Vn,q=zn,fe=qn,be=null;function Se(){var Ee,Oe=kt.call(arguments),Ue=L.apply(this,Oe),rt=R.apply(this,Oe),vt=+X.apply(this,(Oe[0]=Ue,Oe)),nt=q.apply(this,Oe)-me,It=fe.apply(this,Oe)-me,Nt=vt*_9(nt),Jt=vt*a3(nt),Kt=+X.apply(this,(Oe[0]=rt,Oe)),Vt=q.apply(this,Oe)-me,gn=fe.apply(this,Oe)-me;if(be||(be=Ee=Mn()),be.moveTo(Nt,Jt),be.arc(0,0,vt,nt,It),nt===Vt&&It===gn||(be.quadraticCurveTo(0,0,Kt*_9(Vt),Kt*a3(Vt)),be.arc(0,0,Kt,Vt,gn)),be.quadraticCurveTo(0,0,Nt,Jt),be.closePath(),Ee)return be=null,Ee+""||null}return Se.radius=function(Ee){return arguments.length?(X=typeof Ee=="function"?Ee:xt(+Ee),Se):X},Se.startAngle=function(Ee){return arguments.length?(q=typeof Ee=="function"?Ee:xt(+Ee),Se):q},Se.endAngle=function(Ee){return arguments.length?(fe=typeof Ee=="function"?Ee:xt(+Ee),Se):fe},Se.source=function(Ee){return arguments.length?(L=Ee,Se):L},Se.target=function(Ee){return arguments.length?(R=Ee,Se):R},Se.context=function(Ee){return arguments.length?(be=Ee??null,Se):be},Se}var kn="$";function ki(){}function Zi(L,R){var X=new ki;if(L instanceof ki)L.each(function(Ee,Oe){X.set(Oe,Ee)});else if(Array.isArray(L)){var q,fe=-1,be=L.length;if(R==null)for(;++fe=q.length)return L!=null&&Ee.sort(L),R!=null?R(Ee):Ee;for(var vt,nt,It,Nt=-1,Jt=Ee.length,Kt=q[Oe++],Vt=pi(),gn=Ue();++Ntq.length)return Ee;var Ue,rt=fe[Oe-1];return R!=null&&Oe>=q.length?Ue=Ee.entries():(Ue=[],Ee.each(function(vt,nt){Ue.push({key:nt,values:Se(vt,Oe)})})),rt!=null?Ue.sort(function(vt,nt){return rt(vt.key,nt.key)}):Ue}return X={object:function(Ee){return be(Ee,0,ko,io)},map:function(Ee){return be(Ee,0,Do,Wo)},entries:function(Ee){return Se(be(Ee,0,Do,Wo),0)},key:function(Ee){return q.push(Ee),X},sortKeys:function(Ee){return fe[q.length-1]=Ee,X},sortValues:function(Ee){return L=Ee,X},rollup:function(Ee){return R=Ee,X}}}function ko(){return{}}function io(L,R,X){L[R]=X}function Do(){return pi()}function Wo(L,R,X){L.set(R,X)}function Hr(){}var er=pi.prototype;function Ir(L,R){var X=new Hr;if(L instanceof Hr)L.each(function(be){X.add(be)});else if(L){var q=-1,fe=L.length;if(R==null)for(;++q.008856451679035631?Math.pow(L,1/3):L/jl+Tl}function ys(L){return L>ua?L*L*L:jl*(L-Tl)}function Ls(L){return 255*(L<=.0031308?12.92*L:1.055*Math.pow(L,1/2.4)-.055)}function Oa(L){return(L/=255)<=.04045?L/12.92:Math.pow((L+.055)/1.055,2.4)}function lu(L){if(L instanceof ka)return new ka(L.h,L.c,L.l,L.opacity);if(L instanceof Bl||(L=Ol(L)),L.a===0&&L.b===0)return new ka(NaN,0q!=It>q&&X<(nt-Ue)*(q-rt)/(It-rt)+Ue&&(fe=-fe)}return fe}function v$(L,R,X){var q,fe,be,Se;return function(Ee,Oe,Ue){return(Oe[0]-Ee[0])*(Ue[1]-Ee[1])==(Ue[0]-Ee[0])*(Oe[1]-Ee[1])}(L,R,X)&&(fe=L[q=+(L[0]===R[0])],be=X[q],Se=R[q],fe<=be&&be<=Se||Se<=be&&be<=fe)}function m$(){}var Ok=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function S7(){var L=1,R=1,X=I,q=Ee;function fe(Oe){var Ue=X(Oe);if(Array.isArray(Ue))Ue=Ue.slice().sort(s3);else{var rt=C(Oe),vt=rt[0],nt=rt[1];Ue=H(vt,nt,Ue),Ue=M(Math.floor(vt/Ue)*Ue,Math.floor(nt/Ue)*Ue,Ue)}return Ue.map(function(It){return be(Oe,It)})}function be(Oe,Ue){var rt=[],vt=[];return function(nt,It,Nt){var Jt,Kt,Vt,gn,un,Dn,fi=new Array,Mi=new Array;for(Jt=Kt=-1,gn=nt[0]>=It,Ok[gn<<1].forEach(Ri);++Jt=It,Ok[Vt|gn<<1].forEach(Ri);for(Ok[gn<<0].forEach(Ri);++Kt=It,un=nt[Kt*L]>=It,Ok[gn<<1|un<<2].forEach(Ri);++Jt=It,Dn=un,un=nt[Kt*L+Jt+1]>=It,Ok[Vt|gn<<1|un<<2|Dn<<3].forEach(Ri);Ok[gn|un<<3].forEach(Ri)}for(Jt=-1,un=nt[Kt*L]>=It,Ok[un<<2].forEach(Ri);++Jt=It,Ok[un<<2|Dn<<3].forEach(Ri);function Ri(wo){var vi,Ji,Tn=[wo[0][0]+Jt,wo[0][1]+Kt],Qn=[wo[1][0]+Jt,wo[1][1]+Kt],zi=Se(Tn),Pi=Se(Qn);(vi=Mi[zi])?(Ji=fi[Pi])?(delete Mi[vi.end],delete fi[Ji.start],vi===Ji?(vi.ring.push(Qn),Nt(vi.ring)):fi[vi.start]=Mi[Ji.end]={start:vi.start,end:Ji.end,ring:vi.ring.concat(Ji.ring)}):(delete Mi[vi.end],vi.ring.push(Qn),Mi[vi.end=Pi]=vi):(vi=fi[Pi])?(Ji=Mi[zi])?(delete fi[vi.start],delete Mi[Ji.end],vi===Ji?(vi.ring.push(Qn),Nt(vi.ring)):fi[Ji.start]=Mi[vi.end]={start:Ji.start,end:vi.end,ring:Ji.ring.concat(vi.ring)}):(delete fi[vi.start],vi.ring.unshift(Tn),fi[vi.start=zi]=vi):fi[zi]=Mi[Pi]={start:zi,end:Pi,ring:[Tn,Qn]}}Ok[un<<3].forEach(Ri)}(Oe,Ue,function(nt){q(nt,Oe,Ue),function(It){for(var Nt=0,Jt=It.length,Kt=It[Jt-1][1]*It[0][0]-It[Jt-1][0]*It[0][1];++Nt0?rt.push([nt]):vt.push(nt)}),vt.forEach(function(nt){for(var It,Nt=0,Jt=rt.length;Nt0&&It0&&Nt0&&rt>0))throw new Error("invalid size");return L=Ue,R=rt,fe},fe.thresholds=function(Oe){return arguments.length?(X=typeof Oe=="function"?Oe:Array.isArray(Oe)?c3(J2.call(Oe)):c3(Oe),fe):X},fe.smooth=function(Oe){return arguments.length?(q=Oe?Ee:m$,fe):q===Ee},fe}function lm(L,R,X){for(var q=L.width,fe=L.height,be=1+(X<<1),Se=0;Se=X&&(Ee>=be&&(Oe-=L.data[Ee-be+Se*q]),R.data[Ee-X+Se*q]=Oe/Math.min(Ee+1,q-1+be-Ee,be))}function AD(L,R,X){for(var q=L.width,fe=L.height,be=1+(X<<1),Se=0;Se=X&&(Ee>=be&&(Oe-=L.data[Se+(Ee-be)*q]),R.data[Se+(Ee-X)*q]=Oe/Math.min(Ee+1,fe-1+be-Ee,be))}function b$(L){return L[0]}function C$(L){return L[1]}function wD(){return 1}function yD(){var L=b$,R=C$,X=wD,q=960,fe=500,be=20,Se=2,Ee=3*be,Oe=q+2*Ee>>Se,Ue=fe+2*Ee>>Se,rt=c3(20);function vt(Vt){var gn=new Float32Array(Oe*Ue),un=new Float32Array(Oe*Ue);Vt.forEach(function(Mi,Ri,wo){var vi=+L(Mi,Ri,wo)+Ee>>Se,Ji=+R(Mi,Ri,wo)+Ee>>Se,Tn=+X(Mi,Ri,wo);vi>=0&&vi=0&&Ji>Se),AD({width:Oe,height:Ue,data:un},{data:gn},be>>Se),lm({width:Oe,height:Ue,data:gn},{data:un},be>>Se),AD({width:Oe,height:Ue,data:un},{data:gn},be>>Se),lm({width:Oe,height:Ue,data:gn},{data:un},be>>Se),AD({width:Oe,height:Ue,data:un},{data:gn},be>>Se);var Dn=rt(gn);if(!Array.isArray(Dn)){var fi=U(gn);Dn=H(0,fi,Dn),(Dn=M(0,Math.floor(fi/Dn)*Dn,Dn)).shift()}return S7().thresholds(Dn).size([Oe,Ue])(gn).map(nt)}function nt(Vt){return Vt.value*=Math.pow(2,-2*Se),Vt.coordinates.forEach(It),Vt}function It(Vt){Vt.forEach(Nt)}function Nt(Vt){Vt.forEach(Jt)}function Jt(Vt){Vt[0]=Vt[0]*Math.pow(2,Se)-Ee,Vt[1]=Vt[1]*Math.pow(2,Se)-Ee}function Kt(){return Oe=q+2*(Ee=3*be)>>Se,Ue=fe+2*Ee>>Se,vt}return vt.x=function(Vt){return arguments.length?(L=typeof Vt=="function"?Vt:c3(+Vt),vt):L},vt.y=function(Vt){return arguments.length?(R=typeof Vt=="function"?Vt:c3(+Vt),vt):R},vt.weight=function(Vt){return arguments.length?(X=typeof Vt=="function"?Vt:c3(+Vt),vt):X},vt.size=function(Vt){if(!arguments.length)return[q,fe];var gn=Math.ceil(Vt[0]),un=Math.ceil(Vt[1]);if(!(gn>=0||gn>=0))throw new Error("invalid size");return q=gn,fe=un,Kt()},vt.cellSize=function(Vt){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return Se=Math.floor(Math.log(Vt)/Math.LN2),Kt()},vt.thresholds=function(Vt){return arguments.length?(rt=typeof Vt=="function"?Vt:Array.isArray(Vt)?c3(J2.call(Vt)):c3(Vt),vt):rt},vt.bandwidth=function(Vt){if(!arguments.length)return Math.sqrt(be*(be+1));if(!((Vt=+Vt)>=0))throw new Error("invalid bandwidth");return be=Math.round((Math.sqrt(4*Vt*Vt+1)-1)/2),Kt()},vt}function u3(L){return function(){return L}}function am(L,R,X,q,fe,be,Se,Ee,Oe,Ue){this.target=L,this.type=R,this.subject=X,this.identifier=q,this.active=fe,this.x=be,this.y=Se,this.dx=Ee,this.dy=Oe,this._=Ue}function FR(){return!Yn.ctrlKey&&!Yn.button}function _R(){return this.parentNode}function Cd(L){return L??{x:Yn.x,y:Yn.y}}function A$(){return navigator.maxTouchPoints||"ontouchstart"in this}function w$(){var L,R,X,q,fe=FR,be=_R,Se=Cd,Ee=A$,Oe={},Ue=et("start","drag","end"),rt=0,vt=0;function nt(Dn){Dn.on("mousedown.drag",It).filter(Ee).on("touchstart.drag",Kt).on("touchmove.drag",Vt).on("touchend.drag touchcancel.drag",gn).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function It(){if(!q&&fe.apply(this,arguments)){var Dn=un("mouse",be.apply(this,arguments),Hf,this,arguments);Dn&&(nl(Yn.view).on("mousemove.drag",Nt,!0).on("mouseup.drag",Jt,!0),ya(Yn.view),cl(),X=!1,L=Yn.clientX,R=Yn.clientY,Dn("start"))}}function Nt(){if(Ll(),!X){var Dn=Yn.clientX-L,fi=Yn.clientY-R;X=Dn*Dn+fi*fi>vt}Oe.mouse("drag")}function Jt(){nl(Yn.view).on("mousemove.drag mouseup.drag",null),gl(Yn.view,X),Ll(),Oe.mouse("end")}function Kt(){if(fe.apply(this,arguments)){var Dn,fi,Mi=Yn.changedTouches,Ri=be.apply(this,arguments),wo=Mi.length;for(Dn=0;Dn=vt?Nt=!0:(un=Ee.charCodeAt(nt++))===10?Jt=!0:un===13&&(Jt=!0,Ee.charCodeAt(nt)===10&&++nt),Ee.slice(Dn+1,gn-1).replace(/""/g,'"')}for(;nt9999?"+"+mh(It,6):mh(It,4)}(Oe.getUTCFullYear())+"-"+mh(Oe.getUTCMonth()+1,2)+"-"+mh(Oe.getUTCDate(),2)+(nt?"T"+mh(Ue,2)+":"+mh(rt,2)+":"+mh(vt,2)+"."+mh(nt,3)+"Z":vt?"T"+mh(Ue,2)+":"+mh(rt,2)+":"+mh(vt,2)+"Z":rt||Ue?"T"+mh(Ue,2)+":"+mh(rt,2)+"Z":"")}(Ee):R.test(Ee+="")?'"'+Ee.replace(/"/g,'""')+'"':Ee}return{parse:function(Ee,Oe){var Ue,rt,vt=q(Ee,function(nt,It){if(Ue)return Ue(nt,It-1);rt=nt,Ue=Oe?function(Nt,Jt){var Kt=U9(Nt);return function(Vt,gn){return Jt(Kt(Vt),gn,Nt)}}(nt,Oe):U9(nt)});return vt.columns=rt||[],vt},parseRows:q,format:function(Ee,Oe){return Oe==null&&(Oe=G9(Ee)),[Oe.map(Se).join(L)].concat(fe(Ee,Oe)).join(` +`)},formatBody:function(Ee,Oe){return Oe==null&&(Oe=G9(Ee)),fe(Ee,Oe).join(` +`)},formatRows:function(Ee){return Ee.map(be).join(` +`)},formatRow:be,formatValue:Se}}var sm=M7(","),VR=sm.parse,y$=sm.parseRows,UR=sm.format,GR=sm.formatBody,L$=sm.formatRows,x$=sm.formatRow,E$=sm.formatValue,d3=M7(" "),YR=d3.parse,XR=d3.parseRows,S$=d3.format,M$=d3.formatBody,T$=d3.formatRows,D$=d3.formatRow,j$=d3.formatValue;function O$(L){for(var R in L){var X,q,fe=L[R].trim();if(fe)if(fe==="true")fe=!0;else if(fe==="false")fe=!1;else if(fe==="NaN")fe=NaN;else if(isNaN(X=+fe)){if(!(q=fe.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;p$&&q[4]&&!q[7]&&(fe=fe.replace(/-/g,"/").replace(/T/," ")),fe=new Date(fe)}else fe=X;else fe=null;L[R]=fe}return L}var p$=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function QR(L){return+L}function I$(L){return L*L}function P$(L){return L*(2-L)}function ZR(L){return((L*=2)<=1?L*L:--L*(2-L)+1)/2}var qR=function L(R){function X(q){return Math.pow(q,R)}return R=+R,X.exponent=L,X}(3),B$=function L(R){function X(q){return 1-Math.pow(1-q,R)}return R=+R,X.exponent=L,X}(3),KR=function L(R){function X(q){return((q*=2)<=1?Math.pow(q,R):2-Math.pow(2-q,R))/2}return R=+R,X.exponent=L,X}(3),JR=Math.PI,$R=JR/2;function N$(L){return+L==1?1:1-Math.cos(L*$R)}function R$(L){return Math.sin(L*$R)}function xD(L){return(1-Math.cos(JR*L))/2}function f3(L){return 1.0009775171065494*(Math.pow(2,-10*L)-.0009765625)}function H$(L){return f3(1-+L)}function W$(L){return 1-f3(L)}function eH(L){return((L*=2)<=1?f3(1-L):2-f3(L-1))/2}function z$(L){return 1-Math.sqrt(1-L*L)}function F$(L){return Math.sqrt(1- --L*L)}function tH(L){return((L*=2)<=1?1-Math.sqrt(1-L*L):Math.sqrt(1-(L-=2)*L)+1)/2}var T7=7.5625;function nH(L){return 1-tC(1-L)}function tC(L){return(L=+L)<.36363636363636365?T7*L*L:L<.7272727272727273?T7*(L-=.5454545454545454)*L+.75:L<.9090909090909091?T7*(L-=.8181818181818182)*L+.9375:T7*(L-=.9545454545454546)*L+.984375}function _$(L){return((L*=2)<=1?1-tC(1-L):tC(L-1)+1)/2}var ED=1.70158,iH=function L(R){function X(q){return(q=+q)*q*(R*(q-1)+q)}return R=+R,X.overshoot=L,X}(ED),V$=function L(R){function X(q){return--q*q*((q+1)*R+q)+1}return R=+R,X.overshoot=L,X}(ED),oH=function L(R){function X(q){return((q*=2)<1?q*q*((R+1)*q-R):(q-=2)*q*((R+1)*q+R)+2)/2}return R=+R,X.overshoot=L,X}(ED),Y9=2*Math.PI,U$=function L(R,X){var q=Math.asin(1/(R=Math.max(1,R)))*(X/=Y9);function fe(be){return R*f3(- --be)*Math.sin((q-be)/X)}return fe.amplitude=function(be){return L(be,X*Y9)},fe.period=function(be){return L(R,be)},fe}(1,.3),rH=function L(R,X){var q=Math.asin(1/(R=Math.max(1,R)))*(X/=Y9);function fe(be){return 1-R*f3(be=+be)*Math.sin((be+q)/X)}return fe.amplitude=function(be){return L(be,X*Y9)},fe.period=function(be){return L(R,be)},fe}(1,.3),G$=function L(R,X){var q=Math.asin(1/(R=Math.max(1,R)))*(X/=Y9);function fe(be){return((be=2*be-1)<0?R*f3(-be)*Math.sin((q-be)/X):2-R*f3(be)*Math.sin((q+be)/X))/2}return fe.amplitude=function(be){return L(be,X*Y9)},fe.period=function(be){return L(R,be)},fe}(1,.3);function lH(L){if(!L.ok)throw new Error(L.status+" "+L.statusText);return L.blob()}function Y$(L,R){return fetch(L,R).then(lH)}function X$(L){if(!L.ok)throw new Error(L.status+" "+L.statusText);return L.arrayBuffer()}function Q$(L,R){return fetch(L,R).then(X$)}function Z$(L){if(!L.ok)throw new Error(L.status+" "+L.statusText);return L.text()}function D7(L,R){return fetch(L,R).then(Z$)}function aH(L){return function(R,X,q){return arguments.length===2&&typeof X=="function"&&(q=X,X=void 0),D7(R,X).then(function(fe){return L(fe,q)})}}function q$(L,R,X,q){arguments.length===3&&typeof X=="function"&&(q=X,X=void 0);var fe=M7(L);return D7(R,X).then(function(be){return fe.parse(be,q)})}var K$=aH(VR),sH=aH(YR);function cH(L,R){return new Promise(function(X,q){var fe=new Image;for(var be in R)fe[be]=R[be];fe.onerror=q,fe.onload=function(){X(fe)},fe.src=L})}function uH(L){if(!L.ok)throw new Error(L.status+" "+L.statusText);if(L.status!==204&&L.status!==205)return L.json()}function J$(L,R){return fetch(L,R).then(uH)}function SD(L){return function(R,X){return D7(R,X).then(function(q){return new DOMParser().parseFromString(q,L)})}}const dH=SD("application/xml");var $$=SD("text/html"),MD=SD("image/svg+xml");function fH(L,R){var X;function q(){var fe,be,Se=X.length,Ee=0,Oe=0;for(fe=0;fe=(be=(Jt+Vt)/2))?Jt=be:Vt=be,(rt=X>=(Se=(Kt+gn)/2))?Kt=Se:gn=Se,fe=It,!(It=It[vt=rt<<1|Ue]))return fe[vt]=Nt,L;if(Ee=+L._x.call(null,It.data),Oe=+L._y.call(null,It.data),R===Ee&&X===Oe)return Nt.next=It,fe?fe[vt]=Nt:L._root=Nt,L;do fe=fe?fe[vt]=new Array(4):L._root=new Array(4),(Ue=R>=(be=(Jt+Vt)/2))?Jt=be:Vt=be,(rt=X>=(Se=(Kt+gn)/2))?Kt=Se:gn=Se;while((vt=rt<<1|Ue)==(nt=(Oe>=Se)<<1|Ee>=be));return fe[nt]=It,fe[vt]=Nt,L}function bf(L,R,X,q,fe){this.node=L,this.x0=R,this.y0=X,this.x1=q,this.y1=fe}function eee(L){return L[0]}function tee(L){return L[1]}function j7(L,R,X){var q=new DD(R??eee,X??tee,NaN,NaN,NaN,NaN);return L==null?q:q.addAll(L)}function DD(L,R,X,q,fe,be){this._x=L,this._y=R,this._x0=X,this._y0=q,this._x1=fe,this._y1=be,this._root=void 0}function jD(L){for(var R={data:L.data},X=R;L=L.next;)X=X.next={data:L.data};return R}var Ad=j7.prototype=DD.prototype;function nee(L){return L.x+L.vx}function iee(L){return L.y+L.vy}function oee(L){var R,X,q=1,fe=1;function be(){for(var Oe,Ue,rt,vt,nt,It,Nt,Jt=R.length,Kt=0;Ktvt+vi||fint+vi||Mirt.index){var Ji=vt-Ri.x-Ri.vx,Tn=nt-Ri.y-Ri.vy,Qn=Ji*Ji+Tn*Tn;QnOe.r&&(Oe.r=Oe[Ue].r)}function Ee(){if(R){var Oe,Ue,rt=R.length;for(X=new Array(rt),Oe=0;Oert&&(rt=q),fevt&&(vt=fe));if(Oe>rt||Ue>vt)return this;for(this.cover(Oe,Ue).cover(rt,vt),X=0;XL||L>=fe||q>R||R>=be;)switch(Ee=(Rnt||(be=Oe.y0)>It||(Se=Oe.x1)=Vt)<<1|L>=Kt)&&(Oe=Nt[Nt.length-1],Nt[Nt.length-1]=Nt[Nt.length-1-Ue],Nt[Nt.length-1-Ue]=Oe)}else{var gn=L-+this._x.call(null,Jt.data),un=R-+this._y.call(null,Jt.data),Dn=gn*gn+un*un;if(Dn=(Ee=(Nt+Kt)/2))?Nt=Ee:Kt=Ee,(rt=Se>=(Oe=(Jt+Vt)/2))?Jt=Oe:Vt=Oe,R=It,!(It=It[vt=rt<<1|Ue]))return this;if(!It.length)break;(R[vt+1&3]||R[vt+2&3]||R[vt+3&3])&&(X=R,nt=vt)}for(;It.data!==L;)if(q=It,!(It=It.next))return this;return(fe=It.next)&&delete It.next,q?(fe?q.next=fe:delete q.next,this):R?(fe?R[vt]=fe:delete R[vt],(It=R[0]||R[1]||R[2]||R[3])&&It===(R[3]||R[2]||R[1]||R[0])&&!It.length&&(X?X[nt]=It:this._root=It),this):(this._root=fe,this)},Ad.removeAll=function(L){for(var R=0,X=L.length;R1?(Jt==null?Ee.remove(Nt):Ee.set(Nt,It(Jt)),R):Ee.get(Nt)},find:function(Nt,Jt,Kt){var Vt,gn,un,Dn,fi,Mi=0,Ri=L.length;for(Kt==null?Kt=1/0:Kt*=Kt,Mi=0;Mi1?(Ue.on(Nt,Jt),R):Ue.on(Nt)}}}function see(){var L,R,X,q,fe=ld(-30),be=1,Se=1/0,Ee=.81;function Oe(nt){var It,Nt=L.length,Jt=j7(L,OD,kH).visitAfter(rt);for(X=nt,It=0;It=Se)){(nt.data!==R||nt.next)&&(Kt===0&&(un+=(Kt=pk())*Kt),Vt===0&&(un+=(Vt=pk())*Vt),un1?q[0]+q.slice(2):q,+L.slice(X+1)]}function cm(L){return(L=p7(Math.abs(L)))?L[1]:NaN}var gH,fee=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function nC(L){if(!(R=fee.exec(L)))throw new Error("invalid format: "+L);var R;return new Ik({fill:R[1],align:R[2],sign:R[3],symbol:R[4],zero:R[5],width:R[6],comma:R[7],precision:R[8]&&R[8].slice(1),trim:R[9],type:R[10]})}function Ik(L){this.fill=L.fill===void 0?" ":L.fill+"",this.align=L.align===void 0?">":L.align+"",this.sign=L.sign===void 0?"-":L.sign+"",this.symbol=L.symbol===void 0?"":L.symbol+"",this.zero=!!L.zero,this.width=L.width===void 0?void 0:+L.width,this.comma=!!L.comma,this.precision=L.precision===void 0?void 0:+L.precision,this.trim=!!L.trim,this.type=L.type===void 0?"":L.type+""}function vH(L,R){var X=p7(L,R);if(!X)return L+"";var q=X[0],fe=X[1];return fe<0?"0."+new Array(-fe).join("0")+q:q.length>fe+1?q.slice(0,fe+1)+"."+q.slice(fe+1):q+new Array(fe-q.length+2).join("0")}nC.prototype=Ik.prototype,Ik.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,0|this.width))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const mH={"%":function(L,R){return(100*L).toFixed(R)},b:function(L){return Math.round(L).toString(2)},c:function(L){return L+""},d:function(L){return Math.abs(L=Math.round(L))>=1e21?L.toLocaleString("en").replace(/,/g,""):L.toString(10)},e:function(L,R){return L.toExponential(R)},f:function(L,R){return L.toFixed(R)},g:function(L,R){return L.toPrecision(R)},o:function(L){return Math.round(L).toString(8)},p:function(L,R){return vH(100*L,R)},r:vH,s:function(L,R){var X=p7(L,R);if(!X)return L+"";var q=X[0],fe=X[1],be=fe-(gH=3*Math.max(-8,Math.min(8,Math.floor(fe/3))))+1,Se=q.length;return be===Se?q:be>Se?q+new Array(be-Se+1).join("0"):be>0?q.slice(0,be)+"."+q.slice(be):"0."+new Array(1-be).join("0")+p7(L,Math.max(0,R+be-1))[0]},X:function(L){return Math.round(L).toString(16).toUpperCase()},x:function(L){return Math.round(L).toString(16)}};function bH(L){return L}var iC,X9,I7,pD=Array.prototype.map,ID=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function CH(L){var R,X,q=L.grouping===void 0||L.thousands===void 0?bH:(R=pD.call(L.grouping,Number),X=L.thousands+"",function(nt,It){for(var Nt=nt.length,Jt=[],Kt=0,Vt=R[0],gn=0;Nt>0&&Vt>0&&(gn+Vt+1>It&&(Vt=Math.max(1,It-gn)),Jt.push(nt.substring(Nt-=Vt,Nt+Vt)),!((gn+=Vt+1)>It));)Vt=R[Kt=(Kt+1)%R.length];return Jt.reverse().join(X)}),fe=L.currency===void 0?"":L.currency[0]+"",be=L.currency===void 0?"":L.currency[1]+"",Se=L.decimal===void 0?".":L.decimal+"",Ee=L.numerals===void 0?bH:function(nt){return function(It){return It.replace(/[0-9]/g,function(Nt){return nt[+Nt]})}}(pD.call(L.numerals,String)),Oe=L.percent===void 0?"%":L.percent+"",Ue=L.minus===void 0?"-":L.minus+"",rt=L.nan===void 0?"NaN":L.nan+"";function vt(nt){var It=(nt=nC(nt)).fill,Nt=nt.align,Jt=nt.sign,Kt=nt.symbol,Vt=nt.zero,gn=nt.width,un=nt.comma,Dn=nt.precision,fi=nt.trim,Mi=nt.type;Mi==="n"?(un=!0,Mi="g"):mH[Mi]||(Dn===void 0&&(Dn=12),fi=!0,Mi="g"),(Vt||It==="0"&&Nt==="=")&&(Vt=!0,It="0",Nt="=");var Ri=Kt==="$"?fe:Kt==="#"&&/[boxX]/.test(Mi)?"0"+Mi.toLowerCase():"",wo=Kt==="$"?be:/[%p]/.test(Mi)?Oe:"",vi=mH[Mi],Ji=/[defgprs%]/.test(Mi);function Tn(Qn){var zi,Pi,Gi,or=Ri,Lr=wo;if(Mi==="c")Lr=vi(Qn)+Lr,Qn="";else{var ml=(Qn=+Qn)<0||1/Qn<0;if(Qn=isNaN(Qn)?rt:vi(Math.abs(Qn),Dn),fi&&(Qn=function(Wr){e:for(var za,Dl=Wr.length,El=1,Ka=-1;El0&&(Ka=0)}return Ka>0?Wr.slice(0,Ka)+Wr.slice(za+1):Wr}(Qn)),ml&&+Qn==0&&Jt!=="+"&&(ml=!1),or=(ml?Jt==="("?Jt:Ue:Jt==="-"||Jt==="("?"":Jt)+or,Lr=(Mi==="s"?ID[8+gH/3]:"")+Lr+(ml&&Jt==="("?")":""),Ji){for(zi=-1,Pi=Qn.length;++zi(Gi=Qn.charCodeAt(zi))||Gi>57){Lr=(Gi===46?Se+Qn.slice(zi+1):Qn.slice(zi))+Lr,Qn=Qn.slice(0,zi);break}}}un&&!Vt&&(Qn=q(Qn,1/0));var Ei=or.length+Qn.length+Lr.length,Ro=Ei>1)+or+Qn+Lr+Ro.slice(Ei);break;default:Qn=Ro+or+Qn+Lr}return Ee(Qn)}return Dn=Dn===void 0?6:/[gprs]/.test(Mi)?Math.max(1,Math.min(21,Dn)):Math.max(0,Math.min(20,Dn)),Tn.toString=function(){return nt+""},Tn}return{format:vt,formatPrefix:function(nt,It){var Nt=vt(((nt=nC(nt)).type="f",nt)),Jt=3*Math.max(-8,Math.min(8,Math.floor(cm(It)/3))),Kt=Math.pow(10,-Jt),Vt=ID[8+Jt/3];return function(gn){return Nt(Kt*gn)+Vt}}}}function AH(L){return iC=CH(L),X9=iC.format,I7=iC.formatPrefix,iC}function wH(L){return Math.max(0,-cm(Math.abs(L)))}function yH(L,R){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(cm(R)/3)))-cm(Math.abs(L)))}function LH(L,R){return L=Math.abs(L),R=Math.abs(R)-L,Math.max(0,cm(R)-cm(L))+1}function h3(){return new P7}function P7(){this.reset()}AH({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),P7.prototype={constructor:P7,reset:function(){this.s=this.t=0},add:function(L){xH(B7,L,this.t),xH(this,B7.s,this.s),this.s?this.t+=B7.t:this.s=B7.t},valueOf:function(){return this.s}};var B7=new P7;function xH(L,R,X){var q=L.s=R+X,fe=q-R,be=q-fe;L.t=R-be+(X-fe)}var Jl=1e-6,N7=1e-12,Ha=Math.PI,su=Ha/2,oC=Ha/4,Yf=2*Ha,vc=180/Ha,xl=Ha/180,is=Math.abs,Q9=Math.atan,Xf=Math.atan2,ol=Math.cos,rC=Math.ceil,EH=Math.exp,R7=Math.log,lC=Math.pow,br=Math.sin,s1=Math.sign||function(L){return L>0?1:L<0?-1:0},qc=Math.sqrt,pr=Math.tan;function H7(L){return L>1?0:L<-1?Ha:Math.acos(L)}function qd(L){return L>1?su:L<-1?-su:Math.asin(L)}function W7(L){return(L=br(L/2))*L}function $s(){}function z7(L,R){L&&PD.hasOwnProperty(L.type)&&PD[L.type](L,R)}var F7={Feature:function(L,R){z7(L.geometry,R)},FeatureCollection:function(L,R){for(var X=L.features,q=-1,fe=X.length;++q=0?1:-1,fe=q*X,be=ol(R=(R*=xl)/2+oC),Se=br(R),Ee=e2*Se,Oe=aC*be+Ee*ol(fe),Ue=Ee*q*br(fe);Pk.add(Xf(Ue,Oe)),BD=L,aC=be,e2=Se}function kee(L){return Jd.reset(),$1(L,bh),2*Jd}function G7(L){return[Xf(L[1],L[0]),qd(L[2])]}function um(L){var R=L[0],X=L[1],q=ol(X);return[q*ol(R),q*br(R),br(X)]}function Y7(L,R){return L[0]*R[0]+L[1]*R[1]+L[2]*R[2]}function Z9(L,R){return[L[1]*R[2]-L[2]*R[1],L[2]*R[0]-L[0]*R[2],L[0]*R[1]-L[1]*R[0]]}function RD(L,R){L[0]+=R[0],L[1]+=R[1],L[2]+=R[2]}function dm(L,R){return[L[0]*R,L[1]*R,L[2]*R]}function q9(L){var R=qc(L[0]*L[0]+L[1]*L[1]+L[2]*L[2]);L[0]/=R,L[1]/=R,L[2]/=R}var Wc,Qf,Ps,c1,fm,K9,SH,J9,$2,t2,$9,g3,sC,cC,uC,dC,fC,hC,kC,e5,X7,HD,WD,Cf,wd,$d,hm=h3(),ef={point:Q7,lineStart:v3,lineEnd:FD,polygonStart:function(){ef.point=gC,ef.lineStart=gee,ef.lineEnd=vee,hm.reset(),bh.polygonStart()},polygonEnd:function(){bh.polygonEnd(),ef.point=Q7,ef.lineStart=v3,ef.lineEnd=FD,Pk<0?(Wc=-(Ps=180),Qf=-(c1=90)):hm>Jl?c1=90:hm<-1e-6&&(Qf=-90),t2[0]=Wc,t2[1]=Ps},sphere:function(){Wc=-(Ps=180),Qf=-(c1=90)}};function Q7(L,R){$2.push(t2=[Wc=L,Ps=L]),Rc1&&(c1=R)}function zD(L,R){var X=um([L*xl,R*xl]);if(J9){var q=Z9(J9,X),fe=Z9([q[1],-q[0],0],q);q9(fe),fe=G7(fe);var be,Se=L-fm,Ee=Se>0?1:-1,Oe=fe[0]*vc*Ee,Ue=is(Se)>180;Ue^(Ee*fmc1&&(c1=be):Ue^(Ee*fm<(Oe=(Oe+360)%360-180)&&Oec1&&(c1=R)),Ue?Lyd(Wc,Ps)&&(Ps=L):yd(L,Ps)>yd(Wc,Ps)&&(Wc=L):Ps>=Wc?(LPs&&(Ps=L)):L>fm?yd(Wc,L)>yd(Wc,Ps)&&(Ps=L):yd(L,Ps)>yd(Wc,Ps)&&(Wc=L)}else $2.push(t2=[Wc=L,Ps=L]);Rc1&&(c1=R),J9=X,fm=L}function v3(){ef.point=zD}function FD(){t2[0]=Wc,t2[1]=Ps,ef.point=Q7,J9=null}function gC(L,R){if(J9){var X=L-fm;hm.add(is(X)>180?X+(X>0?360:-360):X)}else K9=L,SH=R;bh.point(L,R),zD(L,R)}function gee(){bh.lineStart()}function vee(){gC(K9,SH),bh.lineEnd(),is(hm)>Jl&&(Wc=-(Ps=180)),t2[0]=Wc,t2[1]=Ps,J9=null}function yd(L,R){return(R-=L)<0?R+360:R}function mee(L,R){return L[0]-R[0]}function MH(L,R){return L[0]<=L[1]?L[0]<=R&&R<=L[1]:Ryd(q[0],q[1])&&(q[1]=fe[1]),yd(fe[0],q[1])>yd(q[0],q[1])&&(q[0]=fe[0])):be.push(q=fe);for(Se=-1/0,R=0,q=be[X=be.length-1];R<=X;q=fe,++R)fe=be[R],(Ee=yd(q[1],fe[0]))>Se&&(Se=Ee,Wc=fe[0],Ps=q[1])}return $2=t2=null,Wc===1/0||Qf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Wc,Qf],[Ps,c1]]}var n2={sphere:$s,point:Bk,lineStart:vC,lineEnd:km,polygonStart:function(){n2.lineStart=Aee,n2.lineEnd=wee},polygonEnd:function(){n2.lineStart=vC,n2.lineEnd=km}};function Bk(L,R){L*=xl;var X=ol(R*=xl);t5(X*ol(L),X*br(L),br(R))}function t5(L,R,X){++$9,sC+=(L-sC)/$9,cC+=(R-cC)/$9,uC+=(X-uC)/$9}function vC(){n2.point=bee}function bee(L,R){L*=xl;var X=ol(R*=xl);Cf=X*ol(L),wd=X*br(L),$d=br(R),n2.point=Cee,t5(Cf,wd,$d)}function Cee(L,R){L*=xl;var X=ol(R*=xl),q=X*ol(L),fe=X*br(L),be=br(R),Se=Xf(qc((Se=wd*be-$d*fe)*Se+(Se=$d*q-Cf*be)*Se+(Se=Cf*fe-wd*q)*Se),Cf*q+wd*fe+$d*be);g3+=Se,dC+=Se*(Cf+(Cf=q)),fC+=Se*(wd+(wd=fe)),hC+=Se*($d+($d=be)),t5(Cf,wd,$d)}function km(){n2.point=Bk}function Aee(){n2.point=DH}function wee(){_D(HD,WD),n2.point=Bk}function DH(L,R){HD=L,WD=R,L*=xl,R*=xl,n2.point=_D;var X=ol(R);Cf=X*ol(L),wd=X*br(L),$d=br(R),t5(Cf,wd,$d)}function _D(L,R){L*=xl;var X=ol(R*=xl),q=X*ol(L),fe=X*br(L),be=br(R),Se=wd*be-$d*fe,Ee=$d*q-Cf*be,Oe=Cf*fe-wd*q,Ue=qc(Se*Se+Ee*Ee+Oe*Oe),rt=qd(Ue),vt=Ue&&-rt/Ue;kC+=vt*Se,e5+=vt*Ee,X7+=vt*Oe,g3+=rt,dC+=rt*(Cf+(Cf=q)),fC+=rt*(wd+(wd=fe)),hC+=rt*($d+($d=be)),t5(Cf,wd,$d)}function VD(L){$9=g3=sC=cC=uC=dC=fC=hC=kC=e5=X7=0,$1(L,n2);var R=kC,X=e5,q=X7,fe=R*R+X*X+q*q;return feHa?L+Math.round(-L/Yf)*Yf:L,R]}function bC(L,R,X){return(L%=Yf)?R||X?mC(n5(L),i5(R,X)):n5(L):R||X?i5(R,X):gm}function Z7(L){return function(R,X){return[(R+=L)>Ha?R-Yf:R<-Ha?R+Yf:R,X]}}function n5(L){var R=Z7(L);return R.invert=Z7(-L),R}function i5(L,R){var X=ol(L),q=br(L),fe=ol(R),be=br(R);function Se(Ee,Oe){var Ue=ol(Oe),rt=ol(Ee)*Ue,vt=br(Ee)*Ue,nt=br(Oe),It=nt*X+rt*q;return[Xf(vt*fe-It*be,rt*X-nt*q),qd(It*fe+vt*be)]}return Se.invert=function(Ee,Oe){var Ue=ol(Oe),rt=ol(Ee)*Ue,vt=br(Ee)*Ue,nt=br(Oe),It=nt*fe-vt*be;return[Xf(vt*fe+nt*be,rt*X+It*q),qd(It*X-rt*q)]},Se}function q7(L){function R(X){return(X=L(X[0]*xl,X[1]*xl))[0]*=vc,X[1]*=vc,X}return L=bC(L[0]*xl,L[1]*xl,L.length>2?L[2]*xl:0),R.invert=function(X){return(X=L.invert(X[0]*xl,X[1]*xl))[0]*=vc,X[1]*=vc,X},R}function UD(L,R,X,q,fe,be){if(X){var Se=ol(R),Ee=br(R),Oe=q*X;fe==null?(fe=R+q*Yf,be=R-Oe/2):(fe=ad(Se,fe),be=ad(Se,be),(q>0?febe)&&(fe+=q*Yf));for(var Ue,rt=fe;q>0?rt>be:rt1&&R.push(R.pop().concat(R.shift()))},result:function(){var X=R;return R=[],L=null,X}}}function os(L,R){return is(L[0]-R[0])=0;--be)fe.point((rt=Ue[be])[0],rt[1]);else q(nt.x,nt.p.x,-1,fe);nt=nt.p}Ue=(nt=nt.o).z,It=!It}while(!nt.v);fe.lineEnd()}}}function r5(L){if(R=L.length){for(var R,X,q=0,fe=L[0];++q=0?1:-1,vi=wo*Ri,Ji=vi>Ha,Tn=Jt*fi;if(GD.add(Xf(Tn*wo*br(vi),Kt*Mi+Tn*ol(vi))),Se+=Ji?Ri+wo*Yf:Ri,Ji^It>=X^un>=X){var Qn=Z9(um(nt),um(gn));q9(Qn);var zi=Z9(be,Qn);q9(zi);var Pi=(Ji^Ri>=0?-1:1)*qd(zi[2]);(q>Pi||q===Pi&&(Qn[0]||Qn[1]))&&(Ee+=Ji^Ri>=0?1:-1)}}return(Se<-1e-6||Se0){for(vt||(fe.polygonStart(),vt=!0),fe.lineStart(),Dn=0;Dn1&&2&wo&&vi.push(vi.pop().concat(vi.shift())),Se.push(vi.filter(Lee))}return nt}}function Lee(L){return L.length>1}function IH(L,R){return((L=L.x)[0]<0?L[1]-su-Jl:su-L[1])-((R=R.x)[0]<0?R[1]-su-Jl:su-R[1])}const J7=pH(function(){return!0},function(L){var R,X=NaN,q=NaN,fe=NaN;return{lineStart:function(){L.lineStart(),R=1},point:function(be,Se){var Ee=be>0?Ha:-Ha,Oe=is(be-X);is(Oe-Ha)0?su:-su),L.point(fe,q),L.lineEnd(),L.lineStart(),L.point(Ee,q),L.point(be,q),R=0):fe!==Ee&&Oe>=Ha&&(is(X-fe)Jl?Q9((br(rt)*(Nt=ol(nt))*br(vt)-br(nt)*(It=ol(rt))*br(Ue))/(It*Nt*Jt)):(rt+nt)/2}(X,q,be,Se),L.point(fe,q),L.lineEnd(),L.lineStart(),L.point(Ee,q),R=0),L.point(X=be,q=Se),fe=Ee},lineEnd:function(){L.lineEnd(),X=q=NaN},clean:function(){return 2-R}}},function(L,R,X,q){var fe;if(L==null)fe=X*su,q.point(-Ha,fe),q.point(0,fe),q.point(Ha,fe),q.point(Ha,0),q.point(Ha,-fe),q.point(0,-fe),q.point(-Ha,-fe),q.point(-Ha,0),q.point(-Ha,fe);else if(is(L[0]-R[0])>Jl){var be=L[0]0,fe=is(R)>Jl;function be(Oe,Ue){return ol(Oe)*ol(Ue)>R}function Se(Oe,Ue,rt){var vt=[1,0,0],nt=Z9(um(Oe),um(Ue)),It=Y7(nt,nt),Nt=nt[0],Jt=It-Nt*Nt;if(!Jt)return!rt&&Oe;var Kt=R*It/Jt,Vt=-R*Nt/Jt,gn=Z9(vt,nt),un=dm(vt,Kt);RD(un,dm(nt,Vt));var Dn=gn,fi=Y7(un,Dn),Mi=Y7(Dn,Dn),Ri=fi*fi-Mi*(Y7(un,un)-1);if(!(Ri<0)){var wo=qc(Ri),vi=dm(Dn,(-fi-wo)/Mi);if(RD(vi,un),vi=G7(vi),!rt)return vi;var Ji,Tn=Oe[0],Qn=Ue[0],zi=Oe[1],Pi=Ue[1];Qn0^vi[1]<(is(vi[0]-Tn)Ha^(Tn<=vi[0]&&vi[0]<=Qn)){var Lr=dm(Dn,(-fi+wo)/Mi);return RD(Lr,un),[vi,G7(Lr)]}}}function Ee(Oe,Ue){var rt=q?L:Ha-L,vt=0;return Oe<-rt?vt|=1:Oe>rt&&(vt|=2),Ue<-rt?vt|=4:Ue>rt&&(vt|=8),vt}return pH(be,function(Oe){var Ue,rt,vt,nt,It;return{lineStart:function(){nt=vt=!1,It=1},point:function(Nt,Jt){var Kt,Vt=[Nt,Jt],gn=be(Nt,Jt),un=q?gn?0:Ee(Nt,Jt):gn?Ee(Nt+(Nt<0?Ha:-Ha),Jt):0;if(!Ue&&(nt=vt=gn)&&Oe.lineStart(),gn!==vt&&(!(Kt=Se(Ue,Vt))||os(Ue,Kt)||os(Vt,Kt))&&(Vt[2]=1),gn!==vt)It=0,gn?(Oe.lineStart(),Kt=Se(Vt,Ue),Oe.point(Kt[0],Kt[1])):(Kt=Se(Ue,Vt),Oe.point(Kt[0],Kt[1],2),Oe.lineEnd()),Ue=Kt;else if(fe&&Ue&&q^gn){var Dn;un&rt||!(Dn=Se(Vt,Ue,!0))||(It=0,q?(Oe.lineStart(),Oe.point(Dn[0][0],Dn[0][1]),Oe.point(Dn[1][0],Dn[1][1]),Oe.lineEnd()):(Oe.point(Dn[1][0],Dn[1][1]),Oe.lineEnd(),Oe.lineStart(),Oe.point(Dn[0][0],Dn[0][1],3)))}!gn||Ue&&os(Ue,Vt)||Oe.point(Vt[0],Vt[1]),Ue=Vt,vt=gn,rt=un},lineEnd:function(){vt&&Oe.lineEnd(),Ue=null},clean:function(){return It|(nt&&vt)<<1}}},function(Oe,Ue,rt,vt){UD(vt,L,X,rt,Oe,Ue)},q?[0,-L]:[-Ha,L-Ha])}var CC=1e9,$7=-CC;function AC(L,R,X,q){function fe(Ue,rt){return L<=Ue&&Ue<=X&&R<=rt&&rt<=q}function be(Ue,rt,vt,nt){var It=0,Nt=0;if(Ue==null||(It=Se(Ue,vt))!==(Nt=Se(rt,vt))||Oe(Ue,rt)<0^vt>0)do nt.point(It===0||It===3?L:X,It>1?q:R);while((It=(It+vt+4)%4)!==Nt);else nt.point(rt[0],rt[1])}function Se(Ue,rt){return is(Ue[0]-L)0?0:3:is(Ue[0]-X)0?2:1:is(Ue[1]-R)0?1:0:rt>0?3:2}function Ee(Ue,rt){return Oe(Ue.x,rt.x)}function Oe(Ue,rt){var vt=Se(Ue,1),nt=Se(rt,1);return vt!==nt?vt-nt:vt===0?rt[1]-Ue[1]:vt===1?Ue[0]-rt[0]:vt===2?Ue[1]-rt[1]:rt[0]-Ue[0]}return function(Ue){var rt,vt,nt,It,Nt,Jt,Kt,Vt,gn,un,Dn,fi=Ue,Mi=jH(),Ri={point:wo,lineStart:function(){Ri.point=vi,vt&&vt.push(nt=[]),un=!0,gn=!1,Kt=Vt=NaN},lineEnd:function(){rt&&(vi(It,Nt),Jt&&gn&&Mi.rejoin(),rt.push(Mi.result())),Ri.point=wo,gn&&fi.lineEnd()},polygonStart:function(){fi=Mi,rt=[],vt=[],Dn=!0},polygonEnd:function(){var Ji=function(){for(var zi=0,Pi=0,Gi=vt.length;Piq&&(za-or)*(q-Lr)>(Dl-Lr)*(L-or)&&++zi:Dl<=q&&(za-or)*(q-Lr)<(Dl-Lr)*(L-or)&&--zi;return zi}(),Tn=Dn&&Ji,Qn=(rt=J(rt)).length;(Tn||Qn)&&(Ue.polygonStart(),Tn&&(Ue.lineStart(),be(null,null,1,Ue),Ue.lineEnd()),Qn&&o5(rt,Ee,Ji,be,Ue),Ue.polygonEnd()),fi=Ue,rt=vt=nt=null}};function wo(Ji,Tn){fe(Ji,Tn)&&fi.point(Ji,Tn)}function vi(Ji,Tn){var Qn=fe(Ji,Tn);if(vt&&nt.push([Ji,Tn]),un)It=Ji,Nt=Tn,Jt=Qn,un=!1,Qn&&(fi.lineStart(),fi.point(Ji,Tn));else if(Qn&&gn)fi.point(Ji,Tn);else{var zi=[Kt=Math.max($7,Math.min(CC,Kt)),Vt=Math.max($7,Math.min(CC,Vt))],Pi=[Ji=Math.max($7,Math.min(CC,Ji)),Tn=Math.max($7,Math.min(CC,Tn))];(function(Gi,or,Lr,ml,Ei,Ro){var Wr,za=Gi[0],Dl=Gi[1],El=0,Ka=1,Sd=or[0]-za,Kc=or[1]-Dl;if(Wr=Lr-za,Sd||!(Wr>0)){if(Wr/=Sd,Sd<0){if(Wr0){if(Wr>Ka)return;Wr>El&&(El=Wr)}if(Wr=Ei-za,Sd||!(Wr<0)){if(Wr/=Sd,Sd<0){if(Wr>Ka)return;Wr>El&&(El=Wr)}else if(Sd>0){if(Wr0)){if(Wr/=Kc,Kc<0){if(Wr0){if(Wr>Ka)return;Wr>El&&(El=Wr)}if(Wr=Ro-Dl,Kc||!(Wr<0)){if(Wr/=Kc,Kc<0){if(Wr>Ka)return;Wr>El&&(El=Wr)}else if(Kc>0){if(Wr0&&(Gi[0]=za+El*Sd,Gi[1]=Dl+El*Kc),Ka<1&&(or[0]=za+Ka*Sd,or[1]=Dl+Ka*Kc),!0}}}}})(zi,Pi,L,R,X,q)?(gn||(fi.lineStart(),fi.point(zi[0],zi[1])),fi.point(Pi[0],Pi[1]),Qn||fi.lineEnd(),Dn=!1):Qn&&(fi.lineStart(),fi.point(Ji,Tn),Dn=!1)}Kt=Ji,Vt=Tn,gn=Qn}return Ri}}function xee(){var L,R,X,q=0,fe=0,be=960,Se=500;return X={stream:function(Ee){return L&&R===Ee?L:L=AC(q,fe,be,Se)(R=Ee)},extent:function(Ee){return arguments.length?(q=+Ee[0][0],fe=+Ee[0][1],be=+Ee[1][0],Se=+Ee[1][1],L=R=null,X):[[q,fe],[be,Se]]}}}var eL,tL,nL,XD=h3(),l5={sphere:$s,point:$s,lineStart:function(){l5.point=See,l5.lineEnd=Eee},lineEnd:$s,polygonStart:$s,polygonEnd:$s};function Eee(){l5.point=l5.lineEnd=$s}function See(L,R){eL=L*=xl,tL=br(R*=xl),nL=ol(R),l5.point=Mee}function Mee(L,R){L*=xl;var X=br(R*=xl),q=ol(R),fe=is(L-eL),be=ol(fe),Se=q*br(fe),Ee=nL*X-tL*q*be,Oe=tL*X+nL*q*be;XD.add(Xf(qc(Se*Se+Ee*Ee),Oe)),eL=L,tL=X,nL=q}function QD(L){return XD.reset(),$1(L,l5),+XD}var ZD=[null,null],Tee={type:"LineString",coordinates:ZD};function iL(L,R){return ZD[0]=L,ZD[1]=R,QD(Tee)}var qD={Feature:function(L,R){return oL(L.geometry,R)},FeatureCollection:function(L,R){for(var X=L.features,q=-1,fe=X.length;++q0&&(fe=iL(L[be],L[be-1]))>0&&X<=fe&&q<=fe&&(X+q-fe)*(1-Math.pow((X-q)/fe,2))Jl}).map(Oe)).concat(M(rC(be/It)*It,fe,It).filter(function(un){return is(un%Jt)>Jl}).map(Ue))}return Vt.lines=function(){return gn().map(function(un){return{type:"LineString",coordinates:un}})},Vt.outline=function(){return{type:"Polygon",coordinates:[rt(q).concat(vt(Se).slice(1),rt(X).reverse().slice(1),vt(Ee).reverse().slice(1))]}},Vt.extent=function(un){return arguments.length?Vt.extentMajor(un).extentMinor(un):Vt.extentMinor()},Vt.extentMajor=function(un){return arguments.length?(q=+un[0][0],X=+un[1][0],Ee=+un[0][1],Se=+un[1][1],q>X&&(un=q,q=X,X=un),Ee>Se&&(un=Ee,Ee=Se,Se=un),Vt.precision(Kt)):[[q,Ee],[X,Se]]},Vt.extentMinor=function(un){return arguments.length?(R=+un[0][0],L=+un[1][0],be=+un[0][1],fe=+un[1][1],R>L&&(un=R,R=L,L=un),be>fe&&(un=be,be=fe,fe=un),Vt.precision(Kt)):[[R,be],[L,fe]]},Vt.step=function(un){return arguments.length?Vt.stepMajor(un).stepMinor(un):Vt.stepMinor()},Vt.stepMajor=function(un){return arguments.length?(Nt=+un[0],Jt=+un[1],Vt):[Nt,Jt]},Vt.stepMinor=function(un){return arguments.length?(nt=+un[0],It=+un[1],Vt):[nt,It]},Vt.precision=function(un){return arguments.length?(Kt=+un,Oe=WH(be,fe,90),Ue=zH(R,L,Kt),rt=WH(Ee,Se,90),vt=zH(q,X,Kt),Vt):Kt},Vt.extentMajor([[-180,-89.999999],[180,89.999999]]).extentMinor([[-180,-80.000001],[180,80.000001]])}function Oee(){return FH()()}function pee(L,R){var X=L[0]*xl,q=L[1]*xl,fe=R[0]*xl,be=R[1]*xl,Se=ol(q),Ee=br(q),Oe=ol(be),Ue=br(be),rt=Se*ol(X),vt=Se*br(X),nt=Oe*ol(fe),It=Oe*br(fe),Nt=2*qd(qc(W7(be-q)+Se*Oe*W7(fe-X))),Jt=br(Nt),Kt=Nt?function(Vt){var gn=br(Vt*=Nt)/Jt,un=br(Nt-Vt)/Jt,Dn=un*rt+gn*nt,fi=un*vt+gn*It,Mi=un*Ee+gn*Ue;return[Xf(fi,Dn)*vc,Xf(Mi,qc(Dn*Dn+fi*fi))*vc]}:function(){return[X*vc,q*vc]};return Kt.distance=Nt,Kt}function wC(L){return L}var _H,JD,$D,ej,tj=h3(),rL=h3(),m3={point:$s,lineStart:$s,lineEnd:$s,polygonStart:function(){m3.lineStart=Iee,m3.lineEnd=Bee},polygonEnd:function(){m3.lineStart=m3.lineEnd=m3.point=$s,tj.add(is(rL)),rL.reset()},result:function(){var L=tj/2;return tj.reset(),L}};function Iee(){m3.point=Pee}function Pee(L,R){m3.point=VH,_H=$D=L,JD=ej=R}function VH(L,R){rL.add(ej*L-$D*R),$D=L,ej=R}function Bee(){VH(_H,JD)}const UH=m3;var vm=1/0,lL=vm,yC=-vm,aL=yC,Nee={point:function(L,R){LyC&&(yC=L),RaL&&(aL=R)},lineStart:$s,lineEnd:$s,polygonStart:$s,polygonEnd:$s,result:function(){var L=[[vm,lL],[yC,aL]];return yC=aL=-(lL=vm=1/0),L}};const sL=Nee;var GH,YH,f4,e0,cL=0,uL=0,LC=0,xC=0,mm=0,a5=0,nj=0,dL=0,EC=0,Ch={point:t0,lineStart:bm,lineEnd:TC,polygonStart:function(){Ch.lineStart=Cm,Ch.lineEnd=fL},polygonEnd:function(){Ch.point=t0,Ch.lineStart=bm,Ch.lineEnd=TC},result:function(){var L=EC?[nj/EC,dL/EC]:a5?[xC/a5,mm/a5]:LC?[cL/LC,uL/LC]:[NaN,NaN];return cL=uL=LC=xC=mm=a5=nj=dL=EC=0,L}};function t0(L,R){cL+=L,uL+=R,++LC}function bm(){Ch.point=SC}function SC(L,R){Ch.point=MC,t0(f4=L,e0=R)}function MC(L,R){var X=L-f4,q=R-e0,fe=qc(X*X+q*q);xC+=fe*(f4+L)/2,mm+=fe*(e0+R)/2,a5+=fe,t0(f4=L,e0=R)}function TC(){Ch.point=t0}function Cm(){Ch.point=DC}function fL(){ij(GH,YH)}function DC(L,R){Ch.point=ij,t0(GH=f4=L,YH=e0=R)}function ij(L,R){var X=L-f4,q=R-e0,fe=qc(X*X+q*q);xC+=fe*(f4+L)/2,mm+=fe*(e0+R)/2,a5+=fe,nj+=(fe=e0*L-f4*R)*(f4+L),dL+=fe*(e0+R),EC+=3*fe,t0(f4=L,e0=R)}const hL=Ch;function XH(L){this._context=L}XH.prototype={_radius:4.5,pointRadius:function(L){return this._radius=L,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){this._line===0&&this._context.closePath(),this._point=NaN},point:function(L,R){switch(this._point){case 0:this._context.moveTo(L,R),this._point=1;break;case 1:this._context.lineTo(L,R);break;default:this._context.moveTo(L+this._radius,R),this._context.arc(L,R,this._radius,0,Yf)}},result:$s};var s5,oj,rj,jC,Am,kL=h3(),gL={point:$s,lineStart:function(){gL.point=Ree},lineEnd:function(){s5&&OC(oj,rj),gL.point=$s},polygonStart:function(){s5=!0},polygonEnd:function(){s5=null},result:function(){var L=+kL;return kL.reset(),L}};function Ree(L,R){gL.point=OC,oj=jC=L,rj=Am=R}function OC(L,R){jC-=L,Am-=R,kL.add(qc(jC*jC+Am*Am)),jC=L,Am=R}const vL=gL;function n0(){this._string=[]}function i2(L){return"m0,"+L+"a"+L+","+L+" 0 1,1 0,"+-2*L+"a"+L+","+L+" 0 1,1 0,"+2*L+"z"}function b3(L,R){var X,q,fe=4.5;function be(Se){return Se&&(typeof fe=="function"&&q.pointRadius(+fe.apply(this,arguments)),$1(Se,X(q))),q.result()}return be.area=function(Se){return $1(Se,X(UH)),UH.result()},be.measure=function(Se){return $1(Se,X(vL)),vL.result()},be.bounds=function(Se){return $1(Se,X(sL)),sL.result()},be.centroid=function(Se){return $1(Se,X(hL)),hL.result()},be.projection=function(Se){return arguments.length?(X=Se==null?(L=null,wC):(L=Se).stream,be):L},be.context=function(Se){return arguments.length?(q=Se==null?(R=null,new n0):new XH(R=Se),typeof fe!="function"&&q.pointRadius(fe),be):R},be.pointRadius=function(Se){return arguments.length?(fe=typeof Se=="function"?Se:(q.pointRadius(+Se),+Se),be):fe},be.projection(L).context(R)}function mL(L){return{stream:c5(L)}}function c5(L){return function(R){var X=new pC;for(var q in L)X[q]=L[q];return X.stream=R,X}}function pC(){}function bL(L,R,X){var q=L.clipExtent&&L.clipExtent();return L.scale(150).translate([0,0]),q!=null&&L.clipExtent(null),$1(X,L.stream(sL)),R(sL.result()),q!=null&&L.clipExtent(q),L}function IC(L,R,X){return bL(L,function(q){var fe=R[1][0]-R[0][0],be=R[1][1]-R[0][1],Se=Math.min(fe/(q[1][0]-q[0][0]),be/(q[1][1]-q[0][1])),Ee=+R[0][0]+(fe-Se*(q[1][0]+q[0][0]))/2,Oe=+R[0][1]+(be-Se*(q[1][1]+q[0][1]))/2;L.scale(150*Se).translate([Ee,Oe])},X)}function lj(L,R,X){return IC(L,[[0,0],R],X)}function aj(L,R,X){return bL(L,function(q){var fe=+R,be=fe/(q[1][0]-q[0][0]),Se=(fe-be*(q[1][0]+q[0][0]))/2,Ee=-be*q[0][1];L.scale(150*be).translate([Se,Ee])},X)}function sj(L,R,X){return bL(L,function(q){var fe=+R,be=fe/(q[1][1]-q[0][1]),Se=-be*q[0][0],Ee=(fe-be*(q[1][1]+q[0][1]))/2;L.scale(150*be).translate([Se,Ee])},X)}n0.prototype={_radius:4.5,_circle:i2(4.5),pointRadius:function(L){return(L=+L)!==this._radius&&(this._radius=L,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){this._line===0&&this._string.push("Z"),this._point=NaN},point:function(L,R){switch(this._point){case 0:this._string.push("M",L,",",R),this._point=1;break;case 1:this._string.push("L",L,",",R);break;default:this._circle==null&&(this._circle=i2(this._radius)),this._string.push("M",L,",",R,this._circle)}},result:function(){if(this._string.length){var L=this._string.join("");return this._string=[],L}return null}},pC.prototype={constructor:pC,point:function(L,R){this.stream.point(L,R)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Hee=ol(30*xl);function CL(L,R){return+R?function(X,q){function fe(be,Se,Ee,Oe,Ue,rt,vt,nt,It,Nt,Jt,Kt,Vt,gn){var un=vt-be,Dn=nt-Se,fi=un*un+Dn*Dn;if(fi>4*q&&Vt--){var Mi=Oe+Nt,Ri=Ue+Jt,wo=rt+Kt,vi=qc(Mi*Mi+Ri*Ri+wo*wo),Ji=qd(wo/=vi),Tn=is(is(wo)-1)q||is((un*Gi+Dn*or)/fi-.5)>.3||Oe*Nt+Ue*Jt+rt*Kt2?Gi[2]%360*xl:0,zi()):[Kt*vc,Vt*vc,gn*vc]},Tn.angle=function(Gi){return arguments.length?(un=Gi%360*xl,zi()):un*vc},Tn.reflectX=function(Gi){return arguments.length?(Dn=Gi?-1:1,zi()):Dn<0},Tn.reflectY=function(Gi){return arguments.length?(fi=Gi?-1:1,zi()):fi<0},Tn.precision=function(Gi){return arguments.length?(Se=CL(Ee,Ji=Gi*Gi),Pi()):qc(Ji)},Tn.fitExtent=function(Gi,or){return IC(Tn,Gi,or)},Tn.fitSize=function(Gi,or){return lj(Tn,Gi,or)},Tn.fitWidth=function(Gi,or){return aj(Tn,Gi,or)},Tn.fitHeight=function(Gi,or){return sj(Tn,Gi,or)},function(){return R=L.apply(this,arguments),Tn.invert=R.invert&&Qn,zi()}}function uj(L){var R=0,X=Ha/3,q=wL(L),fe=q(R,X);return fe.parallels=function(be){return arguments.length?q(R=be[0]*xl,X=be[1]*xl):[R*vc,X*vc]},fe}function ZH(L,R){var X=br(L),q=(X+br(R))/2;if(is(q)=.12&&Kt<.234&&Jt>=-.425&&Jt<-.214?Ee:Kt>=.166&&Kt<.234&&Jt>=-.214&&Jt<-.115?Oe:Se).invert(nt)},rt.stream=function(nt){return L&&R===nt?L:(It=[Se.stream(R=nt),Ee.stream(nt),Oe.stream(nt)],Nt=It.length,L={point:function(Jt,Kt){for(var Vt=-1;++Vt0?Ee<-su+Jl&&(Ee=-su+Jl):Ee>su-Jl&&(Ee=su-Jl);var Oe=fe/lC(LL(Ee),q);return[Oe*br(q*Se),fe-Oe*ol(q*Se)]}return be.invert=function(Se,Ee){var Oe=fe-Ee,Ue=s1(q)*qc(Se*Se+Oe*Oe),rt=Xf(Se,is(Oe))*s1(Oe);return Oe*q<0&&(rt-=Ha*s1(Se)*s1(Oe)),[rt/q,2*Q9(lC(fe/Ue,1/q))-su]},be}function Vee(){return uj($H).scale(109.5).parallels([30,30])}function u5(L,R){return[L,R]}function Uee(){return h4(u5).scale(152.63)}function eW(L,R){var X=ol(L),q=L===R?br(L):(X-ol(R))/(R-L),fe=X/q+L;if(is(q)2?q[2]+90:90]):[(q=X())[0],q[1],q[2]-90]},X([0,0,90]).scale(159.155)}function iW(L,R){return L.parent===R.parent?1:2}function EL(L,R){return L+R.x}function qee(L,R){return Math.max(L,R.y)}function Kee(){var L=iW,R=1,X=1,q=!1;function fe(be){var Se,Ee=0;be.eachAfter(function(nt){var It=nt.children;It?(nt.x=function(Nt){return Nt.reduce(EL,0)/Nt.length}(It),nt.y=function(Nt){return 1+Nt.reduce(qee,0)}(It)):(nt.x=Se?Ee+=L(nt,Se):0,nt.y=0,Se=nt)});var Oe=function(nt){for(var It;It=nt.children;)nt=It[0];return nt}(be),Ue=function(nt){for(var It;It=nt.children;)nt=It[It.length-1];return nt}(be),rt=Oe.x-L(Oe,Ue)/2,vt=Ue.x+L(Ue,Oe)/2;return be.eachAfter(q?function(nt){nt.x=(nt.x-be.x)*R,nt.y=(be.y-nt.y)*X}:function(nt){nt.x=(nt.x-rt)/(vt-rt)*R,nt.y=(1-(be.y?nt.y/be.y:1))*X})}return fe.separation=function(be){return arguments.length?(L=be,fe):L},fe.size=function(be){return arguments.length?(q=!1,R=+be[0],X=+be[1],fe):q?null:[R,X]},fe.nodeSize=function(be){return arguments.length?(q=!0,R=+be[0],X=+be[1],fe):q?[R,X]:null},fe}function Jee(L){var R=0,X=L.children,q=X&&X.length;if(q)for(;--q>=0;)R+=X[q].value;else R=1;L.value=R}function Cj(L,R){var X,q,fe,be,Se,Ee=new wm(L),Oe=+L.value&&(Ee.value=L.value),Ue=[Ee];for(R==null&&(R=$ee);X=Ue.pop();)if(Oe&&(X.value=+X.data.value),(fe=R(X.data))&&(Se=fe.length))for(X.children=new Array(Se),be=Se-1;be>=0;--be)Ue.push(q=X.children[be]=new wm(fe[be])),q.parent=X,q.depth=X.depth+1;return Ee.eachBefore(SL)}function $ee(L){return L.children}function ete(L){L.data=L.data.data}function SL(L){var R=0;do L.height=R;while((L=L.parent)&&L.height<++R)}function wm(L){this.data=L,this.depth=this.height=0,this.parent=null}hj.invert=function(L,R){for(var X,q=R,fe=q*q,be=fe*fe*fe,Se=0;Se<12&&(be=(fe=(q-=X=(q*(NC+RC*fe+be*(u1+d5*fe))-R)/(NC+3*RC*fe+be*(7*u1+9*d5*fe)))*q)*fe*fe,!(is(X)Jl&&--fe>0);return[L/(.8707+(be=q*q)*(be*(be*be*be*(.003971-.001529*be)-.013791)-.131979)),q]},xL.invert=PC(qd),mj.invert=PC(function(L){return 2*Q9(L)}),bj.invert=function(L,R){return[-R,2*Q9(EH(L))-su]},wm.prototype=Cj.prototype={constructor:wm,count:function(){return this.eachAfter(Jee)},each:function(L){var R,X,q,fe,be=this,Se=[be];do for(R=Se.reverse(),Se=[];be=R.pop();)if(L(be),X=be.children)for(q=0,fe=X.length;q=0;--X)fe.push(R[X]);return this},sum:function(L){return this.eachAfter(function(R){for(var X=+L(R.data)||0,q=R.children,fe=q&&q.length;--fe>=0;)X+=q[fe].value;R.value=X})},sort:function(L){return this.eachBefore(function(R){R.children&&R.children.sort(L)})},path:function(L){for(var R=this,X=function(be,Se){if(be===Se)return be;var Ee=be.ancestors(),Oe=Se.ancestors(),Ue=null;for(be=Ee.pop(),Se=Oe.pop();be===Se;)Ue=be,be=Ee.pop(),Se=Oe.pop();return Ue}(R,L),q=[R];R!==X;)R=R.parent,q.push(R);for(var fe=q.length;L!==X;)q.splice(fe,0,L),L=L.parent;return q},ancestors:function(){for(var L=this,R=[L];L=L.parent;)R.push(L);return R},descendants:function(){var L=[];return this.each(function(R){L.push(R)}),L},leaves:function(){var L=[];return this.eachBefore(function(R){R.children||L.push(R)}),L},links:function(){var L=this,R=[];return L.each(function(X){X!==L&&R.push({source:X.parent,target:X})}),R},copy:function(){return Cj(this).eachBefore(ete)}};var ML=Array.prototype.slice;function oW(L){for(var R,X,q=0,fe=(L=function(Se){for(var Ee,Oe,Ue=Se.length;Ue;)Oe=Math.random()*Ue--|0,Ee=Se[Ue],Se[Ue]=Se[Oe],Se[Oe]=Ee;return Se}(ML.call(L))).length,be=[];q0&&X*X>q*q+fe*fe}function Aj(L,R){for(var X=0;X(Se*=Se)?(q=(Ue+Se-fe)/(2*Ue),be=Math.sqrt(Math.max(0,Se/Ue-q*q)),X.x=L.x-q*Ee-be*Oe,X.y=L.y-q*Oe+be*Ee):(q=(Ue+fe-Se)/(2*Ue),be=Math.sqrt(Math.max(0,fe/Ue-q*q)),X.x=R.x+q*Ee-be*Oe,X.y=R.y+q*Oe+be*Ee)):(X.x=R.x+X.r,X.y=R.y)}function sW(L,R){var X=L.r+R.r-1e-6,q=R.x-L.x,fe=R.y-L.y;return X>0&&X*X>q*q+fe*fe}function ym(L){var R=L._,X=L.next._,q=R.r+X.r,fe=(R.x*X.r+X.x*R.r)/q,be=(R.y*X.r+X.y*R.r)/q;return fe*fe+be*be}function DL(L){this._=L,this.next=null,this.previous=null}function cW(L){if(!(fe=L.length))return 0;var R,X,q,fe,be,Se,Ee,Oe,Ue,rt,vt;if((R=L[0]).x=0,R.y=0,!(fe>1))return R.r;if(X=L[1],R.x=-X.r,X.x=R.r,X.y=0,!(fe>2))return R.r+X.r;aW(X,R,q=L[2]),R=new DL(R),X=new DL(X),q=new DL(q),R.next=q.previous=X,X.next=R.previous=q,q.next=X.previous=R;e:for(Ee=3;Ee0)throw new Error("cycle");return Se}return X.id=function(q){return arguments.length?(L=h5(q),X):L},X.parentId=function(q){return arguments.length?(R=h5(q),X):R},X}function ute(L,R){return L.parent===R.parent?1:2}function jL(L){var R=L.children;return R?R[0]:L.t}function yj(L){var R=L.children;return R?R[R.length-1]:L.t}function dte(L,R,X){var q=X/(R.i-L.i);R.c-=q,R.s+=X,L.c+=q,R.z+=X,R.m+=X}function fte(L,R,X){return L.a.parent===R.parent?L.a:X}function OL(L,R){this._=L,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=R}function hte(){var L=ute,R=1,X=1,q=null;function fe(Oe){var Ue=function(Vt){for(var gn,un,Dn,fi,Mi,Ri=new OL(Vt,0),wo=[Ri];gn=wo.pop();)if(Dn=gn._.children)for(gn.children=new Array(Mi=Dn.length),fi=Mi-1;fi>=0;--fi)wo.push(un=gn.children[fi]=new OL(Dn[fi],fi)),un.parent=gn;return(Ri.parent=new OL(null,0)).children=[Ri],Ri}(Oe);if(Ue.eachAfter(be),Ue.parent.m=-Ue.z,Ue.eachBefore(Se),q)Oe.eachBefore(Ee);else{var rt=Oe,vt=Oe,nt=Oe;Oe.eachBefore(function(Vt){Vt.xvt.x&&(vt=Vt),Vt.depth>nt.depth&&(nt=Vt)});var It=rt===vt?1:L(rt,vt)/2,Nt=It-rt.x,Jt=R/(vt.x+It+Nt),Kt=X/(nt.depth||1);Oe.eachBefore(function(Vt){Vt.x=(Vt.x+Nt)*Jt,Vt.y=Vt.depth*Kt})}return Oe}function be(Oe){var Ue=Oe.children,rt=Oe.parent.children,vt=Oe.i?rt[Oe.i-1]:null;if(Ue){(function(It){for(var Nt,Jt=0,Kt=0,Vt=It.children,gn=Vt.length;--gn>=0;)(Nt=Vt[gn]).z+=Jt,Nt.m+=Jt,Jt+=Nt.s+(Kt+=Nt.c)})(Oe);var nt=(Ue[0].z+Ue[Ue.length-1].z)/2;vt?(Oe.z=vt.z+L(Oe._,vt._),Oe.m=Oe.z-nt):Oe.z=nt}else vt&&(Oe.z=vt.z+L(Oe._,vt._));Oe.parent.A=function(It,Nt,Jt){if(Nt){for(var Kt,Vt=It,gn=It,un=Nt,Dn=Vt.parent.children[0],fi=Vt.m,Mi=gn.m,Ri=un.m,wo=Dn.m;un=yj(un),Vt=jL(Vt),un&&Vt;)Dn=jL(Dn),(gn=yj(gn)).a=It,(Kt=un.z+Ri-Vt.z-fi+L(un._,Vt._))>0&&(dte(fte(un,It,Jt),It,Kt),fi+=Kt,Mi+=Kt),Ri+=un.m,fi+=Vt.m,wo+=Dn.m,Mi+=gn.m;un&&!yj(gn)&&(gn.t=un,gn.m+=Ri-Mi),Vt&&!jL(Dn)&&(Dn.t=Vt,Dn.m+=fi-wo,Jt=It)}return Jt}(Oe,vt,Oe.parent.A||rt[0])}function Se(Oe){Oe._.x=Oe.z+Oe.parent.m,Oe.m+=Oe.parent.m}function Ee(Oe){Oe.x*=R,Oe.y=Oe.depth*X}return fe.separation=function(Oe){return arguments.length?(L=Oe,fe):L},fe.size=function(Oe){return arguments.length?(q=!1,R=+Oe[0],X=+Oe[1],fe):q?null:[R,X]},fe.nodeSize=function(Oe){return arguments.length?(q=!0,R=+Oe[0],X=+Oe[1],fe):q?[R,X]:null},fe}function pL(L,R,X,q,fe){for(var be,Se=L.children,Ee=-1,Oe=Se.length,Ue=L.value&&(fe-X)/L.value;++Eent&&(nt=Ee),Kt=rt*rt*Jt,(It=Math.max(nt/Kt,Kt/vt))>Nt){rt-=Ee;break}Nt=It}Vt.push(Se={value:rt,dice:Oe1?q:1)},X}(vW);function kte(){var L=mW,R=!1,X=1,q=1,fe=[0],be=C3,Se=C3,Ee=C3,Oe=C3,Ue=C3;function rt(nt){return nt.x0=nt.y0=0,nt.x1=X,nt.y1=q,nt.eachBefore(vt),fe=[0],R&&nt.eachBefore(kW),nt}function vt(nt){var It=fe[nt.depth],Nt=nt.x0+It,Jt=nt.y0+It,Kt=nt.x1-It,Vt=nt.y1-It;Kt=nt-1){var gn=Ee[vt];return gn.x0=Nt,gn.y0=Jt,gn.x1=Kt,void(gn.y1=Vt)}for(var un=Ue[vt],Dn=It/2+un,fi=vt+1,Mi=nt-1;fi>>1;Ue[Ri]Vt-Jt){var Ji=(Nt*vi+Kt*wo)/It;rt(vt,fi,wo,Nt,Jt,Ji,Vt),rt(fi,nt,vi,Ji,Jt,Kt,Vt)}else{var Tn=(Jt*vi+Vt*wo)/It;rt(vt,fi,wo,Nt,Jt,Kt,Tn),rt(fi,nt,vi,Nt,Tn,Kt,Vt)}})(0,Oe,L.value,R,X,q,fe)}function i0(L,R,X,q,fe){(1&L.depth?pL:HC)(L,R,X,q,fe)}const bW=function L(R){function X(q,fe,be,Se,Ee){if((Oe=q._squarify)&&Oe.ratio===R)for(var Oe,Ue,rt,vt,nt,It=-1,Nt=Oe.length,Jt=q.value;++It1?q:1)},X}(vW);function IL(L){var R=L.length;return function(X){return L[Math.max(0,Math.min(R-1,Math.floor(X*R)))]}}function vte(L,R){var X=Fo(+L,+R);return function(q){var fe=X(q);return fe-360*Math.floor(fe/360)}}function xj(L,R){return L=+L,R=+R,function(X){return Math.round(L*(1-X)+R*X)}}var A3=Math.SQRT2;function CW(L){return((L=Math.exp(L))+1/L)/2}function AW(L,R){var X,q,fe=L[0],be=L[1],Se=L[2],Ee=R[0],Oe=R[1],Ue=R[2],rt=Ee-fe,vt=Oe-be,nt=rt*rt+vt*vt;if(nt<1e-12)q=Math.log(Ue/Se)/A3,X=function(gn){return[fe+gn*rt,be+gn*vt,Se*Math.exp(A3*gn*q)]};else{var It=Math.sqrt(nt),Nt=(Ue*Ue-Se*Se+4*nt)/(2*Se*2*It),Jt=(Ue*Ue-Se*Se-4*nt)/(2*Ue*2*It),Kt=Math.log(Math.sqrt(Nt*Nt+1)-Nt),Vt=Math.log(Math.sqrt(Jt*Jt+1)-Jt);q=(Vt-Kt)/A3,X=function(gn){var un,Dn=gn*q,fi=CW(Kt),Mi=Se/(2*It)*(fi*(un=A3*Dn+Kt,((un=Math.exp(2*un))-1)/(un+1))-function(Ri){return((Ri=Math.exp(Ri))-1/Ri)/2}(Kt));return[fe+Mi*rt,be+Mi*vt,Se*fi/CW(A3*Dn+Kt)]}}return X.duration=1e3*q,X}function Ej(L){return function(R,X){var q=L((R=Zn(R)).h,(X=Zn(X)).h),fe=kr(R.s,X.s),be=kr(R.l,X.l),Se=kr(R.opacity,X.opacity);return function(Ee){return R.h=q(Ee),R.s=fe(Ee),R.l=be(Ee),R.opacity=Se(Ee),R+""}}}const mte=Ej(Fo);var PL=Ej(kr);function WC(L,R){var X=kr((L=ws(L)).l,(R=ws(R)).l),q=kr(L.a,R.a),fe=kr(L.b,R.b),be=kr(L.opacity,R.opacity);return function(Se){return L.l=X(Se),L.a=q(Se),L.b=fe(Se),L.opacity=be(Se),L+""}}function xm(L){return function(R,X){var q=L((R=au(R)).h,(X=au(X)).h),fe=kr(R.c,X.c),be=kr(R.l,X.l),Se=kr(R.opacity,X.opacity);return function(Ee){return R.h=q(Ee),R.c=fe(Ee),R.l=be(Ee),R.opacity=Se(Ee),R+""}}}const zC=xm(Fo);var FC=xm(kr);function _C(L){return function R(X){function q(fe,be){var Se=L((fe=zs(fe)).h,(be=zs(be)).h),Ee=kr(fe.s,be.s),Oe=kr(fe.l,be.l),Ue=kr(fe.opacity,be.opacity);return function(rt){return fe.h=Se(rt),fe.s=Ee(rt),fe.l=Oe(Math.pow(rt,X)),fe.opacity=Ue(rt),fe+""}}return X=+X,q.gamma=R,q}(1)}const Em=_C(Fo);var Sm=_C(kr);function VC(L,R){for(var X=0,q=R.length-1,fe=R[0],be=new Array(q<0?0:q);X1&&BL(L[X[q-2]],L[X[q-1]],L[fe])<=0;)--q;X[q++]=fe}return X.slice(0,q)}function Cte(L){if((X=L.length)<3)return null;var R,X,q=new Array(X),fe=new Array(X);for(R=0;R=0;--R)Ue.push(L[q[be[R]][2]]);for(R=+Ee;REe!=Ue>Ee&&Se<(Oe-X)*(Ee-q)/(Ue-q)+X&&(rt=!rt),Oe=X,Ue=q;return rt}function LW(L){for(var R,X,q=-1,fe=L.length,be=L[fe-1],Se=be[0],Ee=be[1],Oe=0;++q1);return q+fe*Ee*Math.sqrt(-2*Math.log(Se)/Se)}}return X.source=L,X}(k5),Dj=function L(R){function X(){var q=UC.source(R).apply(this,arguments);return function(){return Math.exp(q())}}return X.source=L,X}(k5),o0=function L(R){function X(q){return function(){for(var fe=0,be=0;beq&&(R=X,X=q,q=R),function(fe){return Math.max(X,Math.min(q,fe))}}function v5(L,R,X){var q=L[0],fe=L[1],be=R[0],Se=R[1];return fe2?QC:v5,fe=be=null,vt}function vt(nt){return isNaN(nt=+nt)?X:(fe||(fe=q(Se.map(L),Ee,Oe)))(L(Ue(nt)))}return vt.invert=function(nt){return Ue(R((be||(be=q(Ee,Se.map(L),Ya)))(nt)))},vt.domain=function(nt){return arguments.length?(Se=GC.call(nt,YC),Ue===Lu||(Ue=XC(Se)),rt()):Se.slice()},vt.range=function(nt){return arguments.length?(Ee=y3.call(nt),rt()):Ee.slice()},vt.rangeRound=function(nt){return Ee=y3.call(nt),Oe=xj,rt()},vt.clamp=function(nt){return arguments.length?(Ue=nt?XC(Se):Lu,vt):Ue!==Lu},vt.interpolate=function(nt){return arguments.length?(Oe=nt,rt()):Oe},vt.unknown=function(nt){return arguments.length?(X=nt,vt):X},function(nt,It){return L=nt,R=It,rt()}}function EW(L,R){return RL()(L,R)}function SW(L,R,X,q){var fe,be=H(L,R,X);switch((q=nC(q??",f")).type){case"s":var Se=Math.max(Math.abs(L),Math.abs(R));return q.precision!=null||isNaN(fe=yH(be,Se))||(q.precision=fe),I7(q,Se);case"":case"e":case"g":case"p":case"r":q.precision!=null||isNaN(fe=LH(be,Math.max(Math.abs(L),Math.abs(R))))||(q.precision=fe-(q.type==="e"));break;case"f":case"%":q.precision!=null||isNaN(fe=wH(be))||(q.precision=fe-2*(q.type==="%"))}return X9(q)}function Mm(L){var R=L.domain;return L.ticks=function(X){var q=R();return W(q[0],q[q.length-1],X??10)},L.tickFormat=function(X,q){var fe=R();return SW(fe[0],fe[fe.length-1],X??10,q)},L.nice=function(X){X==null&&(X=10);var q,fe=R(),be=0,Se=fe.length-1,Ee=fe[be],Oe=fe[Se];return Oe0?q=p(Ee=Math.floor(Ee/q)*q,Oe=Math.ceil(Oe/q)*q,X):q<0&&(q=p(Ee=Math.ceil(Ee*q)/q,Oe=Math.floor(Oe*q)/q,X)),q>0?(fe[be]=Math.floor(Ee/q)*q,fe[Se]=Math.ceil(Oe/q)*q,R(fe)):q<0&&(fe[be]=Math.ceil(Ee*q)/q,fe[Se]=Math.floor(Oe*q)/q,R(fe)),L},L}function MW(){var L=EW(Lu,Lu);return L.copy=function(){return wh(L,MW())},Ah.apply(L,arguments),Mm(L)}function TW(L){var R;function X(q){return isNaN(q=+q)?R:q}return X.invert=X,X.domain=X.range=function(q){return arguments.length?(L=GC.call(q,YC),X):L.slice()},X.unknown=function(q){return arguments.length?(R=q,X):R},X.copy=function(){return TW(L).unknown(R)},L=arguments.length?GC.call(L,YC):[0,1],Mm(X)}function DW(L,R){var X,q=0,fe=(L=L.slice()).length-1,be=L[q],Se=L[fe];return Se0){for(;Jtvt)break;gn.push(Nt)}}else for(;Jt=1;--It)if(!((Nt=nt*It)vt)break;gn.push(Nt)}}else gn=W(Jt,Kt,Math.min(Kt-Jt,Vt)).map(X);return Oe?gn.reverse():gn},q.tickFormat=function(Ee,Oe){if(Oe==null&&(Oe=be===10?".0e":","),typeof Oe!="function"&&(Oe=X9(Oe)),Ee===1/0)return Oe;Ee==null&&(Ee=10);var Ue=Math.max(1,be*Ee/q.ticks().length);return function(rt){var vt=rt/X(Math.round(R(rt)));return vt*be0?q[Ee-1]:R[0],Ee=q?[fe[q-1],X]:[fe[Ue-1],fe[Ue]]},Se.unknown=function(Oe){return arguments.length&&(L=Oe),Se},Se.thresholds=function(){return fe.slice()},Se.copy=function(){return _L().domain([R,X]).range(be).unknown(L)},Ah.apply(Mm(Se),arguments)}function VL(){var L,R=[.5],X=[0,1],q=1;function fe(be){return be<=be?X[u(R,be,0,q)]:L}return fe.domain=function(be){return arguments.length?(R=y3.call(be),q=Math.min(R.length,X.length-1),fe):R.slice()},fe.range=function(be){return arguments.length?(X=y3.call(be),q=Math.min(R.length,X.length-1),fe):X.slice()},fe.invertExtent=function(be){var Se=X.indexOf(be);return[R[Se-1],R[Se]]},fe.unknown=function(be){return arguments.length?(L=be,fe):L},fe.copy=function(){return VL().domain(R).range(X).unknown(L)},Ah.apply(fe,arguments)}var Fj=new Date,UL=new Date;function sd(L,R,X,q){function fe(be){return L(be=arguments.length===0?new Date:new Date(+be)),be}return fe.floor=function(be){return L(be=new Date(+be)),be},fe.ceil=function(be){return L(be=new Date(be-1)),R(be,1),L(be),be},fe.round=function(be){var Se=fe(be),Ee=fe.ceil(be);return be-Se0))return Ue;do Ue.push(Oe=new Date(+be)),R(be,Ee),L(be);while(Oe=Se)for(;L(Se),!be(Se);)Se.setTime(Se-1)},function(Se,Ee){if(Se>=Se)if(Ee<0)for(;++Ee<=0;)for(;R(Se,-1),!be(Se););else for(;--Ee>=0;)for(;R(Se,1),!be(Se););})},X&&(fe.count=function(be,Se){return Fj.setTime(+be),UL.setTime(+Se),L(Fj),L(UL),Math.floor(X(Fj,UL))},fe.every=function(be){return be=Math.floor(be),isFinite(be)&&be>0?be>1?fe.filter(q?function(Se){return q(Se)%be==0}:function(Se){return fe.count(0,Se)%be==0}):fe:null}),fe}var _j=sd(function(L){L.setMonth(0,1),L.setHours(0,0,0,0)},function(L,R){L.setFullYear(L.getFullYear()+R)},function(L,R){return R.getFullYear()-L.getFullYear()},function(L){return L.getFullYear()});_j.every=function(L){return isFinite(L=Math.floor(L))&&L>0?sd(function(R){R.setFullYear(Math.floor(R.getFullYear()/L)*L),R.setMonth(0,1),R.setHours(0,0,0,0)},function(R,X){R.setFullYear(R.getFullYear()+X*L)}):null};const Tm=_j;var wte=_j.range,PW=sd(function(L){L.setDate(1),L.setHours(0,0,0,0)},function(L,R){L.setMonth(L.getMonth()+R)},function(L,R){return R.getMonth()-L.getMonth()+12*(R.getFullYear()-L.getFullYear())},function(L){return L.getMonth()});const BW=PW;var yte=PW.range,GL=1e3,Dm=6e4,YL=36e5,NW=864e5,RW=6048e5;function jm(L){return sd(function(R){R.setDate(R.getDate()-(R.getDay()+7-L)%7),R.setHours(0,0,0,0)},function(R,X){R.setDate(R.getDate()+7*X)},function(R,X){return(X-R-(X.getTimezoneOffset()-R.getTimezoneOffset())*Dm)/RW})}var JC=jm(0),$C=jm(1),HW=jm(2),WW=jm(3),L3=jm(4),zW=jm(5),FW=jm(6),_W=JC.range,Lte=$C.range,xte=HW.range,Nk=WW.range,VW=L3.range,Rk=zW.range,Ete=FW.range,UW=sd(function(L){L.setHours(0,0,0,0)},function(L,R){L.setDate(L.getDate()+R)},function(L,R){return(R-L-(R.getTimezoneOffset()-L.getTimezoneOffset())*Dm)/NW},function(L){return L.getDate()-1});const x3=UW;var GW=UW.range,Vj=sd(function(L){L.setTime(L-L.getMilliseconds()-L.getSeconds()*GL-L.getMinutes()*Dm)},function(L,R){L.setTime(+L+R*YL)},function(L,R){return(R-L)/YL},function(L){return L.getHours()});const Uj=Vj;var Ste=Vj.range,XL=sd(function(L){L.setTime(L-L.getMilliseconds()-L.getSeconds()*GL)},function(L,R){L.setTime(+L+R*Dm)},function(L,R){return(R-L)/Dm},function(L){return L.getMinutes()});const Gj=XL;var Yj=XL.range,YW=sd(function(L){L.setTime(L-L.getMilliseconds())},function(L,R){L.setTime(+L+R*GL)},function(L,R){return(R-L)/GL},function(L){return L.getUTCSeconds()});const m5=YW;var b5=YW.range,l0=sd(function(){},function(L,R){L.setTime(+L+R)},function(L,R){return R-L});l0.every=function(L){return L=Math.floor(L),isFinite(L)&&L>0?L>1?sd(function(R){R.setTime(Math.floor(R/L)*L)},function(R,X){R.setTime(+R+X*L)},function(R,X){return(X-R)/L}):l0:null};const eA=l0;var tA=l0.range;function Hk(L){return sd(function(R){R.setUTCDate(R.getUTCDate()-(R.getUTCDay()+7-L)%7),R.setUTCHours(0,0,0,0)},function(R,X){R.setUTCDate(R.getUTCDate()+7*X)},function(R,X){return(X-R)/RW})}var nA=Hk(0),E3=Hk(1),Om=Hk(2),Xj=Hk(3),Ld=Hk(4),xu=Hk(5),pm=Hk(6),QL=nA.range,Mte=E3.range,a0=Om.range,Im=Xj.range,ZL=Ld.range,qL=xu.range,Qj=pm.range,KL=sd(function(L){L.setUTCHours(0,0,0,0)},function(L,R){L.setUTCDate(L.getUTCDate()+R)},function(L,R){return(R-L)/NW},function(L){return L.getUTCDate()-1});const JL=KL;var Tte=KL.range,iA=sd(function(L){L.setUTCMonth(0,1),L.setUTCHours(0,0,0,0)},function(L,R){L.setUTCFullYear(L.getUTCFullYear()+R)},function(L,R){return R.getUTCFullYear()-L.getUTCFullYear()},function(L){return L.getUTCFullYear()});iA.every=function(L){return isFinite(L=Math.floor(L))&&L>0?sd(function(R){R.setUTCFullYear(Math.floor(R.getUTCFullYear()/L)*L),R.setUTCMonth(0,1),R.setUTCHours(0,0,0,0)},function(R,X){R.setUTCFullYear(R.getUTCFullYear()+X*L)}):null};const Pm=iA;var Dte=iA.range;function Zj(L){if(0<=L.y&&L.y<100){var R=new Date(-1,L.m,L.d,L.H,L.M,L.S,L.L);return R.setFullYear(L.y),R}return new Date(L.y,L.m,L.d,L.H,L.M,L.S,L.L)}function C5(L){if(0<=L.y&&L.y<100){var R=new Date(Date.UTC(-1,L.m,L.d,L.H,L.M,L.S,L.L));return R.setUTCFullYear(L.y),R}return new Date(Date.UTC(L.y,L.m,L.d,L.H,L.M,L.S,L.L))}function A5(L,R,X){return{y:L,m:R,d:X,H:0,M:0,S:0,L:0}}function XW(L){var R=L.dateTime,X=L.date,q=L.time,fe=L.periods,be=L.days,Se=L.shortDays,Ee=L.months,Oe=L.shortMonths,Ue=w5(fe),rt=Eu(fe),vt=w5(be),nt=Eu(be),It=w5(Se),Nt=Eu(Se),Jt=w5(Ee),Kt=Eu(Ee),Vt=w5(Oe),gn=Eu(Oe),un={a:function(vi){return Se[vi.getDay()]},A:function(vi){return be[vi.getDay()]},b:function(vi){return Oe[vi.getMonth()]},B:function(vi){return Ee[vi.getMonth()]},c:null,d:Zr,e:Zr,f:Jj,g:Fte,G:_te,H:JW,I:fs,j:$l,L:Af,m:Pte,M:Bte,p:function(vi){return fe[+(vi.getHours()>=12)]},q:function(vi){return 1+~~(vi.getMonth()/3)},Q:cA,s:s0,S:$j,u:Nte,U:Rte,V:Hte,w:Wte,W:eO,x:null,X:null,y:zte,Y:tO,Z:Vte,"%":aO},Dn={a:function(vi){return Se[vi.getUTCDay()]},A:function(vi){return be[vi.getUTCDay()]},b:function(vi){return Oe[vi.getUTCMonth()]},B:function(vi){return Ee[vi.getUTCMonth()]},c:null,d:_k,e:_k,f:Ute,g:ax,G:qte,H:nO,I:iO,j:oO,L:Rm,m:Gte,M:Yte,p:function(vi){return fe[+(vi.getUTCHours()>=12)]},q:function(vi){return 1+~~(vi.getUTCMonth()/3)},Q:cA,s:s0,S:Xte,u:$W,U:r2,V:ez,w:lO,W:lx,x:null,X:null,y:Qte,Y:Zte,Z:tz,"%":aO},fi={a:function(vi,Ji,Tn){var Qn=It.exec(Ji.slice(Tn));return Qn?(vi.w=Nt[Qn[0].toLowerCase()],Tn+Qn[0].length):-1},A:function(vi,Ji,Tn){var Qn=vt.exec(Ji.slice(Tn));return Qn?(vi.w=nt[Qn[0].toLowerCase()],Tn+Qn[0].length):-1},b:function(vi,Ji,Tn){var Qn=Vt.exec(Ji.slice(Tn));return Qn?(vi.m=gn[Qn[0].toLowerCase()],Tn+Qn[0].length):-1},B:function(vi,Ji,Tn){var Qn=Jt.exec(Ji.slice(Tn));return Qn?(vi.m=Kt[Qn[0].toLowerCase()],Tn+Qn[0].length):-1},c:function(vi,Ji,Tn){return wo(vi,R,Ji,Tn)},d:aA,e:aA,f:Fk,g:rA,G:zk,H:Kj,I:Kj,j:ix,L:Ite,m:nx,M:qW,p:function(vi,Ji,Tn){var Qn=Ue.exec(Ji.slice(Tn));return Qn?(vi.p=rt[Qn[0].toLowerCase()],Tn+Qn[0].length):-1},q:lA,Q:ir,s:sA,S:ox,u:tx,U:Ote,V:pte,w:pa,W:da,x:function(vi,Ji,Tn){return wo(vi,X,Ji,Tn)},X:function(vi,Ji,Tn){return wo(vi,q,Ji,Tn)},y:rA,Y:zk,Z:ZW,"%":KW};function Mi(vi,Ji){return function(Tn){var Qn,zi,Pi,Gi=[],or=-1,Lr=0,ml=vi.length;for(Tn instanceof Date||(Tn=new Date(+Tn));++or53)return null;"w"in Pi||(Pi.w=1),"Z"in Pi?(zi=(Qn=C5(A5(Pi.y,0,1))).getUTCDay(),Qn=zi>4||zi===0?E3.ceil(Qn):E3(Qn),Qn=JL.offset(Qn,7*(Pi.V-1)),Pi.y=Qn.getUTCFullYear(),Pi.m=Qn.getUTCMonth(),Pi.d=Qn.getUTCDate()+(Pi.w+6)%7):(zi=(Qn=Zj(A5(Pi.y,0,1))).getDay(),Qn=zi>4||zi===0?$C.ceil(Qn):$C(Qn),Qn=x3.offset(Qn,7*(Pi.V-1)),Pi.y=Qn.getFullYear(),Pi.m=Qn.getMonth(),Pi.d=Qn.getDate()+(Pi.w+6)%7)}else("W"in Pi||"U"in Pi)&&("w"in Pi||(Pi.w="u"in Pi?Pi.u%7:"W"in Pi?1:0),zi="Z"in Pi?C5(A5(Pi.y,0,1)).getUTCDay():Zj(A5(Pi.y,0,1)).getDay(),Pi.m=0,Pi.d="W"in Pi?(Pi.w+6)%7+7*Pi.W-(zi+5)%7:Pi.w+7*Pi.U-(zi+6)%7);return"Z"in Pi?(Pi.H+=Pi.Z/100|0,Pi.M+=Pi.Z%100,C5(Pi)):Zj(Pi)}}function wo(vi,Ji,Tn,Qn){for(var zi,Pi,Gi=0,or=Ji.length,Lr=Tn.length;Gi=Lr)return-1;if((zi=Ji.charCodeAt(Gi++))===37){if(zi=Ji.charAt(Gi++),!(Pi=fi[zi in qj?Ji.charAt(Gi++):zi])||(Qn=Pi(vi,Tn,Qn))<0)return-1}else if(zi!=Tn.charCodeAt(Qn++))return-1}return Qn}return un.x=Mi(X,un),un.X=Mi(q,un),un.c=Mi(R,un),Dn.x=Mi(X,Dn),Dn.X=Mi(q,Dn),Dn.c=Mi(R,Dn),{format:function(vi){var Ji=Mi(vi+="",un);return Ji.toString=function(){return vi},Ji},parse:function(vi){var Ji=Ri(vi+="",!1);return Ji.toString=function(){return vi},Ji},utcFormat:function(vi){var Ji=Mi(vi+="",Dn);return Ji.toString=function(){return vi},Ji},utcParse:function(vi){var Ji=Ri(vi+="",!0);return Ji.toString=function(){return vi},Ji}}}var Bm,$L,Nm,ex,oA,qj={"-":"",_:" ",0:"0"},cd=/^\s*\d+/,QW=/^%/,Wk=/[\\^$*+?|[\]().{}]/g;function rs(L,R,X){var q=L<0?"-":"",fe=(q?-L:L)+"",be=fe.length;return q+(be68?1900:2e3),X+q[0].length):-1}function ZW(L,R,X){var q=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(R.slice(X,X+6));return q?(L.Z=q[1]?0:-(q[2]+(q[3]||"00")),X+q[0].length):-1}function lA(L,R,X){var q=cd.exec(R.slice(X,X+1));return q?(L.q=3*q[0]-3,X+q[0].length):-1}function nx(L,R,X){var q=cd.exec(R.slice(X,X+2));return q?(L.m=q[0]-1,X+q[0].length):-1}function aA(L,R,X){var q=cd.exec(R.slice(X,X+2));return q?(L.d=+q[0],X+q[0].length):-1}function ix(L,R,X){var q=cd.exec(R.slice(X,X+3));return q?(L.m=0,L.d=+q[0],X+q[0].length):-1}function Kj(L,R,X){var q=cd.exec(R.slice(X,X+2));return q?(L.H=+q[0],X+q[0].length):-1}function qW(L,R,X){var q=cd.exec(R.slice(X,X+2));return q?(L.M=+q[0],X+q[0].length):-1}function ox(L,R,X){var q=cd.exec(R.slice(X,X+2));return q?(L.S=+q[0],X+q[0].length):-1}function Ite(L,R,X){var q=cd.exec(R.slice(X,X+3));return q?(L.L=+q[0],X+q[0].length):-1}function Fk(L,R,X){var q=cd.exec(R.slice(X,X+6));return q?(L.L=Math.floor(q[0]/1e3),X+q[0].length):-1}function KW(L,R,X){var q=QW.exec(R.slice(X,X+1));return q?X+q[0].length:-1}function ir(L,R,X){var q=cd.exec(R.slice(X));return q?(L.Q=+q[0],X+q[0].length):-1}function sA(L,R,X){var q=cd.exec(R.slice(X));return q?(L.s=+q[0],X+q[0].length):-1}function Zr(L,R){return rs(L.getDate(),R,2)}function JW(L,R){return rs(L.getHours(),R,2)}function fs(L,R){return rs(L.getHours()%12||12,R,2)}function $l(L,R){return rs(1+x3.count(Tm(L),L),R,3)}function Af(L,R){return rs(L.getMilliseconds(),R,3)}function Jj(L,R){return Af(L,R)+"000"}function Pte(L,R){return rs(L.getMonth()+1,R,2)}function Bte(L,R){return rs(L.getMinutes(),R,2)}function $j(L,R){return rs(L.getSeconds(),R,2)}function Nte(L){var R=L.getDay();return R===0?7:R}function Rte(L,R){return rs(JC.count(Tm(L)-1,L),R,2)}function rx(L){var R=L.getDay();return R>=4||R===0?L3(L):L3.ceil(L)}function Hte(L,R){return L=rx(L),rs(L3.count(Tm(L),L)+(Tm(L).getDay()===4),R,2)}function Wte(L){return L.getDay()}function eO(L,R){return rs($C.count(Tm(L)-1,L),R,2)}function zte(L,R){return rs(L.getFullYear()%100,R,2)}function Fte(L,R){return rs((L=rx(L)).getFullYear()%100,R,2)}function tO(L,R){return rs(L.getFullYear()%1e4,R,4)}function _te(L,R){var X=L.getDay();return rs((L=X>=4||X===0?L3(L):L3.ceil(L)).getFullYear()%1e4,R,4)}function Vte(L){var R=L.getTimezoneOffset();return(R>0?"-":(R*=-1,"+"))+rs(R/60|0,"0",2)+rs(R%60,"0",2)}function _k(L,R){return rs(L.getUTCDate(),R,2)}function nO(L,R){return rs(L.getUTCHours(),R,2)}function iO(L,R){return rs(L.getUTCHours()%12||12,R,2)}function oO(L,R){return rs(1+JL.count(Pm(L),L),R,3)}function Rm(L,R){return rs(L.getUTCMilliseconds(),R,3)}function Ute(L,R){return Rm(L,R)+"000"}function Gte(L,R){return rs(L.getUTCMonth()+1,R,2)}function Yte(L,R){return rs(L.getUTCMinutes(),R,2)}function Xte(L,R){return rs(L.getUTCSeconds(),R,2)}function $W(L){var R=L.getUTCDay();return R===0?7:R}function r2(L,R){return rs(nA.count(Pm(L)-1,L),R,2)}function rO(L){var R=L.getUTCDay();return R>=4||R===0?Ld(L):Ld.ceil(L)}function ez(L,R){return L=rO(L),rs(Ld.count(Pm(L),L)+(Pm(L).getUTCDay()===4),R,2)}function lO(L){return L.getUTCDay()}function lx(L,R){return rs(E3.count(Pm(L)-1,L),R,2)}function Qte(L,R){return rs(L.getUTCFullYear()%100,R,2)}function ax(L,R){return rs((L=rO(L)).getUTCFullYear()%100,R,2)}function Zte(L,R){return rs(L.getUTCFullYear()%1e4,R,4)}function qte(L,R){var X=L.getUTCDay();return rs((L=X>=4||X===0?Ld(L):Ld.ceil(L)).getUTCFullYear()%1e4,R,4)}function tz(){return"+0000"}function aO(){return"%"}function cA(L){return+L}function s0(L){return Math.floor(+L/1e3)}function Hm(L){return Bm=XW(L),$L=Bm.format,Nm=Bm.parse,ex=Bm.utcFormat,oA=Bm.utcParse,Bm}Hm({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var v4=31536e6;function nz(L){return new Date(L)}function iz(L){return L instanceof Date?+L:+new Date(+L)}function sx(L,R,X,q,fe,be,Se,Ee,Oe){var Ue=EW(Lu,Lu),rt=Ue.invert,vt=Ue.domain,nt=Oe(".%L"),It=Oe(":%S"),Nt=Oe("%I:%M"),Jt=Oe("%I %p"),Kt=Oe("%a %d"),Vt=Oe("%b %d"),gn=Oe("%B"),un=Oe("%Y"),Dn=[[Se,1,1e3],[Se,5,5e3],[Se,15,15e3],[Se,30,3e4],[be,1,6e4],[be,5,3e5],[be,15,9e5],[be,30,18e5],[fe,1,36e5],[fe,3,108e5],[fe,6,216e5],[fe,12,432e5],[q,1,864e5],[q,2,1728e5],[X,1,6048e5],[R,1,2592e6],[R,3,7776e6],[L,1,v4]];function fi(Ri){return(Se(Ri)1)&&(L-=Math.floor(L));var R=Math.abs(L-.5);return y4.h=360*L-100,y4.s=1.5-1.5*R,y4.l=.8-.9*R,y4+""}var AA=ac(),yz=Math.PI/3,D5=2*Math.PI/3;function Lz(L){var R;return L=(.5-L)*Math.PI,AA.r=255*(R=Math.sin(L))*R,AA.g=255*(R=Math.sin(L+yz))*R,AA.b=255*(R=Math.sin(L+D5))*R,AA+""}function une(L){return L=Math.max(0,Math.min(1,L)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+L*(1172.33-L*(10793.56-L*(33300.12-L*(38394.49-14825.05*L)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+L*(557.33+L*(1225.33-L*(3574.96-L*(1073.77+707.56*L)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+L*(3211.1-L*(15327.97-L*(27814-L*(22569.18-6838.66*L)))))))+")"}function wA(L){var R=L.length;return function(X){return L[Math.max(0,Math.min(R-1,Math.floor(X*R)))]}}const Cx=wA(va("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));var tf=wA(va("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),dne=wA(va("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),Ax=wA(va("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function fne(L){return nl(zt(L).call(document.documentElement))}var xz=0;function Ez(){return new yA}function yA(){this._="@"+(++xz).toString(36)}function Sz(L){return typeof L=="string"?new Ko([document.querySelectorAll(L)],[document.documentElement]):new Ko([L??[]],Or)}function Mz(L,R){R==null&&(R=Rf().touches);for(var X=0,q=R?R.length:0,fe=new Array(q);X1?0:L<-1?Gk:Math.acos(L)}function Lx(L){return L>=1?LA:L<=-1?-LA:Math.asin(L)}function wO(L){return L.innerRadius}function Xk(L){return L.outerRadius}function xx(L){return L.startAngle}function gne(L){return L.endAngle}function Tz(L){return L&&L.padAngle}function yO(L,R,X,q,fe,be,Se,Ee){var Oe=X-L,Ue=q-R,rt=Se-fe,vt=Ee-be,nt=vt*Oe-rt*Ue;if(!(nt*ntPi*Pi+Gi*Gi&&(wo=Ji,vi=Tn),{cx:wo,cy:vi,x01:-rt,y01:-vt,x11:wo*(fe/fi-1),y11:vi*(fe/fi-1)}}function Wm(){var L=wO,R=Xk,X=ma(0),q=null,fe=xx,be=gne,Se=Tz,Ee=null;function Oe(){var Ue,rt,vt=+L.apply(this,arguments),nt=+R.apply(this,arguments),It=fe.apply(this,arguments)-LA,Nt=be.apply(this,arguments)-LA,Jt=wx(Nt-It),Kt=Nt>It;if(Ee||(Ee=Ue=Mn()),ntba)if(Jt>Yk-ba)Ee.moveTo(nt*Fu(It),nt*Ed(It)),Ee.arc(0,0,nt,It,Nt,!Kt),vt>ba&&(Ee.moveTo(vt*Fu(Nt),vt*Ed(Nt)),Ee.arc(0,0,vt,Nt,It,Kt));else{var Vt,gn,un=It,Dn=Nt,fi=It,Mi=Nt,Ri=Jt,wo=Jt,vi=Se.apply(this,arguments)/2,Ji=vi>ba&&(q?+q.apply(this,arguments):d1(vt*vt+nt*nt)),Tn=yx(wx(nt-vt)/2,+X.apply(this,arguments)),Qn=Tn,zi=Tn;if(Ji>ba){var Pi=Lx(Ji/vt*Ed(vi)),Gi=Lx(Ji/nt*Ed(vi));(Ri-=2*Pi)>ba?(fi+=Pi*=Kt?1:-1,Mi-=Pi):(Ri=0,fi=Mi=(It+Nt)/2),(wo-=2*Gi)>ba?(un+=Gi*=Kt?1:-1,Dn-=Gi):(wo=0,un=Dn=(It+Nt)/2)}var or=nt*Fu(un),Lr=nt*Ed(un),ml=vt*Fu(Mi),Ei=vt*Ed(Mi);if(Tn>ba){var Ro,Wr=nt*Fu(Dn),za=nt*Ed(Dn),Dl=vt*Fu(fi),El=vt*Ed(fi);if(Jtba?zi>ba?(Vt=Dc(Dl,El,or,Lr,nt,zi,Kt),gn=Dc(Wr,za,ml,Ei,nt,zi,Kt),Ee.moveTo(Vt.cx+Vt.x01,Vt.cy+Vt.y01),ziba&&Ri>ba?Qn>ba?(Vt=Dc(ml,Ei,Wr,za,vt,-Qn,Kt),gn=Dc(or,Lr,Dl,El,vt,-Qn,Kt),Ee.lineTo(Vt.cx+Vt.x01,Vt.cy+Vt.y01),Qn=nt;--It)Ee.point(gn[It],un[It]);Ee.lineEnd(),Ee.areaEnd()}Vt&&(gn[vt]=+L(Nt,vt,rt),un[vt]=+X(Nt,vt,rt),Ee.point(R?+R(Nt,vt,rt):gn[vt],q?+q(Nt,vt,rt):un[vt]))}if(Jt)return Ee=null,Jt+""||null}function Ue(){return EA().defined(fe).curve(Se).context(be)}return Oe.x=function(rt){return arguments.length?(L=typeof rt=="function"?rt:ma(+rt),R=null,Oe):L},Oe.x0=function(rt){return arguments.length?(L=typeof rt=="function"?rt:ma(+rt),Oe):L},Oe.x1=function(rt){return arguments.length?(R=rt==null?null:typeof rt=="function"?rt:ma(+rt),Oe):R},Oe.y=function(rt){return arguments.length?(X=typeof rt=="function"?rt:ma(+rt),q=null,Oe):X},Oe.y0=function(rt){return arguments.length?(X=typeof rt=="function"?rt:ma(+rt),Oe):X},Oe.y1=function(rt){return arguments.length?(q=rt==null?null:typeof rt=="function"?rt:ma(+rt),Oe):q},Oe.lineX0=Oe.lineY0=function(){return Ue().x(L).y(X)},Oe.lineY1=function(){return Ue().x(L).y(q)},Oe.lineX1=function(){return Ue().x(R).y(X)},Oe.defined=function(rt){return arguments.length?(fe=typeof rt=="function"?rt:ma(!!rt),Oe):fe},Oe.curve=function(rt){return arguments.length?(Se=rt,be!=null&&(Ee=Se(be)),Oe):Se},Oe.context=function(rt){return arguments.length?(rt==null?be=Ee=null:Ee=Se(be=rt),Oe):be},Oe}function Sx(L,R){return RL?1:R>=L?0:NaN}function Mx(L){return L}function Tx(){var L=Mx,R=Sx,X=null,q=ma(0),fe=ma(Yk),be=ma(0);function Se(Ee){var Oe,Ue,rt,vt,nt,It=Ee.length,Nt=0,Jt=new Array(It),Kt=new Array(It),Vt=+q.apply(this,arguments),gn=Math.min(Yk,Math.max(-Yk,fe.apply(this,arguments)-Vt)),un=Math.min(Math.abs(gn)/It,be.apply(this,arguments)),Dn=un*(gn<0?-1:1);for(Oe=0;Oe0&&(Nt+=nt);for(R!=null?Jt.sort(function(fi,Mi){return R(Kt[fi],Kt[Mi])}):X!=null&&Jt.sort(function(fi,Mi){return X(Ee[fi],Ee[Mi])}),Oe=0,rt=Nt?(gn-It*Dn)/Nt:0;Oe0?nt*rt:0)+Dn,Kt[Ue]={data:Ee[Ue],index:Oe,value:nt,startAngle:Vt,endAngle:vt,padAngle:un};return Kt}return Se.value=function(Ee){return arguments.length?(L=typeof Ee=="function"?Ee:ma(+Ee),Se):L},Se.sortValues=function(Ee){return arguments.length?(R=Ee,X=null,Se):R},Se.sort=function(Ee){return arguments.length?(X=Ee,R=null,Se):X},Se.startAngle=function(Ee){return arguments.length?(q=typeof Ee=="function"?Ee:ma(+Ee),Se):q},Se.endAngle=function(Ee){return arguments.length?(fe=typeof Ee=="function"?Ee:ma(+Ee),Se):fe},Se.padAngle=function(Ee){return arguments.length?(be=typeof Ee=="function"?Ee:ma(+Ee),Se):be},Se}zm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._line?this._context.lineTo(L,R):this._context.moveTo(L,R);break;case 1:this._point=2;default:this._context.lineTo(L,R)}}};var Dz=jx(f1);function Dx(L){this._curve=L}function jx(L){function R(X){return new Dx(L(X))}return R._curve=L,R}function SA(L){var R=L.curve;return L.angle=L.x,delete L.x,L.radius=L.y,delete L.y,L.curve=function(X){return arguments.length?R(jx(X)):R()._curve},L}function Ox(){return SA(EA().curve(Dz))}function LO(){var L=Ex().curve(Dz),R=L.curve,X=L.lineX0,q=L.lineX1,fe=L.lineY0,be=L.lineY1;return L.angle=L.x,delete L.x,L.startAngle=L.x0,delete L.x0,L.endAngle=L.x1,delete L.x1,L.radius=L.y,delete L.y,L.innerRadius=L.y0,delete L.y0,L.outerRadius=L.y1,delete L.y1,L.lineStartAngle=function(){return SA(X())},delete L.lineX0,L.lineEndAngle=function(){return SA(q())},delete L.lineX1,L.lineInnerRadius=function(){return SA(fe())},delete L.lineY0,L.lineOuterRadius=function(){return SA(be())},delete L.lineY1,L.curve=function(Se){return arguments.length?R(jx(Se)):R()._curve},L}function MA(L,R){return[(R=+R)*Math.cos(L-=Math.PI/2),R*Math.sin(L)]}Dx.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(L,R){this._curve.point(R*Math.sin(L),R*-Math.cos(L))}};var px=Array.prototype.slice;function jz(L){return L.source}function Wa(L){return L.target}function xO(L){var R=jz,X=Wa,q=j5,fe=xA,be=null;function Se(){var Ee,Oe=px.call(arguments),Ue=R.apply(this,Oe),rt=X.apply(this,Oe);if(be||(be=Ee=Mn()),L(be,+q.apply(this,(Oe[0]=Ue,Oe)),+fe.apply(this,Oe),+q.apply(this,(Oe[0]=rt,Oe)),+fe.apply(this,Oe)),Ee)return be=null,Ee+""||null}return Se.source=function(Ee){return arguments.length?(R=Ee,Se):R},Se.target=function(Ee){return arguments.length?(X=Ee,Se):X},Se.x=function(Ee){return arguments.length?(q=typeof Ee=="function"?Ee:ma(+Ee),Se):q},Se.y=function(Ee){return arguments.length?(fe=typeof Ee=="function"?Ee:ma(+Ee),Se):fe},Se.context=function(Ee){return arguments.length?(be=Ee??null,Se):be},Se}function Ix(L,R,X,q,fe){L.moveTo(R,X),L.bezierCurveTo(R=(R+q)/2,X,R,fe,q,fe)}function vne(L,R,X,q,fe){L.moveTo(R,X),L.bezierCurveTo(R,X=(X+fe)/2,q,X,q,fe)}function h1(L,R,X,q,fe){var be=MA(R,X),Se=MA(R,X=(X+fe)/2),Ee=MA(q,X),Oe=MA(q,fe);L.moveTo(be[0],be[1]),L.bezierCurveTo(Se[0],Se[1],Ee[0],Ee[1],Oe[0],Oe[1])}function mne(){return xO(Ix)}function Oz(){return xO(vne)}function bne(){var L=xO(h1);return L.angle=L.x,delete L.x,L.radius=L.y,delete L.y,L}const EO={draw:function(L,R){var X=Math.sqrt(R/Gk);L.moveTo(X,0),L.arc(0,0,X,0,Yk)}},pz={draw:function(L,R){var X=Math.sqrt(R/5)/2;L.moveTo(-3*X,-X),L.lineTo(-X,-X),L.lineTo(-X,-3*X),L.lineTo(X,-3*X),L.lineTo(X,-X),L.lineTo(3*X,-X),L.lineTo(3*X,X),L.lineTo(X,X),L.lineTo(X,3*X),L.lineTo(-X,3*X),L.lineTo(-X,X),L.lineTo(-3*X,X),L.closePath()}};var Iz=Math.sqrt(1/3),Cne=2*Iz;const Pz={draw:function(L,R){var X=Math.sqrt(R/Cne),q=X*Iz;L.moveTo(0,-X),L.lineTo(q,0),L.lineTo(0,X),L.lineTo(-q,0),L.closePath()}};var Bz=Math.sin(Gk/10)/Math.sin(7*Gk/10),Ane=Math.sin(Yk/10)*Bz,wne=-Math.cos(Yk/10)*Bz;const Nz={draw:function(L,R){var X=Math.sqrt(.8908130915292852*R),q=Ane*X,fe=wne*X;L.moveTo(0,-X),L.lineTo(q,fe);for(var be=1;be<5;++be){var Se=Yk*be/5,Ee=Math.cos(Se),Oe=Math.sin(Se);L.lineTo(Oe*X,-Ee*X),L.lineTo(Ee*q-Oe*fe,Oe*q+Ee*fe)}L.closePath()}},Rz={draw:function(L,R){var X=Math.sqrt(R),q=-X/2;L.rect(q,q,X,X)}};var d0=Math.sqrt(3);const Hz={draw:function(L,R){var X=-Math.sqrt(R/(3*d0));L.moveTo(0,2*X),L.lineTo(-d0*X,-X),L.lineTo(d0*X,-X),L.closePath()}};var k1=-.5,g1=Math.sqrt(3)/2,SO=1/Math.sqrt(12),Wz=3*(SO/2+1);const MO={draw:function(L,R){var X=Math.sqrt(R/Wz),q=X/2,fe=X*SO,be=q,Se=X*SO+X,Ee=-be,Oe=Se;L.moveTo(q,fe),L.lineTo(be,Se),L.lineTo(Ee,Oe),L.lineTo(k1*q-g1*fe,g1*q+k1*fe),L.lineTo(k1*be-g1*Se,g1*be+k1*Se),L.lineTo(k1*Ee-g1*Oe,g1*Ee+k1*Oe),L.lineTo(k1*q+g1*fe,k1*fe-g1*q),L.lineTo(k1*be+g1*Se,k1*Se-g1*be),L.lineTo(k1*Ee+g1*Oe,k1*Oe-g1*Ee),L.closePath()}};var yne=[EO,pz,Pz,Rz,Nz,Hz,MO];function TO(){var L=ma(EO),R=ma(64),X=null;function q(){var fe;if(X||(X=fe=Mn()),L.apply(this,arguments).draw(X,+R.apply(this,arguments)),fe)return X=null,fe+""||null}return q.type=function(fe){return arguments.length?(L=typeof fe=="function"?fe:ma(fe),q):L},q.size=function(fe){return arguments.length?(R=typeof fe=="function"?fe:ma(+fe),q):R},q.context=function(fe){return arguments.length?(X=fe??null,q):X},q}function L4(){}function Fm(L,R,X){L._context.bezierCurveTo((2*L._x0+L._x1)/3,(2*L._y0+L._y1)/3,(L._x0+2*L._x1)/3,(L._y0+2*L._y1)/3,(L._x0+4*L._x1+R)/6,(L._y0+4*L._y1+X)/6)}function v1(L){this._context=L}function DO(L){return new v1(L)}function Px(L){this._context=L}function TA(L){return new Px(L)}function O5(L){this._context=L}function jO(L){return new O5(L)}function Bx(L,R){this._basis=new v1(L),this._beta=R}v1.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Fm(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._line?this._context.lineTo(L,R):this._context.moveTo(L,R);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Fm(this,L,R)}this._x0=this._x1,this._x1=L,this._y0=this._y1,this._y1=R}},Px.prototype={areaStart:L4,areaEnd:L4,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._x2=L,this._y2=R;break;case 1:this._point=2,this._x3=L,this._y3=R;break;case 2:this._point=3,this._x4=L,this._y4=R,this._context.moveTo((this._x0+4*this._x1+L)/6,(this._y0+4*this._y1+R)/6);break;default:Fm(this,L,R)}this._x0=this._x1,this._x1=L,this._y0=this._y1,this._y1=R}},O5.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var X=(this._x0+4*this._x1+L)/6,q=(this._y0+4*this._y1+R)/6;this._line?this._context.lineTo(X,q):this._context.moveTo(X,q);break;case 3:this._point=4;default:Fm(this,L,R)}this._x0=this._x1,this._x1=L,this._y0=this._y1,this._y1=R}},Bx.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var L=this._x,R=this._y,X=L.length-1;if(X>0)for(var q,fe=L[0],be=R[0],Se=L[X]-fe,Ee=R[X]-be,Oe=-1;++Oe<=X;)q=Oe/X,this._basis.point(this._beta*L[Oe]+(1-this._beta)*(fe+q*Se),this._beta*R[Oe]+(1-this._beta)*(be+q*Ee));this._x=this._y=null,this._basis.lineEnd()},point:function(L,R){this._x.push(+L),this._y.push(+R)}};const OO=function L(R){function X(q){return R===1?new v1(q):new Bx(q,R)}return X.beta=function(q){return L(+q)},X}(.85);function Qk(L,R,X){L._context.bezierCurveTo(L._x1+L._k*(L._x2-L._x0),L._y1+L._k*(L._y2-L._y0),L._x2+L._k*(L._x1-R),L._y2+L._k*(L._y1-X),L._x2,L._y2)}function Nx(L,R){this._context=L,this._k=(1-R)/6}Nx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Qk(this,this._x1,this._y1)}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._line?this._context.lineTo(L,R):this._context.moveTo(L,R);break;case 1:this._point=2,this._x1=L,this._y1=R;break;case 2:this._point=3;default:Qk(this,L,R)}this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const Rx=function L(R){function X(q){return new Nx(q,R)}return X.tension=function(q){return L(+q)},X}(0);function _m(L,R){this._context=L,this._k=(1-R)/6}_m.prototype={areaStart:L4,areaEnd:L4,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._x3=L,this._y3=R;break;case 1:this._point=2,this._context.moveTo(this._x4=L,this._y4=R);break;case 2:this._point=3,this._x5=L,this._y5=R;break;default:Qk(this,L,R)}this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const pO=function L(R){function X(q){return new _m(q,R)}return X.tension=function(q){return L(+q)},X}(0);function DA(L,R){this._context=L,this._k=(1-R)/6}DA.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Qk(this,L,R)}this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const zz=function L(R){function X(q){return new DA(q,R)}return X.tension=function(q){return L(+q)},X}(0);function Hx(L,R,X){var q=L._x1,fe=L._y1,be=L._x2,Se=L._y2;if(L._l01_a>ba){var Ee=2*L._l01_2a+3*L._l01_a*L._l12_a+L._l12_2a,Oe=3*L._l01_a*(L._l01_a+L._l12_a);q=(q*Ee-L._x0*L._l12_2a+L._x2*L._l01_2a)/Oe,fe=(fe*Ee-L._y0*L._l12_2a+L._y2*L._l01_2a)/Oe}if(L._l23_a>ba){var Ue=2*L._l23_2a+3*L._l23_a*L._l12_a+L._l12_2a,rt=3*L._l23_a*(L._l23_a+L._l12_a);be=(be*Ue+L._x1*L._l23_2a-R*L._l12_2a)/rt,Se=(Se*Ue+L._y1*L._l23_2a-X*L._l12_2a)/rt}L._context.bezierCurveTo(q,fe,be,Se,L._x2,L._y2)}function Fz(L,R){this._context=L,this._alpha=R}Fz.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){if(L=+L,R=+R,this._point){var X=this._x2-L,q=this._y2-R;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(X*X+q*q,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(L,R):this._context.moveTo(L,R);break;case 1:this._point=2;break;case 2:this._point=3;default:Hx(this,L,R)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const IO=function L(R){function X(q){return R?new Fz(q,R):new Nx(q,0)}return X.alpha=function(q){return L(+q)},X}(.5);function PO(L,R){this._context=L,this._alpha=R}PO.prototype={areaStart:L4,areaEnd:L4,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(L,R){if(L=+L,R=+R,this._point){var X=this._x2-L,q=this._y2-R;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(X*X+q*q,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=L,this._y3=R;break;case 1:this._point=2,this._context.moveTo(this._x4=L,this._y4=R);break;case 2:this._point=3,this._x5=L,this._y5=R;break;default:Hx(this,L,R)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const _z=function L(R){function X(q){return R?new PO(q,R):new _m(q,0)}return X.alpha=function(q){return L(+q)},X}(.5);function BO(L,R){this._context=L,this._alpha=R}BO.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(L,R){if(L=+L,R=+R,this._point){var X=this._x2-L,q=this._y2-R;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(X*X+q*q,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Hx(this,L,R)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=L,this._y0=this._y1,this._y1=this._y2,this._y2=R}};const p5=function L(R){function X(q){return R?new BO(q,R):new DA(q,0)}return X.alpha=function(q){return L(+q)},X}(.5);function Su(L){this._context=L}function Vz(L){return new Su(L)}function Vm(L){return L<0?-1:1}function NO(L,R,X){var q=L._x1-L._x0,fe=R-L._x1,be=(L._y1-L._y0)/(q||fe<0&&-0),Se=(X-L._y1)/(fe||q<0&&-0),Ee=(be*fe+Se*q)/(q+fe);return(Vm(be)+Vm(Se))*Math.min(Math.abs(be),Math.abs(Se),.5*Math.abs(Ee))||0}function RO(L,R){var X=L._x1-L._x0;return X?(3*(L._y1-L._y0)/X-R)/2:R}function Wx(L,R,X){var q=L._x0,fe=L._y0,be=L._x1,Se=L._y1,Ee=(be-q)/3;L._context.bezierCurveTo(q+Ee,fe+Ee*R,be-Ee,Se-Ee*X,be,Se)}function Zk(L){this._context=L}function HO(L){this._context=new qk(L)}function qk(L){this._context=L}function m1(L){return new Zk(L)}function Lne(L){return new HO(L)}function Uz(L){this._context=L}function WO(L){var R,X,q=L.length-1,fe=new Array(q),be=new Array(q),Se=new Array(q);for(fe[0]=0,be[0]=2,Se[0]=L[0]+2*L[1],R=1;R=0;--R)fe[R]=(Se[R]-fe[R+1])/be[R];for(be[q-1]=(L[q]+fe[q-1])/2,R=0;R1)for(var X,q,fe,be=1,Se=L[R[0]],Ee=Se.length;be=0;)X[R]=R;return X}function yf(L,R){return L[R]}function f0(){var L=ma([]),R=Kk,X=of,q=yf;function fe(be){var Se,Ee,Oe=L.apply(this,arguments),Ue=be.length,rt=Oe.length,vt=new Array(rt);for(Se=0;Se0){for(var X,q,fe,be=0,Se=L[0].length;be0)for(var X,q,fe,be,Se,Ee,Oe=0,Ue=L[R[0]].length;Oe0?(q[0]=be,q[1]=be+=fe):fe<0?(q[1]=Se,q[0]=Se+=fe):(q[0]=0,q[1]=fe)}function Xz(L,R){if((X=L.length)>0){for(var X,q=0,fe=L[R[0]],be=fe.length;q0&&(q=(X=L[R[0]]).length)>0){for(var X,q,fe,be=0,Se=1;Sebe&&(be=R,q=X);return q}function FO(L){var R=L.map(_O);return Kk(L).sort(function(X,q){return R[X]-R[q]})}function _O(L){for(var R,X=0,q=-1,fe=L.length;++q=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(L,R){switch(L=+L,R=+R,this._point){case 0:this._point=1,this._line?this._context.lineTo(L,R):this._context.moveTo(L,R);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,R),this._context.lineTo(L,R);else{var X=this._x*(1-this._t)+L*this._t;this._context.lineTo(X,this._y),this._context.lineTo(X,R)}}this._x=L,this._y=R}};var UO="%Y-%m-%dT%H:%M:%S.%LZ",OA=Date.prototype.toISOString?function(L){return L.toISOString()}:ex(UO);const Eh=OA;var P5=+new Date("2000-01-01T00:00:00.000Z")?function(L){var R=new Date(L);return isNaN(R)?null:R}:oA(UO);const pA=P5;function _x(L,R,X){var q=new xi,fe=R;return R==null?(q.restart(L,R,X),q):(R=+R,X=X==null?Ht():+X,q.restart(function be(Se){Se+=fe,q.restart(be,fe+=R,X),L(Se)},R,X),q)}function GO(L){return function(){return L}}function qz(L){return L[0]}function Sne(L){return L[1]}function Vx(){this._=null}function IA(L){L.U=L.C=L.L=L.R=L.P=L.N=null}function B5(L,R){var X=R,q=R.R,fe=X.U;fe?fe.L===X?fe.L=q:fe.R=q:L._=q,q.U=fe,X.U=q,X.R=q.L,X.R&&(X.R.U=X),q.L=X}function PA(L,R){var X=R,q=R.L,fe=X.U;fe?fe.L===X?fe.L=q:fe.R=q:L._=q,q.U=fe,X.U=q,X.L=q.R,X.L&&(X.L.U=X),q.R=X}function YO(L){for(;L.L;)L=L.L;return L}Vx.prototype={constructor:Vx,insert:function(L,R){var X,q,fe;if(L){if(R.P=L,R.N=L.N,L.N&&(L.N.P=R),L.N=R,L.R){for(L=L.R;L.L;)L=L.L;L.L=R}else L.R=R;X=L}else this._?(L=YO(this._),R.P=null,R.N=L,L.P=L.L=R,X=L):(R.P=R.N=null,this._=R,X=null);for(R.L=R.R=null,R.U=X,R.C=!0,L=R;X&&X.C;)X===(q=X.U).L?(fe=q.R)&&fe.C?(X.C=fe.C=!1,q.C=!0,L=q):(L===X.R&&(B5(this,X),X=(L=X).U),X.C=!1,q.C=!0,PA(this,q)):(fe=q.L)&&fe.C?(X.C=fe.C=!1,q.C=!0,L=q):(L===X.L&&(PA(this,X),X=(L=X).U),X.C=!1,q.C=!0,B5(this,q)),X=L.U;this._.C=!1},remove:function(L){L.N&&(L.N.P=L.P),L.P&&(L.P.N=L.N),L.N=L.P=null;var R,X,q,fe=L.U,be=L.L,Se=L.R;if(X=be?Se?YO(Se):be:Se,fe?fe.L===L?fe.L=X:fe.R=X:this._=X,be&&Se?(q=X.C,X.C=L.C,X.L=be,be.U=X,X!==Se?(fe=X.U,X.U=L.U,L=X.R,fe.L=L,X.R=Se,Se.U=X):(X.U=fe,fe=X,L=X.R)):(q=L.C,L=X),L&&(L.U=fe),!q)if(L&&L.C)L.C=!1;else{do{if(L===this._)break;if(L===fe.L){if((R=fe.R).C&&(R.C=!1,fe.C=!0,B5(this,fe),R=fe.R),R.L&&R.L.C||R.R&&R.R.C){R.R&&R.R.C||(R.L.C=!1,R.C=!0,PA(this,R),R=fe.R),R.C=fe.C,fe.C=R.R.C=!1,B5(this,fe),L=this._;break}}else if((R=fe.L).C&&(R.C=!1,fe.C=!0,PA(this,fe),R=fe.L),R.L&&R.L.C||R.R&&R.R.C){R.L&&R.L.C||(R.R.C=!1,R.C=!0,B5(this,R),R=fe.L),R.C=fe.C,fe.C=R.L.C=!1,PA(this,fe),L=this._;break}R.C=!0,L=fe,fe=fe.U}while(!L.C);L&&(L.C=!1)}}};const XO=Vx;function BA(L,R,X,q){var fe=[null,null],be=Tu.push(fe)-1;return fe.left=L,fe.right=R,X&&Um(fe,L,R,X),q&&Um(fe,R,L,q),Sh[L.index].halfedges.push(be),Sh[R.index].halfedges.push(be),fe}function N5(L,R,X){var q=[R,X];return q.left=L,q}function Um(L,R,X,q){L[0]||L[1]?L.left===X?L[1]=q:L[0]=q:(L[0]=q,L.left=R,L.right=X)}function QO(L,R,X,q,fe){var be,Se=L[0],Ee=L[1],Oe=Se[0],Ue=Se[1],rt=0,vt=1,nt=Ee[0]-Oe,It=Ee[1]-Ue;if(be=R-Oe,nt||!(be>0)){if(be/=nt,nt<0){if(be0){if(be>vt)return;be>rt&&(rt=be)}if(be=q-Oe,nt||!(be<0)){if(be/=nt,nt<0){if(be>vt)return;be>rt&&(rt=be)}else if(nt>0){if(be0)){if(be/=It,It<0){if(be0){if(be>vt)return;be>rt&&(rt=be)}if(be=fe-Ue,It||!(be<0)){if(be/=It,It<0){if(be>vt)return;be>rt&&(rt=be)}else if(It>0){if(be0||vt<1)||(rt>0&&(L[0]=[Oe+rt*nt,Ue+rt*It]),vt<1&&(L[1]=[Oe+vt*nt,Ue+vt*It]),!0)}}}}}function ZO(L,R,X,q,fe){var be=L[1];if(be)return!0;var Se,Ee,Oe=L[0],Ue=L.left,rt=L.right,vt=Ue[0],nt=Ue[1],It=rt[0],Nt=rt[1],Jt=(vt+It)/2,Kt=(nt+Nt)/2;if(Nt===nt){if(Jt=q)return;if(vt>It){if(Oe){if(Oe[1]>=fe)return}else Oe=[Jt,X];be=[Jt,fe]}else{if(Oe){if(Oe[1]1)if(vt>It){if(Oe){if(Oe[1]>=fe)return}else Oe=[(X-Ee)/Se,X];be=[(fe-Ee)/Se,fe]}else{if(Oe){if(Oe[1]=q)return}else Oe=[R,Se*R+Ee];be=[q,Se*q+Ee]}else{if(Oe){if(Oe[0]=-1e-12)){var It=Oe*Oe+Ue*Ue,Nt=rt*rt+vt*vt,Jt=(vt*It-Ue*Nt)/nt,Kt=(Oe*Nt-rt*It)/nt,Vt=R5.pop()||new Mne;Vt.arc=L,Vt.site=fe,Vt.x=Jt+Se,Vt.y=(Vt.cy=Kt+Ee)+Math.sqrt(Jt*Jt+Kt*Kt),L.circle=Vt;for(var gn=null,un=z5._;un;)if(Vt.yec)Ee=Ee.L;else{if(!((fe=be-Kz(Ee,Se))>ec)){q>-ec?(R=Ee.P,X=Ee):fe>-ec?(R=Ee,X=Ee.N):R=X=Ee;break}if(!Ee.R){R=Ee;break}Ee=Ee.R}(function(fi){Sh[fi.index]={site:fi,halfedges:[]}})(L);var Oe=W5(L);if(Gm.insert(R,Oe),R||X){if(R===X)return fd(R),X=W5(R.site),Gm.insert(Oe,X),Oe.edge=X.edge=BA(R.site,Oe.site),M3(R),void M3(X);if(X){fd(R),fd(X);var Ue=R.site,rt=Ue[0],vt=Ue[1],nt=L[0]-rt,It=L[1]-vt,Nt=X.site,Jt=Nt[0]-rt,Kt=Nt[1]-vt,Vt=2*(nt*Kt-It*Jt),gn=nt*nt+It*It,un=Jt*Jt+Kt*Kt,Dn=[(Kt*gn-It*un)/Vt+rt,(nt*un-Jt*gn)/Vt+vt];Um(X.edge,Ue,Nt,Dn),Oe.edge=BA(Ue,L,null,Dn),X.edge=BA(L,Nt,null,Dn),M3(R),M3(X)}else Oe.edge=BA(R.site,Oe.site)}}function Mu(L,R){var X=L.site,q=X[0],fe=X[1],be=fe-R;if(!be)return q;var Se=L.P;if(!Se)return-1/0;var Ee=(X=Se.site)[0],Oe=X[1],Ue=Oe-R;if(!Ue)return Ee;var rt=Ee-q,vt=1/be-1/Ue,nt=rt/Ue;return vt?(-nt+Math.sqrt(nt*nt-2*vt*(rt*rt/(-2*Ue)-Oe+Ue/2+fe-be/2)))/vt+q:(q+Ee)/2}function Kz(L,R){var X=L.N;if(X)return Mu(X,R);var q=L.site;return q[1]===R?q[0]:1/0}var Gm,Sh,z5,Tu,ec=1e-6;function Dne(L,R,X){return(L[0]-X[0])*(R[1]-L[1])-(L[0]-R[0])*(X[1]-L[1])}function Br(L,R){return R[1]-L[1]||R[0]-L[0]}function $O(L,R){var X,q,fe,be=L.sort(Br).pop();for(Tu=[],Sh=new Array(L.length),Gm=new XO,z5=new XO;;)if(fe=KO,be&&(!fe||be[1]ec||Math.abs(Nt[0][1]-Nt[1][1])>ec)||delete Tu[Jt]})(Se,Ee,Oe,Ue),function(rt,vt,nt,It){var Nt,Jt,Kt,Vt,gn,un,Dn,fi,Mi,Ri,wo,vi,Ji=Sh.length,Tn=!0;for(Nt=0;Ntec||Math.abs(vi-Mi)>ec)&&(gn.splice(Vt,0,Tu.push(N5(Kt,Ri,Math.abs(wo-rt)ec?[rt,Math.abs(fi-rt)ec?[Math.abs(Mi-It)ec?[nt,Math.abs(fi-nt)ec?[Math.abs(Mi-vt)=Ee)return null;var Oe=L-fe.site[0],Ue=R-fe.site[1],rt=Oe*Oe+Ue*Ue;do fe=be.cells[q=Se],Se=null,fe.halfedges.forEach(function(vt){var nt=be.edges[vt],It=nt.left;if(It!==fe.site&&It||(It=nt.right)){var Nt=L-It[0],Jt=R-It[1],Kt=Nt*Nt+Jt*Jt;Ktq?(q+fe)/2:Math.min(0,q)||Math.max(0,fe),Se>be?(be+Se)/2:Math.min(0,be)||Math.max(0,Se))}function tp(){var L,R,X=eg,q=WA,fe=$z,be=zA,Se=Jz,Ee=[0,1/0],Oe=[[-1/0,-1/0],[1/0,1/0]],Ue=250,rt=AW,vt=et("start","zoom","end"),nt=500,It=0;function Nt(Tn){Tn.property("__zoom",Xm).on("wheel.zoom",fi).on("mousedown.zoom",Mi).on("dblclick.zoom",Ri).filter(Se).on("touchstart.zoom",wo).on("touchmove.zoom",vi).on("touchend.zoom touchcancel.zoom",Ji).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function Jt(Tn,Qn){return(Qn=Math.max(Ee[0],Math.min(Ee[1],Qn)))===Tn.k?Tn:new g0(Qn,Tn.x,Tn.y)}function Kt(Tn,Qn,zi){var Pi=Qn[0]-zi[0]*Tn.k,Gi=Qn[1]-zi[1]*Tn.k;return Pi===Tn.x&&Gi===Tn.y?Tn:new g0(Tn.k,Pi,Gi)}function Vt(Tn){return[(+Tn[0][0]+ +Tn[1][0])/2,(+Tn[0][1]+ +Tn[1][1])/2]}function gn(Tn,Qn,zi){Tn.on("start.zoom",function(){un(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){un(this,arguments).end()}).tween("zoom",function(){var Pi=this,Gi=arguments,or=un(Pi,Gi),Lr=q.apply(Pi,Gi),ml=zi==null?Vt(Lr):typeof zi=="function"?zi.apply(Pi,Gi):zi,Ei=Math.max(Lr[1][0]-Lr[0][0],Lr[1][1]-Lr[0][1]),Ro=Pi.__zoom,Wr=typeof Qn=="function"?Qn.apply(Pi,Gi):Qn,za=rt(Ro.invert(ml).concat(Ei/Ro.k),Wr.invert(ml).concat(Ei/Wr.k));return function(Dl){if(Dl===1)Dl=Wr;else{var El=za(Dl),Ka=Ei/El[2];Dl=new g0(Ka,ml[0]-El[0]*Ka,ml[1]-El[1]*Ka)}or.zoom(null,Dl)}})}function un(Tn,Qn,zi){return!zi&&Tn.__zooming||new Dn(Tn,Qn)}function Dn(Tn,Qn){this.that=Tn,this.args=Qn,this.active=0,this.extent=q.apply(Tn,Qn),this.taps=0}function fi(){if(X.apply(this,arguments)){var Tn=un(this,arguments),Qn=this.__zoom,zi=Math.max(Ee[0],Math.min(Ee[1],Qn.k*Math.pow(2,be.apply(this,arguments)))),Pi=Hf(this);if(Tn.wheel)Tn.mouse[0][0]===Pi[0]&&Tn.mouse[0][1]===Pi[1]||(Tn.mouse[1]=Qn.invert(Tn.mouse[0]=Pi)),clearTimeout(Tn.wheel);else{if(Qn.k===zi)return;Tn.mouse=[Pi,Qn.invert(Pi)],od(this),Tn.start()}HA(),Tn.wheel=setTimeout(Gi,150),Tn.zoom("mouse",fe(Kt(Jt(Qn,zi),Tn.mouse[0],Tn.mouse[1]),Tn.extent,Oe))}function Gi(){Tn.wheel=null,Tn.end()}}function Mi(){if(!R&&X.apply(this,arguments)){var Tn=un(this,arguments,!0),Qn=nl(Yn.view).on("mousemove.zoom",or,!0).on("mouseup.zoom",Lr,!0),zi=Hf(this),Pi=Yn.clientX,Gi=Yn.clientY;ya(Yn.view),RA(),Tn.mouse=[zi,this.__zoom.invert(zi)],od(this),Tn.start()}function or(){if(HA(),!Tn.moved){var ml=Yn.clientX-Pi,Ei=Yn.clientY-Gi;Tn.moved=ml*ml+Ei*Ei>It}Tn.zoom("mouse",fe(Kt(Tn.that.__zoom,Tn.mouse[0]=Hf(Tn.that),Tn.mouse[1]),Tn.extent,Oe))}function Lr(){Qn.on("mousemove.zoom mouseup.zoom",null),gl(Yn.view,Tn.moved),HA(),Tn.end()}}function Ri(){if(X.apply(this,arguments)){var Tn=this.__zoom,Qn=Hf(this),zi=Tn.invert(Qn),Pi=Tn.k*(Yn.shiftKey?.5:2),Gi=fe(Kt(Jt(Tn,Pi),Qn,zi),q.apply(this,arguments),Oe);HA(),Ue>0?nl(this).transition().duration(Ue).call(gn,Gi,Qn):nl(this).call(Nt.transform,Gi)}}function wo(){if(X.apply(this,arguments)){var Tn,Qn,zi,Pi,Gi=Yn.touches,or=Gi.length,Lr=un(this,arguments,Yn.changedTouches.length===or);for(RA(),Qn=0;Qn{e.exports={graphlib:n(574),layout:n(8123),debug:n(7570),util:{time:n(1138).time,notime:n(1138).notime},version:n(8177)}},2188:(e,t,n)=>{var i=n(8436),r=n(4079);e.exports={run:function(l){var a=l.graph().acyclicer==="greedy"?r(l,function(s){return function(c){return s.edge(c).weight}}(l)):function(s){var c=[],u={},d={};return i.forEach(s.nodes(),function f(h){i.has(d,h)||(d[h]=!0,u[h]=!0,i.forEach(s.outEdges(h),function(k){i.has(u,k.w)?c.push(k):f(k.w)}),delete u[h])}),c}(l);i.forEach(a,function(s){var c=l.edge(s);l.removeEdge(s),c.forwardName=s.name,c.reversed=!0,l.setEdge(s.w,s.v,c,i.uniqueId("rev"))})},undo:function(l){i.forEach(l.edges(),function(a){var s=l.edge(a);if(s.reversed){l.removeEdge(a);var c=s.forwardName;delete s.reversed,delete s.forwardName,l.setEdge(a.w,a.v,s,c)}})}}},1133:(e,t,n)=>{var i=n(8436),r=n(1138);function l(a,s,c,u,d,f){var h={width:0,height:0,rank:f,borderType:s},k=d[s][f-1],v=r.addDummyNode(a,"border",h,c);d[s][f]=v,a.setParent(v,u),k&&a.setEdge(k,v,{weight:1})}e.exports=function(a){i.forEach(a.children(),function s(c){var u=a.children(c),d=a.node(c);if(u.length&&i.forEach(u,s),i.has(d,"minRank")){d.borderLeft=[],d.borderRight=[];for(var f=d.minRank,h=d.maxRank+1;f{var i=n(8436);function r(c){i.forEach(c.nodes(),function(u){l(c.node(u))}),i.forEach(c.edges(),function(u){l(c.edge(u))})}function l(c){var u=c.width;c.width=c.height,c.height=u}function a(c){c.y=-c.y}function s(c){var u=c.x;c.x=c.y,c.y=u}e.exports={adjust:function(c){var u=c.graph().rankdir.toLowerCase();u!=="lr"&&u!=="rl"||r(c)},undo:function(c){var u=c.graph().rankdir.toLowerCase();u!=="bt"&&u!=="rl"||function(d){i.forEach(d.nodes(),function(f){a(d.node(f))}),i.forEach(d.edges(),function(f){var h=d.edge(f);i.forEach(h.points,a),i.has(h,"y")&&a(h)})}(c),u!=="lr"&&u!=="rl"||(function(d){i.forEach(d.nodes(),function(f){s(d.node(f))}),i.forEach(d.edges(),function(f){var h=d.edge(f);i.forEach(h.points,s),i.has(h,"x")&&s(h)})}(c),r(c))}}},7822:e=>{function t(){var r={};r._next=r._prev=r,this._sentinel=r}function n(r){r._prev._next=r._next,r._next._prev=r._prev,delete r._next,delete r._prev}function i(r,l){if(r!=="_next"&&r!=="_prev")return l}e.exports=t,t.prototype.dequeue=function(){var r=this._sentinel,l=r._prev;if(l!==r)return n(l),l},t.prototype.enqueue=function(r){var l=this._sentinel;r._prev&&r._next&&n(r),r._next=l._next,l._next._prev=r,l._next=r,r._prev=l},t.prototype.toString=function(){for(var r=[],l=this._sentinel,a=l._prev;a!==l;)r.push(JSON.stringify(a,i)),a=a._prev;return"["+r.join(", ")+"]"}},7570:(e,t,n)=>{var i=n(8436),r=n(1138),l=n(574).Graph;e.exports={debugOrdering:function(a){var s=r.buildLayerMatrix(a),c=new l({compound:!0,multigraph:!0}).setGraph({});return i.forEach(a.nodes(),function(u){c.setNode(u,{label:u}),c.setParent(u,"layer"+a.node(u).rank)}),i.forEach(a.edges(),function(u){c.setEdge(u.v,u.w,{},u.name)}),i.forEach(s,function(u,d){var f="layer"+d;c.setNode(f,{rank:"same"}),i.reduce(u,function(h,k){return c.setEdge(h,k,{style:"invis"}),k})}),c}}},574:(e,t,n)=>{var i;try{i=n(8282)}catch{}i||(i=window.graphlib),e.exports=i},4079:(e,t,n)=>{var i=n(8436),r=n(574).Graph,l=n(7822);e.exports=function(u,d){if(u.nodeCount()<=1)return[];var f=function(k,v){var g=new r,m=0,C=0;i.forEach(k.nodes(),function(x){g.setNode(x,{v:x,in:0,out:0})}),i.forEach(k.edges(),function(x){var E=g.edge(x.v,x.w)||0,S=v(x),M=E+S;g.setEdge(x.v,x.w,M),C=Math.max(C,g.node(x.v).out+=S),m=Math.max(m,g.node(x.w).in+=S)});var A=i.range(C+m+3).map(function(){return new l}),y=m+1;return i.forEach(g.nodes(),function(x){c(A,y,g.node(x))}),{graph:g,buckets:A,zeroIdx:y}}(u,d||a),h=function(k,v,g){for(var m,C=[],A=v[v.length-1],y=v[0];k.nodeCount();){for(;m=y.dequeue();)s(k,v,g,m);for(;m=A.dequeue();)s(k,v,g,m);if(k.nodeCount()){for(var x=v.length-2;x>0;--x)if(m=v[x].dequeue()){C=C.concat(s(k,v,g,m,!0));break}}}return C}(f.graph,f.buckets,f.zeroIdx);return i.flatten(i.map(h,function(k){return u.outEdges(k.v,k.w)}),!0)};var a=i.constant(1);function s(u,d,f,h,k){var v=k?[]:void 0;return i.forEach(u.inEdges(h.v),function(g){var m=u.edge(g),C=u.node(g.v);k&&v.push({v:g.v,w:g.w}),C.out-=m,c(d,f,C)}),i.forEach(u.outEdges(h.v),function(g){var m=u.edge(g),C=g.w,A=u.node(C);A.in-=m,c(d,f,A)}),u.removeNode(h.v),v}function c(u,d,f){f.out?f.in?u[f.out-f.in+d].enqueue(f):u[u.length-1].enqueue(f):u[0].enqueue(f)}},8123:(e,t,n)=>{var i=n(8436),r=n(2188),l=n(5995),a=n(8093),s=n(1138).normalizeRanks,c=n(4219),u=n(1138).removeEmptyRanks,d=n(2981),f=n(1133),h=n(3258),k=n(3408),v=n(7873),g=n(1138),m=n(574).Graph;e.exports=function(W,p){var H=p&&p.debugTiming?g.time:g.notime;H("layout",function(){var I=H(" buildLayoutGraph",function(){return function(_){var j=new m({multigraph:!0,compound:!0}),B=O(_.graph());return j.setGraph(i.merge({},A,D(B,C),i.pick(B,y))),i.forEach(_.nodes(),function(N){var U=O(_.node(N));j.setNode(N,i.defaults(D(U,x),E)),j.setParent(N,_.parent(N))}),i.forEach(_.edges(),function(N){var U=O(_.edge(N));j.setEdge(N,i.merge({},M,D(U,S),i.pick(U,T)))}),j}(W)});H(" runLayout",function(){(function(_,j){j(" makeSpaceForEdgeLabels",function(){(function(B){var N=B.graph();N.ranksep/=2,i.forEach(B.edges(),function(U){var Q=B.edge(U);Q.minlen*=2,Q.labelpos.toLowerCase()!=="c"&&(N.rankdir==="TB"||N.rankdir==="BT"?Q.width+=Q.labeloffset:Q.height+=Q.labeloffset)})})(_)}),j(" removeSelfEdges",function(){(function(B){i.forEach(B.edges(),function(N){if(N.v===N.w){var U=B.node(N.v);U.selfEdges||(U.selfEdges=[]),U.selfEdges.push({e:N,label:B.edge(N)}),B.removeEdge(N)}})})(_)}),j(" acyclic",function(){r.run(_)}),j(" nestingGraph.run",function(){d.run(_)}),j(" rank",function(){a(g.asNonCompoundGraph(_))}),j(" injectEdgeLabelProxies",function(){(function(B){i.forEach(B.edges(),function(N){var U=B.edge(N);if(U.width&&U.height){var Q=B.node(N.v),Y={rank:(B.node(N.w).rank-Q.rank)/2+Q.rank,e:N};g.addDummyNode(B,"edge-proxy",Y,"_ep")}})})(_)}),j(" removeEmptyRanks",function(){u(_)}),j(" nestingGraph.cleanup",function(){d.cleanup(_)}),j(" normalizeRanks",function(){s(_)}),j(" assignRankMinMax",function(){(function(B){var N=0;i.forEach(B.nodes(),function(U){var Q=B.node(U);Q.borderTop&&(Q.minRank=B.node(Q.borderTop).rank,Q.maxRank=B.node(Q.borderBottom).rank,N=i.max(N,Q.maxRank))}),B.graph().maxRank=N})(_)}),j(" removeEdgeLabelProxies",function(){(function(B){i.forEach(B.nodes(),function(N){var U=B.node(N);U.dummy==="edge-proxy"&&(B.edge(U.e).labelRank=U.rank,B.removeNode(N))})})(_)}),j(" normalize.run",function(){l.run(_)}),j(" parentDummyChains",function(){c(_)}),j(" addBorderSegments",function(){f(_)}),j(" order",function(){k(_)}),j(" insertSelfEdges",function(){(function(B){var N=g.buildLayerMatrix(B);i.forEach(N,function(U){var Q=0;i.forEach(U,function(Y,J){var Z=B.node(Y);Z.order=J+Q,i.forEach(Z.selfEdges,function(K){g.addDummyNode(B,"selfedge",{width:K.label.width,height:K.label.height,rank:Z.rank,order:J+ ++Q,e:K.e,label:K.label},"_se")}),delete Z.selfEdges})})})(_)}),j(" adjustCoordinateSystem",function(){h.adjust(_)}),j(" position",function(){v(_)}),j(" positionSelfEdges",function(){(function(B){i.forEach(B.nodes(),function(N){var U=B.node(N);if(U.dummy==="selfedge"){var Q=B.node(U.e.v),Y=Q.x+Q.width/2,J=Q.y,Z=U.x-Y,K=Q.height/2;B.setEdge(U.e,U.label),B.removeNode(N),U.label.points=[{x:Y+2*Z/3,y:J-K},{x:Y+5*Z/6,y:J-K},{x:Y+Z,y:J},{x:Y+5*Z/6,y:J+K},{x:Y+2*Z/3,y:J+K}],U.label.x=U.x,U.label.y=U.y}})})(_)}),j(" removeBorderNodes",function(){(function(B){i.forEach(B.nodes(),function(N){if(B.children(N).length){var U=B.node(N),Q=B.node(U.borderTop),Y=B.node(U.borderBottom),J=B.node(i.last(U.borderLeft)),Z=B.node(i.last(U.borderRight));U.width=Math.abs(Z.x-J.x),U.height=Math.abs(Y.y-Q.y),U.x=J.x+U.width/2,U.y=Q.y+U.height/2}}),i.forEach(B.nodes(),function(N){B.node(N).dummy==="border"&&B.removeNode(N)})})(_)}),j(" normalize.undo",function(){l.undo(_)}),j(" fixupEdgeLabelCoords",function(){(function(B){i.forEach(B.edges(),function(N){var U=B.edge(N);if(i.has(U,"x"))switch(U.labelpos!=="l"&&U.labelpos!=="r"||(U.width-=U.labeloffset),U.labelpos){case"l":U.x-=U.width/2+U.labeloffset;break;case"r":U.x+=U.width/2+U.labeloffset}})})(_)}),j(" undoCoordinateSystem",function(){h.undo(_)}),j(" translateGraph",function(){(function(B){var N=Number.POSITIVE_INFINITY,U=0,Q=Number.POSITIVE_INFINITY,Y=0,J=B.graph(),Z=J.marginx||0,K=J.marginy||0;function te(ae){var ie=ae.x,le=ae.y,se=ae.width,ke=ae.height;N=Math.min(N,ie-se/2),U=Math.max(U,ie+se/2),Q=Math.min(Q,le-ke/2),Y=Math.max(Y,le+ke/2)}i.forEach(B.nodes(),function(ae){te(B.node(ae))}),i.forEach(B.edges(),function(ae){var ie=B.edge(ae);i.has(ie,"x")&&te(ie)}),N-=Z,Q-=K,i.forEach(B.nodes(),function(ae){var ie=B.node(ae);ie.x-=N,ie.y-=Q}),i.forEach(B.edges(),function(ae){var ie=B.edge(ae);i.forEach(ie.points,function(le){le.x-=N,le.y-=Q}),i.has(ie,"x")&&(ie.x-=N),i.has(ie,"y")&&(ie.y-=Q)}),J.width=U-N+Z,J.height=Y-Q+K})(_)}),j(" assignNodeIntersects",function(){(function(B){i.forEach(B.edges(),function(N){var U,Q,Y=B.edge(N),J=B.node(N.v),Z=B.node(N.w);Y.points?(U=Y.points[0],Q=Y.points[Y.points.length-1]):(Y.points=[],U=Z,Q=J),Y.points.unshift(g.intersectRect(J,U)),Y.points.push(g.intersectRect(Z,Q))})})(_)}),j(" reversePoints",function(){(function(B){i.forEach(B.edges(),function(N){var U=B.edge(N);U.reversed&&U.points.reverse()})})(_)}),j(" acyclic.undo",function(){r.undo(_)})})(I,H)}),H(" updateInputGraph",function(){(function(_,j){i.forEach(_.nodes(),function(B){var N=_.node(B),U=j.node(B);N&&(N.x=U.x,N.y=U.y,j.children(B).length&&(N.width=U.width,N.height=U.height))}),i.forEach(_.edges(),function(B){var N=_.edge(B),U=j.edge(B);N.points=U.points,i.has(U,"x")&&(N.x=U.x,N.y=U.y)}),_.graph().width=j.graph().width,_.graph().height=j.graph().height})(W,I)})})};var C=["nodesep","edgesep","ranksep","marginx","marginy"],A={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},y=["acyclicer","ranker","rankdir","align"],x=["width","height"],E={width:0,height:0},S=["minlen","weight","width","height","labeloffset"],M={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},T=["labelpos"];function D(W,p){return i.mapValues(i.pick(W,p),Number)}function O(W){var p={};return i.forEach(W,function(H,I){p[I.toLowerCase()]=H}),p}},8436:(e,t,n)=>{var i;try{i={cloneDeep:n(361),constant:n(5703),defaults:n(1747),each:n(6073),filter:n(3105),find:n(3311),flatten:n(5564),forEach:n(4486),forIn:n(2620),has:n(8721),isUndefined:n(2353),last:n(928),map:n(5161),mapValues:n(6604),max:n(6162),merge:n(3857),min:n(3632),minBy:n(2762),now:n(7771),pick:n(9722),range:n(6026),reduce:n(4061),sortBy:n(9734),uniqueId:n(3955),values:n(2628),zipObject:n(7287)}}catch{}i||(i=window._),e.exports=i},2981:(e,t,n)=>{var i=n(8436),r=n(1138);function l(a,s,c,u,d,f,h){var k=a.children(h);if(k.length){var v=r.addBorderNode(a,"_bt"),g=r.addBorderNode(a,"_bb"),m=a.node(h);a.setParent(v,h),m.borderTop=v,a.setParent(g,h),m.borderBottom=g,i.forEach(k,function(C){l(a,s,c,u,d,f,C);var A=a.node(C),y=A.borderTop?A.borderTop:C,x=A.borderBottom?A.borderBottom:C,E=A.borderTop?u:2*u,S=y!==x?1:d-f[h]+1;a.setEdge(v,y,{weight:E,minlen:S,nestingEdge:!0}),a.setEdge(x,g,{weight:E,minlen:S,nestingEdge:!0})}),a.parent(h)||a.setEdge(s,v,{weight:0,minlen:d+f[h]})}else h!==s&&a.setEdge(s,h,{weight:0,minlen:c})}e.exports={run:function(a){var s=r.addDummyNode(a,"root",{},"_root"),c=function(h){var k={};function v(g,m){var C=h.children(g);C&&C.length&&i.forEach(C,function(A){v(A,m+1)}),k[g]=m}return i.forEach(h.children(),function(g){v(g,1)}),k}(a),u=i.max(i.values(c))-1,d=2*u+1;a.graph().nestingRoot=s,i.forEach(a.edges(),function(h){a.edge(h).minlen*=d});var f=function(h){return i.reduce(h.edges(),function(k,v){return k+h.edge(v).weight},0)}(a)+1;i.forEach(a.children(),function(h){l(a,s,d,f,u,c,h)}),a.graph().nodeRankFactor=d},cleanup:function(a){var s=a.graph();a.removeNode(s.nestingRoot),delete s.nestingRoot,i.forEach(a.edges(),function(c){a.edge(c).nestingEdge&&a.removeEdge(c)})}}},5995:(e,t,n)=>{var i=n(8436),r=n(1138);e.exports={run:function(l){l.graph().dummyChains=[],i.forEach(l.edges(),function(a){(function(s,c){var u,d,f,h=c.v,k=s.node(h).rank,v=c.w,g=s.node(v).rank,m=c.name,C=s.edge(c),A=C.labelRank;if(g!==k+1){for(s.removeEdge(c),f=0,++k;k{var i=n(8436);e.exports=function(r,l,a){var s,c={};i.forEach(a,function(u){for(var d,f,h=r.parent(u);h;){if((d=r.parent(h))?(f=c[d],c[d]=h):(f=s,s=h),f&&f!==h)return void l.setEdge(f,h);h=d}})}},5439:(e,t,n)=>{var i=n(8436);e.exports=function(r,l){return i.map(l,function(a){var s=r.inEdges(a);if(s.length){var c=i.reduce(s,function(u,d){var f=r.edge(d),h=r.node(d.v);return{sum:u.sum+f.weight*h.order,weight:u.weight+f.weight}},{sum:0,weight:0});return{v:a,barycenter:c.sum/c.weight,weight:c.weight}}return{v:a}})}},3128:(e,t,n)=>{var i=n(8436),r=n(574).Graph;e.exports=function(l,a,s){var c=function(d){for(var f;d.hasNode(f=i.uniqueId("_root")););return f}(l),u=new r({compound:!0}).setGraph({root:c}).setDefaultNodeLabel(function(d){return l.node(d)});return i.forEach(l.nodes(),function(d){var f=l.node(d),h=l.parent(d);(f.rank===a||f.minRank<=a&&a<=f.maxRank)&&(u.setNode(d),u.setParent(d,h||c),i.forEach(l[s](d),function(k){var v=k.v===d?k.w:k.v,g=u.edge(v,d),m=i.isUndefined(g)?0:g.weight;u.setEdge(v,d,{weight:l.edge(k).weight+m})}),i.has(f,"minRank")&&u.setNode(d,{borderLeft:f.borderLeft[a],borderRight:f.borderRight[a]}))}),u}},6630:(e,t,n)=>{var i=n(8436);function r(l,a,s){for(var c=i.zipObject(s,i.map(s,function(v,g){return g})),u=i.flatten(i.map(a,function(v){return i.sortBy(i.map(l.outEdges(v),function(g){return{pos:c[g.w],weight:l.edge(g).weight}}),"pos")}),!0),d=1;d0;)g%2&&(m+=h[g+1]),h[g=g-1>>1]+=v.weight;k+=v.weight*m})),k}e.exports=function(l,a){for(var s=0,c=1;c{var i=n(8436),r=n(2588),l=n(6630),a=n(1026),s=n(3128),c=n(5093),u=n(574).Graph,d=n(1138);function f(v,g,m){return i.map(g,function(C){return s(v,C,m)})}function h(v,g){var m=new u;i.forEach(v,function(C){var A=C.graph().root,y=a(C,A,m,g);i.forEach(y.vs,function(x,E){C.node(x).order=E}),c(C,m,y.vs)})}function k(v,g){i.forEach(g,function(m){i.forEach(m,function(C,A){v.node(C).order=A})})}e.exports=function(v){var g=d.maxRank(v),m=f(v,i.range(1,g+1),"inEdges"),C=f(v,i.range(g-1,-1,-1),"outEdges"),A=r(v);k(v,A);for(var y,x=Number.POSITIVE_INFINITY,E=0,S=0;S<4;++E,++S){h(E%2?m:C,E%4>=2),A=d.buildLayerMatrix(v);var M=l(v,A);M{var i=n(8436);e.exports=function(r){var l={},a=i.filter(r.nodes(),function(d){return!r.children(d).length}),s=i.max(i.map(a,function(d){return r.node(d).rank})),c=i.map(i.range(s+1),function(){return[]}),u=i.sortBy(a,function(d){return r.node(d).rank});return i.forEach(u,function d(f){if(!i.has(l,f)){l[f]=!0;var h=r.node(f);c[h.rank].push(f),i.forEach(r.successors(f),d)}}),c}},9567:(e,t,n)=>{var i=n(8436);e.exports=function(r,l){var a={};return i.forEach(r,function(s,c){var u=a[s.v]={indegree:0,in:[],out:[],vs:[s.v],i:c};i.isUndefined(s.barycenter)||(u.barycenter=s.barycenter,u.weight=s.weight)}),i.forEach(l.edges(),function(s){var c=a[s.v],u=a[s.w];i.isUndefined(c)||i.isUndefined(u)||(u.indegree++,c.out.push(a[s.w]))}),function(s){var c=[];function u(h){return function(k){var v,g,m,C;k.merged||(i.isUndefined(k.barycenter)||i.isUndefined(h.barycenter)||k.barycenter>=h.barycenter)&&(g=k,m=0,C=0,(v=h).weight&&(m+=v.barycenter*v.weight,C+=v.weight),g.weight&&(m+=g.barycenter*g.weight,C+=g.weight),v.vs=g.vs.concat(v.vs),v.barycenter=m/C,v.weight=C,v.i=Math.min(g.i,v.i),g.merged=!0)}}function d(h){return function(k){k.in.push(h),--k.indegree==0&&s.push(k)}}for(;s.length;){var f=s.pop();c.push(f),i.forEach(f.in.reverse(),u(f)),i.forEach(f.out,d(f))}return i.map(i.filter(c,function(h){return!h.merged}),function(h){return i.pick(h,["vs","i","barycenter","weight"])})}(i.filter(a,function(s){return!s.indegree}))}},1026:(e,t,n)=>{var i=n(8436),r=n(5439),l=n(9567),a=n(7304);e.exports=function s(c,u,d,f){var h=c.children(u),k=c.node(u),v=k?k.borderLeft:void 0,g=k?k.borderRight:void 0,m={};v&&(h=i.filter(h,function(S){return S!==v&&S!==g}));var C=r(c,h);i.forEach(C,function(S){if(c.children(S.v).length){var M=s(c,S.v,d,f);m[S.v]=M,i.has(M,"barycenter")&&(T=S,D=M,i.isUndefined(T.barycenter)?(T.barycenter=D.barycenter,T.weight=D.weight):(T.barycenter=(T.barycenter*T.weight+D.barycenter*D.weight)/(T.weight+D.weight),T.weight+=D.weight))}var T,D});var A=l(C,d);(function(S,M){i.forEach(S,function(T){T.vs=i.flatten(T.vs.map(function(D){return M[D]?M[D].vs:D}),!0)})})(A,m);var y=a(A,f);if(v&&(y.vs=i.flatten([v,y.vs,g],!0),c.predecessors(v).length)){var x=c.node(c.predecessors(v)[0]),E=c.node(c.predecessors(g)[0]);i.has(y,"barycenter")||(y.barycenter=0,y.weight=0),y.barycenter=(y.barycenter*y.weight+x.order+E.order)/(y.weight+2),y.weight+=2}return y}},7304:(e,t,n)=>{var i=n(8436),r=n(1138);function l(a,s,c){for(var u;s.length&&(u=i.last(s)).i<=c;)s.pop(),a.push(u.vs),c++;return c}e.exports=function(a,s){var c,u=r.partition(a,function(C){return i.has(C,"barycenter")}),d=u.lhs,f=i.sortBy(u.rhs,function(C){return-C.i}),h=[],k=0,v=0,g=0;d.sort((c=!!s,function(C,A){return C.barycenterA.barycenter?1:c?A.i-C.i:C.i-A.i})),g=l(h,f,g),i.forEach(d,function(C){g+=C.vs.length,h.push(C.vs),k+=C.barycenter*C.weight,v+=C.weight,g=l(h,f,g)});var m={vs:i.flatten(h,!0)};return v&&(m.barycenter=k/v,m.weight=v),m}},4219:(e,t,n)=>{var i=n(8436);e.exports=function(r){var l=function(a){var s={},c=0;return i.forEach(a.children(),function u(d){var f=c;i.forEach(a.children(d),u),s[d]={low:f,lim:c++}}),s}(r);i.forEach(r.graph().dummyChains,function(a){for(var s=r.node(a),c=s.edgeObj,u=function(g,m,C,A){var y,x,E=[],S=[],M=Math.min(m[C].low,m[A].low),T=Math.max(m[C].lim,m[A].lim);y=C;do y=g.parent(y),E.push(y);while(y&&(m[y].low>M||T>m[y].lim));for(x=y,y=A;(y=g.parent(y))!==x;)S.push(y);return{path:E.concat(S.reverse()),lca:x}}(r,l,c.v,c.w),d=u.path,f=u.lca,h=0,k=d[h],v=!0;a!==c.w;){if(s=r.node(a),v){for(;(k=d[h])!==f&&r.node(k).maxRank{var i=n(8436),r=n(574).Graph,l=n(1138);function a(g,m){var C={};return i.reduce(m,function(A,y){var x=0,E=0,S=A.length,M=i.last(y);return i.forEach(y,function(T,D){var O=function(p,H){if(p.node(H).dummy)return i.find(p.predecessors(H),function(I){return p.node(I).dummy})}(g,T),W=O?g.node(O).order:S;(O||T===M)&&(i.forEach(y.slice(E,D+1),function(p){i.forEach(g.predecessors(p),function(H){var I=g.node(H),_=I.order;!(_M)&&c(C,O,T)})})}return i.reduce(m,function(y,x){var E,S=-1,M=0;return i.forEach(x,function(T,D){if(g.node(T).dummy==="border"){var O=g.predecessors(T);O.length&&(E=g.node(O[0]).order,A(x,M,D,S,E),M=D,S=E)}A(x,M,x.length,E,y.length)}),x}),C}function c(g,m,C){if(m>C){var A=m;m=C,C=A}var y=g[m];y||(g[m]=y={}),y[C]=!0}function u(g,m,C){if(m>C){var A=m;m=C,C=A}return i.has(g[m],C)}function d(g,m,C,A){var y={},x={},E={};return i.forEach(m,function(S){i.forEach(S,function(M,T){y[M]=M,x[M]=M,E[M]=T})}),i.forEach(m,function(S){var M=-1;i.forEach(S,function(T){var D=A(T);if(D.length){D=i.sortBy(D,function(I){return E[I]});for(var O=(D.length-1)/2,W=Math.floor(O),p=Math.ceil(O);W<=p;++W){var H=D[W];x[T]===T&&M{var i=n(8436),r=n(1138),l=n(3573).positionX;e.exports=function(a){(function(s){var c=r.buildLayerMatrix(s),u=s.graph().ranksep,d=0;i.forEach(c,function(f){var h=i.max(i.map(f,function(k){return s.node(k).height}));i.forEach(f,function(k){s.node(k).y=d+h/2}),d+=h+u})})(a=r.asNonCompoundGraph(a)),i.forEach(l(a),function(s,c){a.node(c).x=s})}},300:(e,t,n)=>{var i=n(8436),r=n(574).Graph,l=n(6681).slack;function a(u,d){return i.forEach(u.nodes(),function f(h){i.forEach(d.nodeEdges(h),function(k){var v=k.v,g=h===v?k.w:v;u.hasNode(g)||l(d,k)||(u.setNode(g,{}),u.setEdge(h,g,{}),f(g))})}),u.nodeCount()}function s(u,d){return i.minBy(d.edges(),function(f){if(u.hasNode(f.v)!==u.hasNode(f.w))return l(d,f)})}function c(u,d,f){i.forEach(u.nodes(),function(h){d.node(h).rank+=f})}e.exports=function(u){var d,f,h=new r({directed:!1}),k=u.nodes()[0],v=u.nodeCount();for(h.setNode(k,{});a(h,u){var i=n(6681).longestPath,r=n(300),l=n(2472);e.exports=function(s){switch(s.graph().ranker){case"network-simplex":default:(function(c){l(c)})(s);break;case"tight-tree":(function(c){i(c),r(c)})(s);break;case"longest-path":a(s)}};var a=i},2472:(e,t,n)=>{var i=n(8436),r=n(300),l=n(6681).slack,a=n(6681).longestPath,s=n(574).alg.preorder,c=n(574).alg.postorder,u=n(1138).simplify;function d(y){y=u(y),a(y);var x,E=r(y);for(k(E),f(E,y);x=g(E);)C(E,y,x,m(E,y,x))}function f(y,x){var E=c(y,y.nodes());E=E.slice(0,E.length-1),i.forEach(E,function(S){(function(M,T,D){var O=M.node(D).parent;M.edge(D,O).cutvalue=h(M,T,D)})(y,x,S)})}function h(y,x,E){var S=y.node(E).parent,M=!0,T=x.edge(E,S),D=0;return T||(M=!1,T=x.edge(S,E)),D=T.weight,i.forEach(x.nodeEdges(E),function(O){var W,p,H=O.v===E,I=H?O.w:O.v;if(I!==S){var _=H===M,j=x.edge(O).weight;if(D+=_?j:-j,W=E,p=I,y.hasEdge(W,p)){var B=y.edge(E,I).cutvalue;D+=_?-B:B}}}),D}function k(y,x){arguments.length<2&&(x=y.nodes()[0]),v(y,{},1,x)}function v(y,x,E,S,M){var T=E,D=y.node(S);return x[S]=!0,i.forEach(y.neighbors(S),function(O){i.has(x,O)||(E=v(y,x,E,O,S))}),D.low=T,D.lim=E++,M?D.parent=M:delete D.parent,E}function g(y){return i.find(y.edges(),function(x){return y.edge(x).cutvalue<0})}function m(y,x,E){var S=E.v,M=E.w;x.hasEdge(S,M)||(S=E.w,M=E.v);var T=y.node(S),D=y.node(M),O=T,W=!1;T.lim>D.lim&&(O=D,W=!0);var p=i.filter(x.edges(),function(H){return W===A(0,y.node(H.v),O)&&W!==A(0,y.node(H.w),O)});return i.minBy(p,function(H){return l(x,H)})}function C(y,x,E,S){var M=E.v,T=E.w;y.removeEdge(M,T),y.setEdge(S.v,S.w,{}),k(y),f(y,x),function(D,O){var W=i.find(D.nodes(),function(H){return!O.node(H).parent}),p=s(D,W);p=p.slice(1),i.forEach(p,function(H){var I=D.node(H).parent,_=O.edge(H,I),j=!1;_||(_=O.edge(I,H),j=!0),O.node(H).rank=O.node(I).rank+(j?_.minlen:-_.minlen)})}(y,x)}function A(y,x,E){return E.low<=x.lim&&x.lim<=E.lim}e.exports=d,d.initLowLimValues=k,d.initCutValues=f,d.calcCutValue=h,d.leaveEdge=g,d.enterEdge=m,d.exchangeEdges=C},6681:(e,t,n)=>{var i=n(8436);e.exports={longestPath:function(r){var l={};i.forEach(r.sources(),function a(s){var c=r.node(s);if(i.has(l,s))return c.rank;l[s]=!0;var u=i.min(i.map(r.outEdges(s),function(d){return a(d.w)-r.edge(d).minlen}));return u!==Number.POSITIVE_INFINITY&&u!=null||(u=0),c.rank=u})},slack:function(r,l){return r.node(l.w).rank-r.node(l.v).rank-r.edge(l).minlen}}},1138:(e,t,n)=>{var i=n(8436),r=n(574).Graph;function l(s,c,u,d){var f;do f=i.uniqueId(d);while(s.hasNode(f));return u.dummy=c,s.setNode(f,u),f}function a(s){return i.max(i.map(s.nodes(),function(c){var u=s.node(c).rank;if(!i.isUndefined(u))return u}))}e.exports={addDummyNode:l,simplify:function(s){var c=new r().setGraph(s.graph());return i.forEach(s.nodes(),function(u){c.setNode(u,s.node(u))}),i.forEach(s.edges(),function(u){var d=c.edge(u.v,u.w)||{weight:0,minlen:1},f=s.edge(u);c.setEdge(u.v,u.w,{weight:d.weight+f.weight,minlen:Math.max(d.minlen,f.minlen)})}),c},asNonCompoundGraph:function(s){var c=new r({multigraph:s.isMultigraph()}).setGraph(s.graph());return i.forEach(s.nodes(),function(u){s.children(u).length||c.setNode(u,s.node(u))}),i.forEach(s.edges(),function(u){c.setEdge(u,s.edge(u))}),c},successorWeights:function(s){var c=i.map(s.nodes(),function(u){var d={};return i.forEach(s.outEdges(u),function(f){d[f.w]=(d[f.w]||0)+s.edge(f).weight}),d});return i.zipObject(s.nodes(),c)},predecessorWeights:function(s){var c=i.map(s.nodes(),function(u){var d={};return i.forEach(s.inEdges(u),function(f){d[f.v]=(d[f.v]||0)+s.edge(f).weight}),d});return i.zipObject(s.nodes(),c)},intersectRect:function(s,c){var u,d,f=s.x,h=s.y,k=c.x-f,v=c.y-h,g=s.width/2,m=s.height/2;if(!k&&!v)throw new Error("Not possible to find intersection inside of the rectangle");return Math.abs(v)*g>Math.abs(k)*m?(v<0&&(m=-m),u=m*k/v,d=m):(k<0&&(g=-g),u=g,d=g*v/k),{x:f+u,y:h+d}},buildLayerMatrix:function(s){var c=i.map(i.range(a(s)+1),function(){return[]});return i.forEach(s.nodes(),function(u){var d=s.node(u),f=d.rank;i.isUndefined(f)||(c[f][d.order]=u)}),c},normalizeRanks:function(s){var c=i.min(i.map(s.nodes(),function(u){return s.node(u).rank}));i.forEach(s.nodes(),function(u){var d=s.node(u);i.has(d,"rank")&&(d.rank-=c)})},removeEmptyRanks:function(s){var c=i.min(i.map(s.nodes(),function(h){return s.node(h).rank})),u=[];i.forEach(s.nodes(),function(h){var k=s.node(h).rank-c;u[k]||(u[k]=[]),u[k].push(h)});var d=0,f=s.graph().nodeRankFactor;i.forEach(u,function(h,k){i.isUndefined(h)&&k%f!=0?--d:d&&i.forEach(h,function(v){s.node(v).rank+=d})})},addBorderNode:function(s,c,u,d){var f={width:0,height:0};return arguments.length>=4&&(f.rank=u,f.order=d),l(s,"border",f,c)},maxRank:a,partition:function(s,c){var u={lhs:[],rhs:[]};return i.forEach(s,function(d){c(d)?u.lhs.push(d):u.rhs.push(d)}),u},time:function(s,c){var u=i.now();try{return c()}finally{console.log(s+" time: "+(i.now()-u)+"ms")}},notime:function(s,c){return c()}}},8177:e=>{e.exports="0.8.5"},7856:function(e){e.exports=function(){var t=Object.hasOwnProperty,n=Object.setPrototypeOf,i=Object.isFrozen,r=Object.getPrototypeOf,l=Object.getOwnPropertyDescriptor,a=Object.freeze,s=Object.seal,c=Object.create,u=typeof Reflect<"u"&&Reflect,d=u.apply,f=u.construct;d||(d=function(re,ve,Ce){return re.apply(ve,Ce)}),a||(a=function(re){return re}),s||(s=function(re){return re}),f||(f=function(re,ve){return new(Function.prototype.bind.apply(re,[null].concat(function(Ce){if(Array.isArray(Ce)){for(var Le=0,ye=Array(Ce.length);Le1?Ce-1:0),ye=1;ye/gm),K=s(/^data-[\-\w.\u00B7-\uFFFF]/),te=s(/^aria-[\-\w]+$/),ae=s(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),ie=s(/^(?:\w+script|data):/i),le=s(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),se=s(/^html$/i),ke=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(re){return typeof re}:function(re){return re&&typeof Symbol=="function"&&re.constructor===Symbol&&re!==Symbol.prototype?"symbol":typeof re};function oe(re){if(Array.isArray(re)){for(var ve=0,Ce=Array(re.length);ve"u"?null:window},ce=function(re,ve){if((re===void 0?"undefined":ke(re))!=="object"||typeof re.createPolicy!="function")return null;var Ce=null,Le="data-tt-policy-suffix";ve.currentScript&&ve.currentScript.hasAttribute(Le)&&(Ce=ve.currentScript.getAttribute(Le));var ye="dompurify"+(Ce?"#"+Ce:"");try{return re.createPolicy(ye,{createHTML:function(De){return De}})}catch{return console.warn("TrustedTypes policy "+ye+" could not be created."),null}};return function re(){var ve=arguments.length>0&&arguments[0]!==void 0?arguments[0]:ge(),Ce=function($n){return re($n)};if(Ce.version="2.3.6",Ce.removed=[],!ve||!ve.document||ve.document.nodeType!==9)return Ce.isSupported=!1,Ce;var Le=ve.document,ye=ve.document,De=ve.DocumentFragment,Re=ve.HTMLTemplateElement,Pe=ve.Node,Be=ve.Element,Fe=ve.NodeFilter,Ve=ve.NamedNodeMap,Ze=Ve===void 0?ve.NamedNodeMap||ve.MozNamedAttrMap:Ve,We=ve.HTMLFormElement,Xe=ve.DOMParser,dt=ve.trustedTypes,He=Be.prototype,et=O(He,"cloneNode"),lt=O(He,"nextSibling"),Ot=O(He,"childNodes"),Et=O(He,"parentNode");if(typeof Re=="function"){var yt=ye.createElement("template");yt.content&&yt.content.ownerDocument&&(ye=yt.content.ownerDocument)}var ot=ce(dt,Le),Lt=ot?ot.createHTML(""):"",at=ye,Tt=at.implementation,Ie=at.createNodeIterator,Ge=at.createDocumentFragment,Ye=at.getElementsByTagName,ft=Le.importNode,ut={};try{ut=D(ye).documentMode?ye.documentMode:{}}catch{}var Dt={};Ce.isSupported=typeof Et=="function"&&Tt&&Tt.createHTMLDocument!==void 0&&ut!==9;var Ft=J,At=Z,bt=K,Qe=te,wt=ie,Ut=le,Zt=ae,$t=null,Yt=T({},[].concat(oe(W),oe(p),oe(H),oe(_),oe(B))),Xt=null,mn=T({},[].concat(oe(N),oe(U),oe(Q),oe(Y))),En=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ti=null,wi=null,to=!0,Ni=!0,sn=!1,Xn=!1,_t=!1,pn=!1,Wt=!1,ln=!1,Nn=!1,ni=!1,_n=!0,xn=!0,ri=!1,Ci={},Hi=null,yn=T({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),jt=null,zt=T({},["audio","video","img","source","image","track"]),en=null,Fn=T({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),hi="http://www.w3.org/1998/Math/MathML",oi="http://www.w3.org/2000/svg",ci="http://www.w3.org/1999/xhtml",Yn=ci,si=!1,Wi=void 0,wn=["application/xhtml+xml","text/html"],Bo="text/html",Bn=void 0,yo=null,jr=ye.createElement("form"),Eo=function($n){return $n instanceof RegExp||$n instanceof Function},No=function($n){yo&&yo===$n||($n&&($n===void 0?"undefined":ke($n))==="object"||($n={}),$n=D($n),$t="ALLOWED_TAGS"in $n?T({},$n.ALLOWED_TAGS):Yt,Xt="ALLOWED_ATTR"in $n?T({},$n.ALLOWED_ATTR):mn,en="ADD_URI_SAFE_ATTR"in $n?T(D(Fn),$n.ADD_URI_SAFE_ATTR):Fn,jt="ADD_DATA_URI_TAGS"in $n?T(D(zt),$n.ADD_DATA_URI_TAGS):zt,Hi="FORBID_CONTENTS"in $n?T({},$n.FORBID_CONTENTS):yn,ti="FORBID_TAGS"in $n?T({},$n.FORBID_TAGS):{},wi="FORBID_ATTR"in $n?T({},$n.FORBID_ATTR):{},Ci="USE_PROFILES"in $n&&$n.USE_PROFILES,to=$n.ALLOW_ARIA_ATTR!==!1,Ni=$n.ALLOW_DATA_ATTR!==!1,sn=$n.ALLOW_UNKNOWN_PROTOCOLS||!1,Xn=$n.SAFE_FOR_TEMPLATES||!1,_t=$n.WHOLE_DOCUMENT||!1,ln=$n.RETURN_DOM||!1,Nn=$n.RETURN_DOM_FRAGMENT||!1,ni=$n.RETURN_TRUSTED_TYPE||!1,Wt=$n.FORCE_BODY||!1,_n=$n.SANITIZE_DOM!==!1,xn=$n.KEEP_CONTENT!==!1,ri=$n.IN_PLACE||!1,Zt=$n.ALLOWED_URI_REGEXP||Zt,Yn=$n.NAMESPACE||ci,$n.CUSTOM_ELEMENT_HANDLING&&Eo($n.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(En.tagNameCheck=$n.CUSTOM_ELEMENT_HANDLING.tagNameCheck),$n.CUSTOM_ELEMENT_HANDLING&&Eo($n.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(En.attributeNameCheck=$n.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),$n.CUSTOM_ELEMENT_HANDLING&&typeof $n.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(En.allowCustomizedBuiltInElements=$n.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Wi=Wi=wn.indexOf($n.PARSER_MEDIA_TYPE)===-1?Bo:$n.PARSER_MEDIA_TYPE,Bn=Wi==="application/xhtml+xml"?function(po){return po}:m,Xn&&(Ni=!1),Nn&&(ln=!0),Ci&&($t=T({},[].concat(oe(B))),Xt=[],Ci.html===!0&&(T($t,W),T(Xt,N)),Ci.svg===!0&&(T($t,p),T(Xt,U),T(Xt,Y)),Ci.svgFilters===!0&&(T($t,H),T(Xt,U),T(Xt,Y)),Ci.mathMl===!0&&(T($t,_),T(Xt,Q),T(Xt,Y))),$n.ADD_TAGS&&($t===Yt&&($t=D($t)),T($t,$n.ADD_TAGS)),$n.ADD_ATTR&&(Xt===mn&&(Xt=D(Xt)),T(Xt,$n.ADD_ATTR)),$n.ADD_URI_SAFE_ATTR&&T(en,$n.ADD_URI_SAFE_ATTR),$n.FORBID_CONTENTS&&(Hi===yn&&(Hi=D(Hi)),T(Hi,$n.FORBID_CONTENTS)),xn&&($t["#text"]=!0),_t&&T($t,["html","head","body"]),$t.table&&(T($t,["tbody"]),delete ti.tbody),a&&a($n),yo=$n)},Or=T({},["mi","mo","mn","ms","mtext"]),Ko=T({},["foreignobject","desc","title","annotation-xml"]),Gr=T({},p);T(Gr,H),T(Gr,I);var Cl=T({},_);T(Cl,j);var nl=function($n){var po=Et($n);po&&po.tagName||(po={namespaceURI:ci,tagName:"template"});var lo=m($n.tagName),ll=m(po.tagName);if($n.namespaceURI===oi)return po.namespaceURI===ci?lo==="svg":po.namespaceURI===hi?lo==="svg"&&(ll==="annotation-xml"||Or[ll]):!!Gr[lo];if($n.namespaceURI===hi)return po.namespaceURI===ci?lo==="math":po.namespaceURI===oi?lo==="math"&&Ko[ll]:!!Cl[lo];if($n.namespaceURI===ci){if(po.namespaceURI===oi&&!Ko[ll]||po.namespaceURI===hi&&!Or[ll])return!1;var vl=T({},["title","style","font","a","script"]);return!Cl[lo]&&(vl[lo]||!Gr[lo])}return!1},cl=function($n){g(Ce.removed,{element:$n});try{$n.parentNode.removeChild($n)}catch{try{$n.outerHTML=Lt}catch{$n.remove()}}},Ll=function($n,po){try{g(Ce.removed,{attribute:po.getAttributeNode($n),from:po})}catch{g(Ce.removed,{attribute:null,from:po})}if(po.removeAttribute($n),$n==="is"&&!Xt[$n])if(ln||Nn)try{cl(po)}catch{}else try{po.setAttribute($n,"")}catch{}},ya=function($n){var po=void 0,lo=void 0;if(Wt)$n=""+$n;else{var ll=C($n,/^[\r\n\t ]+/);lo=ll&&ll[0]}Wi==="application/xhtml+xml"&&($n=''+$n+"");var vl=ot?ot.createHTML($n):$n;if(Yn===ci)try{po=new Xe().parseFromString(vl,Wi)}catch{}if(!po||!po.documentElement){po=Tt.createDocument(Yn,"template",null);try{po.documentElement.innerHTML=si?"":vl}catch{}}var wl=po.body||po.documentElement;return $n&&lo&&wl.insertBefore(ye.createTextNode(lo),wl.childNodes[0]||null),Yn===ci?Ye.call(po,_t?"html":"body")[0]:_t?po.documentElement:wl},gl=function($n){return Ie.call($n.ownerDocument||$n,$n,Fe.SHOW_ELEMENT|Fe.SHOW_COMMENT|Fe.SHOW_TEXT,null,!1)},na=function($n){return $n instanceof We&&(typeof $n.nodeName!="string"||typeof $n.textContent!="string"||typeof $n.removeChild!="function"||!($n.attributes instanceof Ze)||typeof $n.removeAttribute!="function"||typeof $n.setAttribute!="function"||typeof $n.namespaceURI!="string"||typeof $n.insertBefore!="function")},ia=function($n){return(Pe===void 0?"undefined":ke(Pe))==="object"?$n instanceof Pe:$n&&($n===void 0?"undefined":ke($n))==="object"&&typeof $n.nodeType=="number"&&typeof $n.nodeName=="string"},Al=function($n,po,lo){Dt[$n]&&k(Dt[$n],function(ll){ll.call(Ce,po,lo,yo)})},Ul=function($n){var po=void 0;if(Al("beforeSanitizeElements",$n,null),na($n)||C($n.nodeName,/[\u0080-\uFFFF]/))return cl($n),!0;var lo=Bn($n.nodeName);if(Al("uponSanitizeElement",$n,{tagName:lo,allowedTags:$t}),!ia($n.firstElementChild)&&(!ia($n.content)||!ia($n.content.firstElementChild))&&E(/<[/\w]/g,$n.innerHTML)&&E(/<[/\w]/g,$n.textContent)||lo==="select"&&E(/