This commit is contained in:
zhishi 2026-04-02 23:49:41 +08:00
commit 8b5a8ff9c2
12 changed files with 1301 additions and 1454 deletions

BIN
data/latest.zip Normal file

Binary file not shown.

27
data/update.json Normal file
View File

@ -0,0 +1,27 @@
{
"version": "1.0.8",
"time": 1775118545494,
"data": {
"toonflow": [
{
"type": "zip",
"url": "https://toonflow.oss-cn-beijing.aliyuncs.com/latest/latest.zip"
},
{
"type": "windows",
"url": "https://toonflow.oss-cn-beijing.aliyuncs.com/latest/latest.exe"
},
{
"type": "linux",
"url": "https://toonflow.oss-cn-beijing.aliyuncs.com/latest/latest.AppImage"
},
{
"type": "macos",
"url": "https://toonflow.oss-cn-beijing.aliyuncs.com/latest/latest.dmg"
}
],
"github": [],
"atomgit": [],
"gitee": []
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 169 KiB

File diff suppressed because one or more lines are too long

BIN
docs/g-star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

View File

@ -13,19 +13,16 @@ declare const __APP_VERSION__: string | undefined;
* extraResources data * extraResources data
*/ */
function getVersionFromFile(filePath: string): string | null { function getVersionFromUpdateJson(filePath: string): string | null {
try { try {
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
return fs.readFileSync(filePath, "utf8").trim(); const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
return data.version ?? null;
} }
} catch {} } catch {}
return null; return null;
} }
function writeVersionToFile(filePath: string, version: string): void {
fs.writeFileSync(filePath, version, { encoding: "utf8" });
}
function copyDirForce(src: string, dest: string): void { function copyDirForce(src: string, dest: string): void {
if (!fs.existsSync(src)) return; if (!fs.existsSync(src)) return;
if (fs.existsSync(dest)) { if (fs.existsSync(dest)) {
@ -37,14 +34,13 @@ function copyDirForce(src: string, dest: string): void {
function initializeData(): void { function initializeData(): void {
const srcDir = path.join(process.resourcesPath, "data"); const srcDir = path.join(process.resourcesPath, "data");
const destDir = path.join(app.getPath("userData"), "data"); const destDir = path.join(app.getPath("userData"), "data");
const versionFile = path.join(destDir, "version.txt"); const updateJsonFile = path.join(destDir, "update.json");
const currentVersion = typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : "0.0.0"; const currentVersion = typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : "0.0.0";
const userVersion = getVersionFromFile(versionFile); const userVersion = getVersionFromUpdateJson(updateJsonFile);
// 首次安装或无version.txt,直接全量拷贝 // 首次安装或无update.json,直接全量拷贝
if (!fs.existsSync(destDir) || !userVersion) { if (!fs.existsSync(destDir) || !userVersion) {
copyDirRecursive(srcDir, destDir); copyDirRecursive(srcDir, destDir);
writeVersionToFile(versionFile, currentVersion);
return; return;
} }
@ -52,7 +48,6 @@ function initializeData(): void {
if (userVersion !== currentVersion) { if (userVersion !== currentVersion) {
copyDirForce(path.join(srcDir, "serve"), path.join(destDir, "serve")); copyDirForce(path.join(srcDir, "serve"), path.join(destDir, "serve"));
copyDirForce(path.join(srcDir, "web"), path.join(destDir, "web")); copyDirForce(path.join(srcDir, "web"), path.join(destDir, "web"));
writeVersionToFile(versionFile, currentVersion);
} }
} }
@ -61,6 +56,7 @@ function copyDirRecursive(src: string, dest: string): void {
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true }); if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
for (const entry of fs.readdirSync(src, { withFileTypes: true })) { for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
// 跳过 oss 文件夹和 db2.sqlite 文件 // 跳过 oss 文件夹和 db2.sqlite 文件
if (entry.isDirectory() && entry.name === "logs") continue;
if (entry.isDirectory() && entry.name === "oss") continue; if (entry.isDirectory() && entry.name === "oss") continue;
if (!entry.isDirectory() && entry.name === "db2.sqlite") continue; if (!entry.isDirectory() && entry.name === "db2.sqlite") continue;
const srcPath = path.join(src, entry.name); const srcPath = path.join(src, entry.name);

View File

@ -43,12 +43,23 @@ export async function decisionAI(ctx: AgentContext) {
const skill = path.join(u.getPath("skills"), "production_agent_decision.md"); const skill = path.join(u.getPath("skills"), "production_agent_decision.md");
const prompt = await fs.promises.readFile(skill, "utf-8"); const prompt = await fs.promises.readFile(skill, "utf-8");
const projectInfo = await u.db("o_project").where("id", ctx.resTool.data.projectId).first();
if (!projectInfo) throw new Error(`项目不存在ID: ${ctx.resTool.data.projectId}`);
const [_, imageModelName] = projectInfo.imageModel!.split(":");
const [id, videoModelName] = projectInfo.videoModel!.split(":");
const data = await u.db("o_vendorConfig").where("id", id).select("models").first();
const models = JSON.parse(data!.models!);
const findData = models.find((i: any) => i.modelName == name);
const isRef = findData.mode.every((i: any) => Array.isArray(i));
const modelInfo = `项目使用的模型如下:\n图像模型${imageModelName}\n视频模型${videoModelName}\n多参${isRef ? "是" : "否"}`;
const mem = buildMemPrompt(await memory.get(text)); const mem = buildMemPrompt(await memory.get(text));
const { textStream } = await u.Ai.Text("productionAgent").stream({ const { textStream } = await u.Ai.Text("productionAgent").stream({
messages: [ messages: [
{ role: "system", content: prompt }, { role: "system", content: prompt },
{ role: "assistant", content: mem }, { role: "assistant", content: mem + "\n" + modelInfo },
{ role: "user", content: text }, { role: "user", content: text },
], ],
abortSignal, abortSignal,
@ -138,13 +149,20 @@ function createSubAgent(parentCtx: AgentContext) {
"分镜面板:<storyboardItem videoDesc='视频描述' prompt=提示词内容 track='分组' duration='视频推荐时间' associateAssetsIds='[该分镜所需的资产ID列表]'></storyboardItem>", "分镜面板:<storyboardItem videoDesc='视频描述' prompt=提示词内容 track='分组' duration='视频推荐时间' associateAssetsIds='[该分镜所需的资产ID列表]'></storyboardItem>",
"```", "```",
].join("\n"); ].join("\n");
const projectData = await u.db("o_project").where("id", resTool.data.projectId).first();
const modelInfo = `项目使用的模型如下:\n图像模型${projectData?.imageModel}\n视频模型${projectData?.videoModel}`;
const projectInfo = await u.db("o_project").where("id", resTool.data.projectId).first(); const projectInfo = await u.db("o_project").where("id", resTool.data.projectId).first();
if (!projectInfo) throw new Error(`项目不存在ID: ${resTool.data.projectId}`); if (!projectInfo) throw new Error(`项目不存在ID: ${resTool.data.projectId}`);
const artSkills = await createArtSkills(projectInfo?.artStyle!); const artSkills = await createArtSkills(projectInfo?.artStyle!);
const [_, imageModelName] = projectInfo.imageModel!.split(":");
const [id, videoModelName] = projectInfo.videoModel!.split(":");
const data = await u.db("o_vendorConfig").where("id", id).select("models").first();
const models = JSON.parse(data!.models!);
const findData = models.find((i: any) => i.modelName == name);
const isRef = findData.mode.every((i: any) => Array.isArray(i));
const modelInfo = `项目使用的模型如下:\n图像模型${imageModelName}\n视频模型${videoModelName}\n多参${isRef ? "是" : "否"}`;
return runAgent({ return runAgent({
prompt, prompt,
system: systemPrompt + addPrompt, system: systemPrompt + addPrompt,
@ -194,7 +212,6 @@ async function createArtSkills(artName: string) {
return res; return res;
} }
function removeAllXmlTags(text: string): string { function removeAllXmlTags(text: string): string {
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, ""); text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, "");
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, ""); text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, "");

View File

@ -95,8 +95,12 @@ export default router.post(
`; `;
const { text } = await u.Ai.Text("universalAi").invoke({ const { text } = await u.Ai.Text("universalAi").invoke({
system: `${videoPrompt?.data}\n${visualManual}\n${directorManual}`, system: videoPrompt?.data!,
messages: [ messages: [
{
role: "assistant",
content: `${visualManual}\n${directorManual}`,
},
{ {
role: "user", role: "user",
content: content, content: content,

View File

@ -1,5 +1,7 @@
import express from "express"; import express from "express";
import { success } from "@/lib/responseFormat"; import { success, error } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
import { z } from "zod";
const router = express.Router(); const router = express.Router();
import fs from "fs"; import fs from "fs";
@ -17,21 +19,49 @@ const APP_VERSION: string = (() => {
return pkg.version; return pkg.version;
})(); })();
export default router.post("/", async (req, res) => { export default router.post(
const tagger = "1.1.0"; "/",
const taggerList = tagger.split(".").map(Number); validateFields({
const currentVersionList = APP_VERSION.split(".").map(Number); source: z.enum(["toonflow", "github", "gitee", "atomgit"]),
//对比Major }),
if (taggerList[0] > currentVersionList[0]) { async (req, res) => {
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: false })); const { source } = req.body;
}
//对比Minor const getUrl = "https://toonflow.oss-cn-beijing.aliyuncs.com/update.json";
if (taggerList[1] > currentVersionList[1]) {
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: false })); const versionInfo = await fetch(getUrl).then((res) => res.json());
} if (!versionInfo) return res.status(400).send(error("无法获取版本信息"));
//Patch const { version: tagger, time, data } = versionInfo;
if (taggerList[2] > currentVersionList[2]) {
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: false })); const sourceData = data[source];
} if (!sourceData) return res.status(400).send(error("无法获取该源的下载信息"));
return res.status(200).send(success({ needUpdate: false, latestVersion: tagger, reinstall: false }));
}); const platformType: Record<string, string> = {
win32: "windows",
darwin: "macos",
linux: "linux",
};
const zipItem = sourceData.find((d: any) => d.type === "zip");
const installerItem = sourceData.find((d: any) => d.type === platformType[process.platform]);
const taggerList = tagger.split(".").map(Number);
const currentVersionList = APP_VERSION.split(".").map(Number);
//对比Major
if (taggerList[0] > currentVersionList[0]) {
if (!installerItem) return res.status(400).send(error("该源暂无适用于当前系统的安装包"));
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: true, time, url: installerItem.url }));
}
//对比Minor
if (taggerList[1] > currentVersionList[1]) {
if (!installerItem) return res.status(400).send(error("该源暂无适用于当前系统的安装包"));
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: true, time, url: installerItem.url }));
}
//Patch
if (taggerList[2] > currentVersionList[2]) {
if (!zipItem) return res.status(400).send(error("该源暂无增量更新包"));
return res.status(200).send(success({ needUpdate: true, latestVersion: tagger, reinstall: false, time, url: zipItem.url }));
}
return res.status(200).send(success({ needUpdate: false, latestVersion: tagger, reinstall: false, time }));
},
);

View File

@ -1,238 +1,64 @@
import express from "express"; import express from "express";
import { success, error } from "@/lib/responseFormat";
import getPath from "@/utils/getPath";
import z from "zod"; import z from "zod";
import { validateFields } from "@/middleware/middleware";
import u from "@/utils";
import fs from "fs"; import fs from "fs";
import path from "path";
import axios from "axios"; import axios from "axios";
import compressing from "compressing"; import compressing from "compressing";
import { validateFields } from "@/middleware/middleware"; import path from "path";
import { spawn } from "child_process"; import { success, error } from "@/lib/responseFormat";
const router = express.Router(); const router = express.Router();
/** 仓库源配置 */ const runInstaller = (installerPath: string) => {
const REPO_SOURCES = { const { exec } = require("child_process");
github: { if (process.platform === "darwin") {
repo: "HBAI-Ltd/Toonflow-app", exec(`open "${installerPath}"`);
api: "https://api.github.com/repos/HBAI-Ltd/Toonflow-app/releases/latest", } else {
headers: { Accept: "application/vnd.github.v3+json" }, if (process.platform !== "win32") fs.chmodSync(installerPath, 0o755);
}, exec(`"${installerPath}"`);
gitee: {
repo: "HBAI-Ltd/Toonflow-app",
api: "https://gitee.com/api/v5/repos/HBAI-Ltd/Toonflow-app/releases/latest",
headers: {},
},
} as const;
type SourceType = keyof typeof REPO_SOURCES;
function normalizeAssets(source: SourceType, release: any): { name: string; browser_download_url: string }[] {
if (source === "github") {
return (release.assets ?? []).map((a: any) => ({
name: a.name,
browser_download_url: a.browser_download_url,
}));
} }
return (release.assets ?? []).map((a: any) => ({ };
name: a.name,
browser_download_url: a.browser_download_url,
}));
}
/** 获取当前系统平台和架构标识,用于匹配安装包文件名 */
function getPlatformArch(): { platform: string; arch: string } {
const platform = process.platform === "win32" ? "win" : process.platform === "darwin" ? "mac" : "linux";
const arch = process.arch === "arm64" ? "arm64" : "x64";
return { platform, arch };
}
/** 匹配安装包资产(.exe / .dmg / .AppImage / .portable.exe */
function findInstallerAsset(assets: any[]): any | null {
const { platform, arch } = getPlatformArch();
const installerExtensions: Record<string, string[]> = {
win: [".exe"],
mac: [".dmg"],
linux: [".AppImage"],
};
const exts = installerExtensions[platform] || [".exe"];
// 优先找 nsis 安装包(排除 portable如果没有再找 portable
return (
assets.find(
(a: any) =>
exts.some((ext) => a.name.endsWith(ext)) &&
a.name.includes(arch) &&
!a.name.toLowerCase().includes("portable") &&
!a.name.endsWith(".blockmap"),
) ??
assets.find((a: any) => exts.some((ext) => a.name.endsWith(ext)) && a.name.includes(arch) && !a.name.endsWith(".blockmap")) ??
null
);
}
/**
*
*/
async function downloadFile(url: string, destPath: string): Promise<void> {
const dir = path.dirname(destPath);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
const response = await axios.get(url, {
responseType: "stream",
headers: { Accept: "application/octet-stream" },
timeout: 600_000, // 10 分钟超时
});
const writer = fs.createWriteStream(destPath);
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on("finish", resolve);
writer.on("error", reject);
});
}
export default router.post( export default router.post(
"/", "/",
validateFields({ validateFields({
source: z.enum(["github", "gitee"]), url: z.url(),
reinstall: z.boolean(), reinstall: z.boolean(),
latestVersion: z.string(),
}), }),
async (req, res) => { async (req, res) => {
try { const { reinstall, url } = req.body;
const { reinstall, latestVersion, source } = req.body as { const rootDir = u.getPath(["temp"]);
reinstall: boolean; fs.mkdirSync(rootDir, { recursive: true });
latestVersion: string; if (reinstall) {
source: string; const response = await axios.get(url, { responseType: "arraybuffer" });
}; const ext =
path.extname(new URL(url).pathname) || (process.platform === "win32" ? ".exe" : process.platform === "darwin" ? ".dmg" : ".AppImage");
if (!latestVersion) { const installerPath = path.join(rootDir, `latest${ext}`);
return res.status(400).send(error("缺少目标版本号 latestVersion")); fs.writeFileSync(installerPath, response.data);
runInstaller(installerPath);
res.status(200).send(success("安装包已下载并启动"));
} else {
const zip = await axios.get(url, { responseType: "arraybuffer" }).then((res) => res.data);
fs.writeFileSync(`${rootDir}/latest.zip`, zip);
await compressing.zip.uncompress(`${rootDir}/latest.zip`, rootDir);
const tempServerPath = u.getPath(["temp", "serve"]);
if (fs.existsSync(tempServerPath)) {
fs.cpSync(tempServerPath, u.getPath(["serve"]), { recursive: true });
} }
const webPath = u.getPath(["temp", "web"]);
const sourceConfig = REPO_SOURCES[source as SourceType] ?? REPO_SOURCES.github; if (fs.existsSync(webPath)) {
fs.cpSync(webPath, u.getPath(["web"]), { recursive: true });
// ─── 获取 Release 信息(支持 GitHub / Gitee ──────────────────────
let releaseRes;
try {
releaseRes = await axios.get(sourceConfig.api, {
headers: sourceConfig.headers,
timeout: 30_000,
});
} catch (e) {
return res.status(500).send(error(`获取 ${source} Release 信息失败`));
} }
const tempSkillsPath = u.getPath(["temp", "skills"]);
const release = releaseRes.data; if (fs.existsSync(tempSkillsPath)) {
fs.cpSync(tempSkillsPath, u.getPath(["skills"]), { recursive: true, force: false });
const assets = normalizeAssets(source as SourceType, release);
if (reinstall) {
// ═══════════════ 模式 A下载完整安装包 ═══════════════
const installerAsset = findInstallerAsset(assets);
if (!installerAsset) {
return res.status(404).send(error("未找到当前平台的安装包,请前往 GitHub Releases 手动下载"));
}
const tempDir = getPath(["temp"]);
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });
const installerPath = path.join(tempDir, installerAsset.name);
// 如果已经下载过相同文件,跳过下载
if (!fs.existsSync(installerPath)) {
await downloadFile(installerAsset.browser_download_url, installerPath);
}
// 使用 shell 打开安装程序
const sub = spawn("cmd", ["/c", `${installerPath}`], {
cwd: tempDir,
detached: true,
stdio: "ignore",
windowsHide: false,
});
sub.unref();
return res.status(200).send(
success({
type: "reinstall",
version: latestVersion,
filePath: installerPath,
message: "安装包已下载并打开,请按照安装向导完成更新",
}),
);
} else {
// ═══════════════ 模式 Bdata 补丁热更新 ═══════════════
const patchAsset = assets.find((a: any) => a.name.startsWith(latestVersion) && a.name.endsWith(".zip")) ?? null;
if (!patchAsset) {
return res.status(404).send(error("未找到 data 补丁包,请前往 GitHub Releases 手动下载"));
}
//
const tempDir = getPath(["temp"]);
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });
const patchZipPath = path.join(tempDir, `${latestVersion}.zip`);
// 下载补丁 zip
await downloadFile(patchAsset.browser_download_url, patchZipPath);
// 解压覆盖到 data 目录(同名文件夹先删除再解压,确保完全替换)
const dataDir = getPath();
// 先读取 zip 内的顶层文件夹/文件列表,删除 data 目录下的同名项
const zipStream = new compressing.zip.UncompressStream({ source: patchZipPath, zipFileNameEncoding: "utf8" });
const topLevelEntries = new Set<string>();
await new Promise<void>((resolve, reject) => {
zipStream.on("entry", (_header: any, stream: any, next: () => void) => {
const entryName: string = _header.name || "";
// 取顶层名称(第一个 / 之前的部分)
const topName = entryName.split("/")[0];
if (topName) topLevelEntries.add(topName);
stream.resume();
next();
});
zipStream.on("finish", resolve);
zipStream.on("error", reject);
});
// 删除 data 目录下与 zip 顶层同名的文件夹/文件
for (const name of topLevelEntries) {
const targetPath = path.join(dataDir, name);
if (fs.existsSync(targetPath)) {
const stat = fs.statSync(targetPath);
if (stat.isDirectory()) {
fs.rmSync(targetPath, { recursive: true, force: true });
} else {
fs.unlinkSync(targetPath);
}
}
}
await compressing.zip.uncompress(patchZipPath, dataDir, { zipFileNameEncoding: "utf8" });
// 清理临时文件
try {
fs.unlinkSync(patchZipPath);
} catch {
// 忽略清理失败
}
return res.status(200).send(
success({
type: "patch",
version: latestVersion,
message: "补丁更新完成,请重启应用以使更新生效",
restartRequired: true,
}),
);
} }
} catch (err: any) { const tempModelsPath = u.getPath(["temp", "models"]);
console.error("[downloadApp] 更新失败:", err); if (fs.existsSync(tempModelsPath)) {
const message = err?.response?.status === 404 ? "未找到更新资源,请检查版本号或稍后重试" : (err?.message ?? "更新失败,请稍后重试"); fs.cpSync(tempModelsPath, u.getPath(["models"]), { recursive: true, force: false });
return res.status(500).send(error(message)); }
fs.rmSync(rootDir, { recursive: true, force: true });
res.status(200).send(success("更新成功5秒后重启"));
} }
}, },
); );

