Merge branch 'develop' of https://github.com/HBAI-Ltd/Toonflow-app into develop
# Conflicts: # src/router.ts # src/types/database.d.ts
This commit is contained in:
commit
2a15c144ae
13
README.md
13
README.md
@ -103,8 +103,8 @@ https://www.bilibili.com/video/BV1na6wB6Ea2
|
||||
| 操作系统 | GitHub 下载 | 夸克网盘下载 | 说明 |
|
||||
| :------: | :----------------------------------------------------------- | :---------------------------------------------- | :------------- |
|
||||
| Windows | [Release](https://github.com/HBAI-Ltd/Toonflow-app/releases) | [夸克网盘](https://pan.quark.cn/s/94ef07509df0) | 官方发布安装包 |
|
||||
| Linux | ⚙️ 敬请期待 | ⚙️ 敬请期待 | 即将发布 |
|
||||
| macOS | ⚙️ 敬请期待 | ⚙️ 敬请期待 | 即将发布 |
|
||||
| Linux | [Release](https://github.com/HBAI-Ltd/Toonflow-app/releases) | [夸克网盘](https://pan.quark.cn/s/94ef07509df0) | 官方发布安装包 |
|
||||
| macOS | [Release](https://github.com/HBAI-Ltd/Toonflow-app/releases) | [夸克网盘](https://pan.quark.cn/s/94ef07509df0) | 官方发布安装包 |
|
||||
|
||||
> 目前仅支持 Windows 版本,其他系统将陆续开放。
|
||||
|
||||
@ -530,10 +530,11 @@ pm2 monit # 监控面板
|
||||
|
||||
~~交流群 12~~
|
||||
|
||||
交流群 13:
|
||||
~~交流群 13~~
|
||||
|
||||
<img src="./docs/chat13QR.jpg?r=2" alt="Toonflow Logo" height="400"/>
|
||||
<p>使用微信扫码添加,二维码过期可提交 Issues 提醒更新</p>
|
||||
拉群小助手:
|
||||
|
||||
<img src="./docs/QR.png" alt="Toonflow Logo" height="400"/>
|
||||
|
||||
---
|
||||
|
||||
@ -555,7 +556,7 @@ Toonflow 基于 AGPL-3.0 协议开源发布,许可证详情:https://www.gnu.
|
||||
|
||||
# ⭐️ 星标历史
|
||||
|
||||
[](https://www.star-history.com/#HBAI-Ltd/Toonflow-app&type=date&legend=top-left)
|
||||
[](https://www.star-history.com/#HBAI-Ltd/Toonflow-app&type=timeline&legend=top-left)
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
docs/QR.png
Normal file
BIN
docs/QR.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
BIN
docs/chat12QR.jpg
Normal file
BIN
docs/chat12QR.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
BIN
docs/chat13QR.jpg
Normal file
BIN
docs/chat13QR.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
1411
output.json
Normal file
1411
output.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -317,6 +317,10 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
|
||||
size: "4K",
|
||||
aspectRatio: projectInfo?.videoRatio ? (projectInfo.videoRatio as any) : "16:9",
|
||||
imageBase64: processedImages.map((buf) => buf.toString("base64")),
|
||||
taskClass: "分镜图生成",
|
||||
name: `分镜图-${outline?.title || "未知剧集"}`,
|
||||
describe: prompts,
|
||||
projectId,
|
||||
},
|
||||
apiConfig,
|
||||
);
|
||||
|
||||
1411
src/lib/artStyle.ts
Normal file
1411
src/lib/artStyle.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
import { Knex } from "knex";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { artStyle } from "./artStyle";
|
||||
interface TableSchema {
|
||||
name: string;
|
||||
builder: (table: Knex.CreateTableBuilder) => void;
|
||||
@ -96,6 +97,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
name: "t_project",
|
||||
builder: (table) => {
|
||||
table.integer("id");
|
||||
table.string("projectType");
|
||||
table.text("name");
|
||||
table.text("intro");
|
||||
table.text("type");
|
||||
@ -160,20 +162,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t_taskList",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("projectName");
|
||||
table.text("name");
|
||||
table.text("prompt");
|
||||
table.text("state");
|
||||
table.text("startTime");
|
||||
table.text("endTime");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t_image",
|
||||
builder: (table) => {
|
||||
@ -207,6 +195,36 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
},
|
||||
initData: async (knex) => {},
|
||||
},
|
||||
{
|
||||
name: "t_myTasks",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("projectId");
|
||||
table.string("taskClass");
|
||||
table.string("relatedObjects");
|
||||
table.string("model");
|
||||
table.text("describe");
|
||||
table.string("state");
|
||||
table.integer("startTime");
|
||||
table.string("reason");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
initData: async (knex) => {},
|
||||
},
|
||||
{
|
||||
name: "t_artStyle",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.string("name");
|
||||
table.text("styles");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
initData: async (knex) => {
|
||||
await knex("t_artStyle").insert(artStyle.map((item, index) => ({ id: index + 1, name: item.name, styles: JSON.stringify(item.styles) })));
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t_videoConfig",
|
||||
builder: (table) => {
|
||||
|
||||
19
src/routes/artStyle/getArtStyle.ts
Normal file
19
src/routes/artStyle/getArtStyle.ts
Normal file
@ -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({
|
||||
name: z.string(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { name } = req.body;
|
||||
const data = await u.db("t_artStyle").where("name", name).select("styles").first();
|
||||
const styles = data?.styles ? JSON.parse(data.styles) : [];
|
||||
res.status(200).send(success(styles));
|
||||
},
|
||||
);
|
||||
@ -123,8 +123,13 @@ export default router.post(
|
||||
state: "生成中",
|
||||
assetsId: id,
|
||||
});
|
||||
const apiConfig = await u.getPromptAi("assetsImage");
|
||||
let taskClass = "";
|
||||
if (type == "role") taskClass = "角色图生成";
|
||||
if (type == "scene") taskClass = "场景图生成";
|
||||
if (type == "props") taskClass = "道具图生成";
|
||||
if (type == "storyboard") taskClass = "分镜图生成";
|
||||
|
||||
const apiConfig = await u.getPromptAi("assetsImage");
|
||||
try {
|
||||
const contentStr = await u.ai.image(
|
||||
{
|
||||
@ -133,6 +138,10 @@ export default router.post(
|
||||
imageBase64: base64 ? [base64] : [],
|
||||
size: "2K",
|
||||
aspectRatio: "16:9",
|
||||
taskClass: taskClass,
|
||||
name: name,
|
||||
describe: prompt,
|
||||
projectId: projectId,
|
||||
},
|
||||
apiConfig,
|
||||
);
|
||||
@ -171,7 +180,6 @@ export default router.post(
|
||||
filePath: imagePath,
|
||||
type: insertType,
|
||||
});
|
||||
|
||||
const path = await u.oss.getFileUrl(imagePath!);
|
||||
|
||||
// const state = await u.db("t_assets").where("id", id).select("state").first();
|
||||
|
||||
@ -24,6 +24,10 @@ export default router.post(
|
||||
imageBase64: [],
|
||||
aspectRatio: "16:9",
|
||||
size: "1K",
|
||||
taskClass: "测试任务",
|
||||
name: "测试图片生成",
|
||||
describe: "测试语言模型生成图片",
|
||||
projectId: 0,
|
||||
},
|
||||
{
|
||||
model: modelName,
|
||||
|
||||
@ -28,6 +28,10 @@ export default router.post(
|
||||
aspectRatio: "16:9",
|
||||
audio: false,
|
||||
mode: "single",
|
||||
taskClass: "测试视频生成",
|
||||
name: "测试视频生成",
|
||||
describe: "测试视频生成",
|
||||
projectId: 0,
|
||||
},
|
||||
{
|
||||
model: modelName,
|
||||
|
||||
@ -9,6 +9,7 @@ const router = express.Router();
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
projectType: z.string(),
|
||||
name: z.string(),
|
||||
intro: z.string(),
|
||||
type: z.string(),
|
||||
@ -16,9 +17,10 @@ export default router.post(
|
||||
videoRatio: z.string(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { name, intro, type, artStyle, videoRatio } = req.body;
|
||||
const { projectType, name, intro, type, artStyle, videoRatio } = req.body;
|
||||
|
||||
await u.db("t_project").insert({
|
||||
projectType,
|
||||
name,
|
||||
intro,
|
||||
type,
|
||||
@ -29,5 +31,5 @@ export default router.post(
|
||||
});
|
||||
|
||||
res.status(200).send(success({ message: "新增项目成功" }));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -27,6 +27,7 @@ export default router.post(
|
||||
await u.db("t_novel").where("projectId", id).delete();
|
||||
await u.db("t_storyline").where("projectId", id).delete();
|
||||
await u.db("t_outline").where("projectId", id).delete();
|
||||
await u.db("t_myTasks").where("projectId", id).delete();
|
||||
|
||||
await u.db("t_script").where("projectId", id).delete();
|
||||
await u.db("t_assets").where("projectId", id).delete();
|
||||
@ -55,5 +56,5 @@ export default router.post(
|
||||
}
|
||||
|
||||
res.status(200).send(success({ message: "删除项目成功" }));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -14,17 +14,19 @@ export default router.post(
|
||||
type: z.string().optional().nullable(),
|
||||
artStyle: z.string().optional().nullable(),
|
||||
videoRatio: z.string().optional().nullable(),
|
||||
projectType: z.string().optional().nullable(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id, intro, type, artStyle, videoRatio } = req.body;
|
||||
const { id, intro, type, artStyle, videoRatio, projectType } = req.body;
|
||||
|
||||
await u.db("t_project").where("id", id).update({
|
||||
intro,
|
||||
type,
|
||||
artStyle,
|
||||
videoRatio,
|
||||
projectType,
|
||||
});
|
||||
|
||||
res.status(200).send(success({ message: "修改成功" }));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -27,6 +27,10 @@ async function superResolutionAndSave(src: string, projectId: number, videoRatio
|
||||
systemPrompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
||||
prompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
||||
imageBase64: [await urlToBase64(src)],
|
||||
taskClass: "分镜图超分",
|
||||
name: `分镜图超分-${v4()}`,
|
||||
describe: `原始图片链接: ${src}`,
|
||||
projectId,
|
||||
},
|
||||
apiConfig,
|
||||
);
|
||||
|
||||
@ -4,50 +4,45 @@ import { success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { number, z } from "zod";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.get(
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
projectName: z.string(),
|
||||
taskName: z.string(),
|
||||
state: z.string(),
|
||||
state: z.string().optional().nullable(),
|
||||
taskClass: z.string().optional().nullable(),
|
||||
page: z.number(),
|
||||
limit: z.number(),
|
||||
projectId: z.number(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { projectName, taskName, state, page = 1, limit = 10 }: any = req.query;
|
||||
const { taskClass, state, page = 1, limit = 10, projectId }: any = req.body;
|
||||
const offset = (page - 1) * limit;
|
||||
const data = await u
|
||||
.db("t_taskList")
|
||||
.db("t_myTasks")
|
||||
.where("projectId", projectId)
|
||||
.andWhere((qb) => {
|
||||
if (projectName) {
|
||||
qb.andWhere("t_taskList.projectName", projectName);
|
||||
}
|
||||
if (taskName) {
|
||||
qb.andWhere("t_taskList.name", taskName);
|
||||
if (taskClass) {
|
||||
qb.andWhere("t_myTasks.taskClass", taskClass);
|
||||
}
|
||||
if (state) {
|
||||
qb.andWhere("t_taskList.state", state);
|
||||
qb.andWhere("t_myTasks.state", state);
|
||||
}
|
||||
})
|
||||
.select("*")
|
||||
.offset(offset)
|
||||
.limit(limit);
|
||||
const totalQuery = (await u
|
||||
.db("t_taskList")
|
||||
.db("t_myTasks")
|
||||
.where("projectId", projectId)
|
||||
.andWhere((qb) => {
|
||||
if (projectName) {
|
||||
qb.andWhere("t_taskList.projectName", projectName);
|
||||
}
|
||||
if (taskName) {
|
||||
qb.andWhere("t_taskList.name", taskName);
|
||||
if (taskClass) {
|
||||
qb.andWhere("t_myTasks.taskClass", taskClass);
|
||||
}
|
||||
if (state) {
|
||||
qb.andWhere("t_taskList.state", state);
|
||||
qb.andWhere("t_myTasks.state", state);
|
||||
}
|
||||
})
|
||||
.count("* as total")
|
||||
.first()) as any;
|
||||
res.status(200).send(success({ data, total: totalQuery?.total }));
|
||||
}
|
||||
},
|
||||
);
|
||||
17
src/routes/task/getTaskCategories.ts
Normal file
17
src/routes/task/getTaskCategories.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import express from "express";
|
||||
import u from "@/utils";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { number, z } from "zod";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
projectId: z.number(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const data = await u.db("t_myTasks").where("projectId", req.body.projectId).select("taskClass").groupBy("taskClass");
|
||||
res.status(200).send(success(data));
|
||||
},
|
||||
);
|
||||
@ -177,6 +177,10 @@ ${prompt}
|
||||
resolution: resolution as any,
|
||||
audio: audioEnabled,
|
||||
mode: mode as any,
|
||||
taskClass: "视频生成",
|
||||
name: `视频生成-${videoId}`,
|
||||
describe: `视频生成,时长${duration}秒,分辨率${resolution}`,
|
||||
projectId,
|
||||
},
|
||||
{
|
||||
baseURL: aiConfigData?.baseUrl!,
|
||||
|
||||
33
src/types/database.d.ts
vendored
33
src/types/database.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// @db-hash bdfbb3a599198f1e91b2e5d7930ccd96
|
||||
// @db-hash 8171d26b6ac1f411a6ec46a0381b821a
|
||||
//该文件由脚本自动生成,请勿手动修改
|
||||
|
||||
export interface t_aiModelMap {
|
||||
@ -7,8 +7,12 @@ export interface t_aiModelMap {
|
||||
'key'?: string | null;
|
||||
'name'?: string | null;
|
||||
}
|
||||
export interface t_artStyle {
|
||||
'id'?: number;
|
||||
'name'?: string | null;
|
||||
'styles'?: string | null;
|
||||
}
|
||||
export interface t_assets {
|
||||
'dialogue'?: string | null;
|
||||
'duration'?: string | null;
|
||||
'episode'?: string | null;
|
||||
'filePath'?: string | null;
|
||||
@ -60,6 +64,17 @@ export interface t_imageModel {
|
||||
'model'?: string | null;
|
||||
'type'?: string | null;
|
||||
}
|
||||
export interface t_myTasks {
|
||||
'describe'?: string | null;
|
||||
'id'?: number;
|
||||
'model'?: string | null;
|
||||
'projectId'?: number | null;
|
||||
'reason'?: string | null;
|
||||
'relatedObjects'?: string | null;
|
||||
'startTime'?: number | null;
|
||||
'state'?: string | null;
|
||||
'taskClass'?: string | null;
|
||||
}
|
||||
export interface t_novel {
|
||||
'chapter'?: string | null;
|
||||
'chapterData'?: string | null;
|
||||
@ -81,6 +96,7 @@ export interface t_project {
|
||||
'id'?: number | null;
|
||||
'intro'?: string | null;
|
||||
'name'?: string | null;
|
||||
'projectType'?: string | null;
|
||||
'type'?: string | null;
|
||||
'userId'?: number | null;
|
||||
'videoRatio'?: string | null;
|
||||
@ -116,15 +132,6 @@ export interface t_storyline {
|
||||
'novelIds'?: string | null;
|
||||
'projectId'?: number | null;
|
||||
}
|
||||
export interface t_taskList {
|
||||
'endTime'?: string | null;
|
||||
'id'?: number;
|
||||
'name'?: string | null;
|
||||
'projectName'?: number | null;
|
||||
'prompt'?: string | null;
|
||||
'startTime'?: string | null;
|
||||
'state'?: string | null;
|
||||
}
|
||||
export interface t_textModel {
|
||||
'id'?: number;
|
||||
'image'?: number | null;
|
||||
@ -158,7 +165,6 @@ export interface t_videoConfig {
|
||||
'aiConfigId'?: number | null;
|
||||
'audioEnabled'?: number | null;
|
||||
'createTime'?: number | null;
|
||||
'dialogue'?: string | null;
|
||||
'duration'?: number | null;
|
||||
'endFrame'?: string | null;
|
||||
'id'?: number;
|
||||
@ -185,11 +191,13 @@ export interface t_videoModel {
|
||||
|
||||
export interface DB {
|
||||
"t_aiModelMap": t_aiModelMap;
|
||||
"t_artStyle": t_artStyle;
|
||||
"t_assets": t_assets;
|
||||
"t_chatHistory": t_chatHistory;
|
||||
"t_config": t_config;
|
||||
"t_image": t_image;
|
||||
"t_imageModel": t_imageModel;
|
||||
"t_myTasks": t_myTasks;
|
||||
"t_novel": t_novel;
|
||||
"t_outline": t_outline;
|
||||
"t_project": t_project;
|
||||
@ -197,7 +205,6 @@ export interface DB {
|
||||
"t_script": t_script;
|
||||
"t_setting": t_setting;
|
||||
"t_storyline": t_storyline;
|
||||
"t_taskList": t_taskList;
|
||||
"t_textModel": t_textModel;
|
||||
"t_user": t_user;
|
||||
"t_video": t_video;
|
||||
|
||||
@ -12,6 +12,7 @@ import other from "./owned/other";
|
||||
import gemini from "./owned/gemini";
|
||||
import modelScope from "./owned/modelScope";
|
||||
import grsai from "./owned/grsai";
|
||||
import { tr } from "zod/locales";
|
||||
|
||||
const urlToBase64 = async (url: string): Promise<string> => {
|
||||
const res = await axios.get(url, { responseType: "arraybuffer" });
|
||||
@ -29,20 +30,31 @@ const modelInstance = {
|
||||
// apimart: apimart,
|
||||
modelScope,
|
||||
other,
|
||||
grsai
|
||||
grsai,
|
||||
} as const;
|
||||
|
||||
export default async (input: ImageConfig, config: AIConfig) => {
|
||||
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("不支持的模型");
|
||||
// }
|
||||
|
||||
//添加到任务中心
|
||||
const [taskId] = await u.db("t_myTasks").insert({
|
||||
taskClass: input.taskClass,
|
||||
relatedObjects: input.name,
|
||||
model: config?.model ? config.model : "未知模型",
|
||||
describe: input.describe ? input.describe : "无",
|
||||
state: "进行中",
|
||||
startTime: Date.now(),
|
||||
projectId: input.projectId,
|
||||
});
|
||||
// 补充图片的 base64 内容类型字符串
|
||||
if (input.imageBase64 && input.imageBase64.length > 0) {
|
||||
input.imageBase64 = input.imageBase64.map((img) => {
|
||||
@ -66,9 +78,19 @@ export default async (input: ImageConfig, config: AIConfig) => {
|
||||
return `data:image/png;base64,${img}`;
|
||||
});
|
||||
}
|
||||
|
||||
let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
||||
if (!input.resType) input.resType = "b64";
|
||||
if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl);
|
||||
return imageUrl;
|
||||
try {
|
||||
let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
||||
if (!input.resType) input.resType = "b64";
|
||||
if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl);
|
||||
await u.db("t_myTasks").where("id", taskId).update({
|
||||
state: "已完成",
|
||||
});
|
||||
return imageUrl;
|
||||
} catch (error: any) {
|
||||
await u.db("t_myTasks").where("id", taskId).update({
|
||||
state: "生成失败",
|
||||
reason: error.message,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,6 +5,10 @@ interface ImageConfig {
|
||||
size: "1K" | "2K" | "4K";
|
||||
aspectRatio: string;
|
||||
resType?: "url" | "b64";
|
||||
taskClass: string;
|
||||
name: string;
|
||||
describe: string;
|
||||
projectId: number;
|
||||
}
|
||||
|
||||
interface AIConfig {
|
||||
|
||||
@ -79,7 +79,7 @@ const ai = Object.create({}) as {
|
||||
|
||||
ai.invoke = async (input: AIInput<any>, config: AIConfig) => {
|
||||
const options = await buildOptions(input, config);
|
||||
|
||||
|
||||
const result = await generateText(options.config);
|
||||
if (options.responseFormat === "object" && input.output) {
|
||||
const pattern = /{[^{}]*}|{(?:[^{}]*|{[^{}]*})*}/g;
|
||||
|
||||
@ -21,7 +21,7 @@ const modelInstance = {
|
||||
runninghub: runninghub,
|
||||
apimart: apimart,
|
||||
other: other,
|
||||
grsai:grsai
|
||||
grsai: grsai,
|
||||
} as const;
|
||||
|
||||
export default async (input: VideoConfig, config?: AIConfig) => {
|
||||
@ -32,7 +32,16 @@ export default async (input: VideoConfig, config?: AIConfig) => {
|
||||
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的视频厂商");
|
||||
// const owned = modelList.find((m) => m.model === model);
|
||||
// if (!owned) throw new Error("不支持的模型");
|
||||
|
||||
//添加到任务中心
|
||||
const [taskId] = await u.db("t_myTasks").insert({
|
||||
taskClass: input.taskClass,
|
||||
relatedObjects: input.name,
|
||||
model: config?.model ? config.model : "未知模型",
|
||||
describe: input.describe ? input.describe : "无",
|
||||
state: "进行中",
|
||||
startTime: Date.now(),
|
||||
projectId: input.projectId,
|
||||
});
|
||||
// 补充图片的 base64 内容类型字符串
|
||||
if (input.imageBase64 && input.imageBase64.length > 0) {
|
||||
input.imageBase64 = input.imageBase64.map((img) => {
|
||||
@ -59,9 +68,20 @@ export default async (input: VideoConfig, config?: AIConfig) => {
|
||||
|
||||
let videoUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
||||
if (videoUrl) {
|
||||
const response = await axios.get(videoUrl, { responseType: "stream" });
|
||||
await u.oss.writeFile(input.savePath, response.data);
|
||||
return input.savePath;
|
||||
try {
|
||||
const response = await axios.get(videoUrl, { responseType: "stream" });
|
||||
await u.oss.writeFile(input.savePath, response.data);
|
||||
await u.db("t_myTasks").where("id", taskId).update({
|
||||
state: "已完成",
|
||||
});
|
||||
return input.savePath;
|
||||
} catch (err: any) {
|
||||
await u.db("t_myTasks").where("id", taskId).update({
|
||||
state: "生成失败",
|
||||
reason: err.message,
|
||||
});
|
||||
return videoUrl;
|
||||
}
|
||||
}
|
||||
return videoUrl;
|
||||
};
|
||||
|
||||
@ -7,6 +7,10 @@ interface VideoConfig {
|
||||
imageBase64?: string[];
|
||||
audio?: boolean;
|
||||
mode: "startEnd" | "multi" | "single" | "text";
|
||||
taskClass: string;
|
||||
name: string;
|
||||
projectId: number;
|
||||
describe?: string;
|
||||
}
|
||||
|
||||
interface AIConfig {
|
||||
|
||||
@ -88,6 +88,10 @@ export default async (images: Record<string, string>, directive: string, project
|
||||
imageBase64: base64Images,
|
||||
aspectRatio: aspectRatio ? aspectRatio : "16:9",
|
||||
size: "1K",
|
||||
taskClass: "图片编辑",
|
||||
name: `图片编辑-${uuid()}`,
|
||||
describe: `编辑指令: ${directive}`,
|
||||
projectId,
|
||||
},
|
||||
apiConfig,
|
||||
);
|
||||
|
||||
2454
tempCodeRunnerFile.javascript
Normal file
2454
tempCodeRunnerFile.javascript
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user