fix
This commit is contained in:
parent
f960a7ef8d
commit
f843b2d894
|
|
@ -7,6 +7,6 @@ export type Body_local_async_change_bg_api_v2_local_batch_change_bg_post = {
|
|||
/**
|
||||
* 场景标签集合JSON字符串
|
||||
*/
|
||||
scenes_tags: string;
|
||||
scenes_list: string;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
export type VideoTaskRequest = {
|
||||
prompt: string;
|
||||
img_url: string;
|
||||
task_id: string;
|
||||
duration?: string;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const $Body_local_async_change_bg_api_v2_local_batch_change_bg_post = {
|
|||
},
|
||||
isRequired: true,
|
||||
},
|
||||
scenes_tags: {
|
||||
scenes_list: {
|
||||
type: 'string',
|
||||
description: `场景标签集合JSON字符串`,
|
||||
isRequired: true,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ export const $VideoTaskRequest = {
|
|||
type: 'string',
|
||||
isRequired: true,
|
||||
},
|
||||
task_id: {
|
||||
type: 'string',
|
||||
isRequired: true,
|
||||
},
|
||||
duration: {
|
||||
type: 'string',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -333,4 +333,15 @@ export class Service {
|
|||
url: '/api/tag/model/tag_list',
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取JM模型的提示词
|
||||
* @returns any Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static fetchJmPromptApiConfigJmPromptGet(): CancelablePromise<any> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/api/config/jm/prompt',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function openDB(): Promise<IDBDatabase> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function addVideoTasks(tasks: { id: string; img_url: string; prompt: string; create_time: string; task_id: string }[]) {
|
||||
export async function addVideoTasks(tasks: { id: string; img_url: string; prompt: string; create_time: string; job_id: string; task_id: string }[]) {
|
||||
const db = await openDB();
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const tx = db.transaction(STORE_NAME, 'readwrite');
|
||||
|
|
@ -39,7 +39,10 @@ export async function getAllVideoTasks(): Promise<any[]> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function updateVideoTask(id: string, partial: Partial<{ img_url: string; prompt: string; create_time: string; task_id: string; video_url?: string }>) {
|
||||
export async function updateVideoTask(
|
||||
id: string,
|
||||
partial: Partial<{ img_url: string; prompt: string; create_time: string; job_id: string; task_id: string; video_url?: string }>
|
||||
) {
|
||||
const db = await openDB();
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const tx = db.transaction(STORE_NAME, 'readwrite');
|
||||
|
|
|
|||
|
|
@ -9,17 +9,25 @@ import { Skeleton } from '@/components/ui/skeleton';
|
|||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { ACTION_PROMPTS } from '@/lib/prompt';
|
||||
import { Service } from '@/api/services/Service';
|
||||
import { toast } from 'sonner';
|
||||
import { addVideoTasks } from '@/lib/indexeddb';
|
||||
import type { BatchVideoTaskRequest } from '@/api';
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
||||
const promptGetter = (list: string[]) => {
|
||||
let index = 0;
|
||||
return () => {
|
||||
index++;
|
||||
return list[index % list.length];
|
||||
};
|
||||
};
|
||||
|
||||
const TryOnTasksPage: React.FC = () => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [previewImg, setPreviewImg] = useState<string | null>(null);
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState<{ id: number; img_url: string }[]>([]);
|
||||
const [selectedRows, setSelectedRows] = useState<{ id: number; img_url: string; task_id: string }[]>([]);
|
||||
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
||||
const [selectedPrompts, setSelectedPrompts] = useState<string[]>([]);
|
||||
const [creating, setCreating] = useState(false);
|
||||
|
|
@ -47,12 +55,12 @@ const TryOnTasksPage: React.FC = () => {
|
|||
const isAllCurrentPageSelected = currentPageIds.length > 0 && currentPageIds.every(id => isRowSelected(id));
|
||||
|
||||
// 单行选择
|
||||
const handleRowSelect = (item: { id: number; img_url?: string }) => {
|
||||
const handleRowSelect = (item: { id: number; img_url?: string; task_id?: string }) => {
|
||||
setSelectedRows(prev => {
|
||||
if (isRowSelected(item.id)) {
|
||||
return prev.filter(row => row.id !== item.id);
|
||||
} else {
|
||||
return [...prev, { id: item.id, img_url: item.img_url || '' }];
|
||||
return [...prev, { id: item.id, img_url: item.img_url || '', task_id: item.task_id || '' }];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -61,7 +69,9 @@ const TryOnTasksPage: React.FC = () => {
|
|||
if (isAllCurrentPageSelected) {
|
||||
setSelectedRows(prev => prev.filter(row => !currentPageIds.includes(row.id)));
|
||||
} else {
|
||||
const toAdd = (data?.data || []).filter(item => !isRowSelected(item.id)).map(item => ({ id: item.id, img_url: item.img_url || '' }));
|
||||
const toAdd = (data?.data || [])
|
||||
.filter(item => !isRowSelected(item.id))
|
||||
.map(item => ({ id: item.id, img_url: item.img_url || '', task_id: item.task_id || '' }));
|
||||
setSelectedRows(prev => [...prev, ...toAdd]);
|
||||
}
|
||||
};
|
||||
|
|
@ -70,9 +80,14 @@ const TryOnTasksPage: React.FC = () => {
|
|||
const handleCreateTask = async () => {
|
||||
if (!selectedRows.length || !selectedPrompts.length) return;
|
||||
setCreating(true);
|
||||
const getPrompt = promptGetter(selectedPrompts);
|
||||
try {
|
||||
const tasks = selectedRows.flatMap(row => selectedPrompts.map(prompt => ({ prompt, img_url: row.img_url })));
|
||||
const res = (await Service.submitVideoTaskApiJmSubmitTaskPost({ requestBody: { tasks } })) as {
|
||||
const tasks: BatchVideoTaskRequest['tasks'] = selectedRows.map(row => ({
|
||||
prompt: getPrompt(),
|
||||
img_url: row.img_url,
|
||||
task_id: row.task_id,
|
||||
}));
|
||||
const res = (await api.Service.submitVideoTaskApiJmSubmitTaskPost({ requestBody: { tasks } })) as {
|
||||
status: boolean;
|
||||
data: { success: { task_id: string; img_url: string }[]; failed: string[] };
|
||||
msg: string;
|
||||
|
|
@ -98,6 +113,7 @@ const TryOnTasksPage: React.FC = () => {
|
|||
img_url: item.img_url,
|
||||
prompt,
|
||||
create_time: new Date().toISOString(),
|
||||
job_id: item.job_id,
|
||||
task_id: item.task_id,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ interface LocalVideoTask {
|
|||
img_url: string;
|
||||
prompt: string;
|
||||
create_time: string;
|
||||
job_id: string;
|
||||
task_id: string;
|
||||
video_url?: string;
|
||||
}
|
||||
|
|
@ -51,7 +52,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
const newMap = { ...prev };
|
||||
tasks.forEach(t => {
|
||||
if (t.video_url) {
|
||||
newMap[t.task_id] = { status: 'finished', video_url: t.video_url };
|
||||
newMap[t.job_id] = { status: 'finished', video_url: t.video_url };
|
||||
}
|
||||
});
|
||||
return newMap;
|
||||
|
|
@ -59,7 +60,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
// 只查本地没有 video_url 的任务
|
||||
const job_ids = tasks
|
||||
.filter(t => !t.video_url)
|
||||
.map(t => t.task_id)
|
||||
.map(t => t.job_id)
|
||||
.filter(Boolean);
|
||||
if (!job_ids.length) return;
|
||||
setStatusLoading(true);
|
||||
|
|
@ -71,7 +72,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
(res.data.finished || []).forEach((item: any) => {
|
||||
map[item.job_id] = { status: 'finished', video_url: item.video_url };
|
||||
if (item.video_url) {
|
||||
const localTask = tasks.find(t => t.task_id === item.job_id);
|
||||
const localTask = tasks.find(t => t.job_id === item.job_id);
|
||||
if (localTask && !localTask.video_url) {
|
||||
updateVideoTask(localTask.id, { video_url: item.video_url });
|
||||
setTasks(prev => prev.map(t => (t.id === localTask.id ? { ...t, video_url: item.video_url } : t)));
|
||||
|
|
@ -91,7 +92,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
}, [tasks]);
|
||||
|
||||
const renderStatus = (task: LocalVideoTask) => {
|
||||
const s = statusMap[task.task_id];
|
||||
const s = statusMap[task.job_id];
|
||||
if (!s || !['finished', 'running', 'failed'].includes(s.status)) {
|
||||
return <span className='text-gray-400'>未知</span>;
|
||||
}
|
||||
|
|
@ -110,7 +111,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
};
|
||||
|
||||
// 计算可选的任务ID(已完成且有video_url)
|
||||
const downloadableIds = tasks.filter(t => statusMap[t.task_id]?.status === 'finished' && statusMap[t.task_id]?.video_url).map(t => t.id);
|
||||
const downloadableIds = tasks.filter(t => statusMap[t.job_id]?.status === 'finished' && statusMap[t.job_id]?.video_url).map(t => t.id);
|
||||
|
||||
const isAllSelected = downloadableIds.length > 0 && downloadableIds.every(id => selectedIds.includes(id));
|
||||
|
||||
|
|
@ -135,7 +136,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
const selectedTasks = tasks.filter(t => selectedIds.includes(t.id));
|
||||
let count = 0;
|
||||
for (const task of selectedTasks) {
|
||||
const s = statusMap[task.task_id];
|
||||
const s = statusMap[task.job_id];
|
||||
if (s?.status === 'finished' && s.video_url) {
|
||||
try {
|
||||
// 直接用 a 标签下载,避免 CORS
|
||||
|
|
@ -156,7 +157,7 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='p-6'>
|
||||
<div className='p-6 overflow-x-auto w-full'>
|
||||
<h2 className='text-xl font-bold mb-4'>视频任务进度</h2>
|
||||
<div className='mb-6 flex justify-between items-center'>
|
||||
<Button variant='outline' onClick={() => window.location.reload()}>
|
||||
|
|
@ -177,23 +178,23 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
<div className='text-gray-400 text-center mt-20'>暂无本地视频任务</div>
|
||||
) : (
|
||||
<div className='overflow-x-auto'>
|
||||
<Table className='min-w-full text-sm'>
|
||||
<Table className='text-sm'>
|
||||
<TableHeader>
|
||||
<TableRow className='bg-gray-100'>
|
||||
<TableHead className='p-2 text-center'>
|
||||
<Checkbox checked={isAllSelected} onCheckedChange={handleSelectAll} aria-label='全选' disabled={downloadableIds.length === 0} />
|
||||
</TableHead>
|
||||
<TableHead className='p-2 text-center'>图片</TableHead>
|
||||
<TableHead className='p-2'>状态</TableHead>
|
||||
<TableHead className='p-2'>ID</TableHead>
|
||||
<TableHead className='p-2'>任务ID</TableHead>
|
||||
<TableHead className='p-2'>Prompt</TableHead>
|
||||
<TableHead className='p-2'>创建时间</TableHead>
|
||||
<TableHead className='p-2'>状态</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{tasks.map(task => {
|
||||
const s = statusMap[task.task_id];
|
||||
const s = statusMap[task.job_id];
|
||||
const canDownload = s?.status === 'finished' && s.video_url;
|
||||
return (
|
||||
<TableRow key={task.id}>
|
||||
|
|
@ -220,11 +221,11 @@ const TryOnVideoTaskPage: React.FC = () => {
|
|||
<span className='text-gray-400'>无</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>{statusLoading ? '查询中...' : renderStatus(task)}</TableCell>
|
||||
<TableCell>{task.id}</TableCell>
|
||||
<TableCell>{task.task_id}</TableCell>
|
||||
<TableCell>{task.job_id}</TableCell>
|
||||
<TableCell>{task.prompt}</TableCell>
|
||||
<TableCell>{task.create_time ? new Date(task.create_time).toLocaleString() : '-'}</TableCell>
|
||||
<TableCell>{statusLoading ? '查询中...' : renderStatus(task)}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
Loading…
Reference in New Issue