View File

@ -14,7 +14,5 @@ export default router.post("/", async (req, res) => {
onlyFiles: true, onlyFiles: true,
}); });
console.log("%c Line:15 🍺 entries", "background:#e41a6a", entries);
res.status(200).send(success(entries)); res.status(200).send(success(entries));
}); });

View File

@ -1,60 +1,10 @@
// @db-hash 7af86e2bafe5cab7d175eb68cf76ed7a <<<<<<< HEAD
// @db-hash 6fa5017e455bc367c9c902ba574d11b4
=======
// @db-hash 35cf00f711e9d4df398703de70511684
>>>>>>> c7be353ef92bb888df3af432bb21220b2fd35d7d
//该文件由脚本自动生成,请勿手动修改 //该文件由脚本自动生成,请勿手动修改
export interface _o_storyboard_old_20260402 {
'createTime'?: number | null;
'duration'?: string | null;
'filePath'?: string | null;
'flowId'?: number | null;
'id'?: number;
'index'?: number | null;
'projectId'?: number | null;
'prompt'?: string | null;
'reason'?: string | null;
'scriptId'?: number | null;
'state'?: string | null;
'trackId'?: number | null;
}
export interface _o_storyboard_old_20260402_1 {
'createTime'?: number | null;
'duration'?: string | null;
'filePath'?: string | null;
'flowId'?: number | null;
'id'?: number;
'index'?: number | null;
'projectId'?: number | null;
'prompt'?: string | null;
'reason'?: string | null;
'scriptId'?: number | null;
'shouldGenerateImage'?: number | null;
'state'?: string | null;
'track'?: string | null;
'trackId'?: number | null;
'videoPrompt'?: string | null;
}
export interface _o_vendorConfig_old_20260401 {
'author'?: string | null;
'code'?: string | null;
'createTime'?: number | null;
'description'?: string | null;
'enableEnglish'?: number | null;
'icon'?: string | null;
'id'?: string;
'inputs'?: string | null;
'inputValues'?: string | null;
'models'?: string | null;
'name'?: string | null;
}
export interface _o_videoTrack_old_20260402 {
'id'?: number;
'projectId'?: number | null;
'prompt'?: string | null;
'reason'?: string | null;
'scriptId'?: number | null;
'selectVideoId'?: number | null;
'state'?: string | null;
'videoId'?: number | null;
}
export interface memories { export interface memories {
'content': string; 'content': string;
'createTime': number; 'createTime': number;
@ -130,7 +80,6 @@ export interface o_image {
'filePath'?: string | null; 'filePath'?: string | null;
'id'?: number; 'id'?: number;
'model'?: string | null; 'model'?: string | null;
'reason'?: string | null;
'resolution'?: string | null; 'resolution'?: string | null;
'state'?: string | null; 'state'?: string | null;
'type'?: string | null; 'type'?: string | null;
@ -165,6 +114,7 @@ export interface o_outlineNovel {
export interface o_project { export interface o_project {
'artStyle'?: string | null; 'artStyle'?: string | null;
'createTime'?: number | null; 'createTime'?: number | null;
'directorManual'?: string | null;
'id'?: number | null; 'id'?: number | null;
'imageModel'?: string | null; 'imageModel'?: string | null;
'imageQuality'?: string | null; 'imageQuality'?: string | null;
@ -255,7 +205,6 @@ export interface o_vendorConfig {
'createTime'?: number | null; 'createTime'?: number | null;
'description'?: string | null; 'description'?: string | null;
'enable'?: number | null; 'enable'?: number | null;
'enableEnglish'?: number | null;
'icon'?: string | null; 'icon'?: string | null;
'id'?: string; 'id'?: string;
'inputs'?: string | null; 'inputs'?: string | null;
@ -285,10 +234,6 @@ export interface o_videoTrack {
} }
export interface DB { export interface DB {
"_o_storyboard_old_20260402": _o_storyboard_old_20260402;
"_o_storyboard_old_20260402_1": _o_storyboard_old_20260402_1;
"_o_vendorConfig_old_20260401": _o_vendorConfig_old_20260401;
"_o_videoTrack_old_20260402": _o_videoTrack_old_20260402;
"memories": memories; "memories": memories;
"o_agentDeploy": o_agentDeploy; "o_agentDeploy": o_agentDeploy;
"o_agentWorkData": o_agentWorkData; "o_agentWorkData": o_agentWorkData;