生成任务兼容图片类型
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# =========================
|
||||
# Dependencies
|
||||
# =========================
|
||||
#node_modules/
|
||||
.pnp/
|
||||
.pnp.js
|
||||
.pnp.cjs
|
||||
|
||||
# =========================
|
||||
# Build outputs
|
||||
# =========================
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
.next/
|
||||
.nuxt/
|
||||
.cache/
|
||||
.parcel-cache/
|
||||
.vite/
|
||||
.turbo/
|
||||
|
||||
# =========================
|
||||
# Logs
|
||||
# =========================
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# =========================
|
||||
# Runtime / cache
|
||||
# =========================
|
||||
.cache/
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
*.tsbuildinfo
|
||||
|
||||
# =========================
|
||||
# Environment files
|
||||
# =========================
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# 如果你有示例环境变量文件,可以提交
|
||||
!.env.example
|
||||
|
||||
# =========================
|
||||
# WebStorm / JetBrains IDE
|
||||
# =========================
|
||||
.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
*.ipr
|
||||
|
||||
# 如果团队需要共享 WebStorm 配置,可以改成下面这种策略:
|
||||
# .idea/*
|
||||
# !.idea/codeStyles/
|
||||
# !.idea/inspectionProfiles/
|
||||
# !.idea/runConfigurations/
|
||||
|
||||
# =========================
|
||||
# VSCode
|
||||
# =========================
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
|
||||
# =========================
|
||||
# OS files
|
||||
# =========================
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# =========================
|
||||
# Test coverage
|
||||
# =========================
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
# =========================
|
||||
# Storybook
|
||||
# =========================
|
||||
storybook-static/
|
||||
|
||||
# =========================
|
||||
# Cypress / Playwright
|
||||
# =========================
|
||||
cypress/videos/
|
||||
cypress/screenshots/
|
||||
playwright-report/
|
||||
test-results/
|
||||
|
||||
# =========================
|
||||
# Sentry / source maps
|
||||
# =========================
|
||||
*.map
|
||||
|
||||
# 如果线上需要 sourcemap,就不要忽略 *.map
|
||||
|
||||
# =========================
|
||||
# Package manager cache
|
||||
# =========================
|
||||
.npm/
|
||||
.yarn/*
|
||||
!.yarn/releases
|
||||
!.yarn/plugins
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
# =========================
|
||||
# Temporary files
|
||||
# =========================
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# =========================
|
||||
# Local certificates / keys
|
||||
# =========================
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
*.p12
|
||||
*.pfx
|
||||
|
||||
# =========================
|
||||
# Misc
|
||||
# =========================
|
||||
*.bak
|
||||
*.swp
|
||||
*.swo
|
||||
@@ -298,7 +298,7 @@ export async function adminUpdateGenerationStatus(
|
||||
}
|
||||
|
||||
export async function adminGenerateVideo(
|
||||
recordId: string, aspectRatio: string, resolution: string
|
||||
recordId: string, aspectRatio: string, resolution: string, image_size: string
|
||||
): Promise<void> {
|
||||
await api.post(`/admin/generation-records/${recordId}/generate`, { aspect_ratio: aspectRatio, resolution });
|
||||
await api.post(`/admin/generation-records/${recordId}/generate`, { aspect_ratio: aspectRatio, resolution, image_size });
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
import {
|
||||
PlayCircleOutlined, EyeOutlined, ClockCircleOutlined, CheckCircleOutlined,
|
||||
LoadingOutlined, CloseCircleOutlined, SearchOutlined, VideoCameraOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
ExclamationCircleOutlined, FileImageOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { getAdminGenerationRecords, adminUpdateGenerationStatus, adminGenerateVideo } from '../api';
|
||||
import type { AdminGenerationRecord } from '../types';
|
||||
@@ -32,7 +32,7 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
const [filterUserId, setFilterUserId] = useState<string>('');
|
||||
const [preview, setPreview] = useState<AdminGenerationRecord | null>(null);
|
||||
const [updating, setUpdating] = useState<string | null>(null);
|
||||
const [genModal, setGenModal] = useState<{ record: AdminGenerationRecord; ratio: string; resolution: string } | null>(null);
|
||||
const [genModal, setGenModal] = useState<{ record: AdminGenerationRecord; ratio: string; resolution: string; image_size: string } | null>(null);
|
||||
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
@@ -63,7 +63,12 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
videoTokensUsed: item.videoTokensUsed || 0,
|
||||
errorMessage: item.errorMessage,
|
||||
createdAt: item.createdAt,
|
||||
generatedAt: item.generatedAt,
|
||||
genType: item.genType,
|
||||
imageSize: item.imageSize,
|
||||
imageUrl: item.imageUrl,
|
||||
imageTokensUsed: item.imageTokensUsed,
|
||||
imageProportion: item.imageProportion,
|
||||
imagePx: item.imagePx,
|
||||
})));
|
||||
setTotal(res.total);
|
||||
} catch {
|
||||
@@ -92,7 +97,7 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
if (!genModal) return;
|
||||
setUpdating(genModal.record.id);
|
||||
try {
|
||||
await adminGenerateVideo(genModal.record.id, genModal.ratio, genModal.resolution);
|
||||
await adminGenerateVideo(genModal.record.id, genModal.ratio, genModal.resolution, genModal.image_size);
|
||||
message.success('已提交视频生成');
|
||||
setGenModal(null);
|
||||
load();
|
||||
@@ -117,6 +122,12 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
title: '项目', dataIndex: 'projectName', width: 120, ellipsis: true,
|
||||
render: (v: string) => <Typography.Text style={{ fontSize: 13 }}>{v}</Typography.Text>,
|
||||
},
|
||||
{
|
||||
title: '类型', dataIndex: 'genType', width: 60, ellipsis: true,
|
||||
render: (v: string) => <Typography.Text style={{ fontSize: 13 }}>
|
||||
{v==='video' ? "视频" : "图片"}
|
||||
</Typography.Text>,
|
||||
},
|
||||
{
|
||||
title: '提示词', key: 'prompt', ellipsis: true,
|
||||
render: (_: any, r: AdminGenerationRecord) => (
|
||||
@@ -130,13 +141,22 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
{
|
||||
title: '参数', key: 'params', width: 140,
|
||||
render: (_: any, r: AdminGenerationRecord) => (
|
||||
r.duration ? (
|
||||
r.genType === 'video'?
|
||||
(r.duration ? (
|
||||
<Space size={4} wrap>
|
||||
<Tag>{r.duration}s</Tag>
|
||||
<Tag>{r.aspectRatio}</Tag>
|
||||
<Tag>{r.resolution}</Tag>
|
||||
</Space>
|
||||
) : <Tag color="default">待配置</Tag>
|
||||
) : <Tag color="default">待配置</Tag>)
|
||||
:
|
||||
(r.imageSize ? (
|
||||
<Space size={4} wrap>
|
||||
<Tag>{r.imageSize}</Tag>
|
||||
<Tag>{r.imageProportion}</Tag>
|
||||
<Tag>{r.imagePx}</Tag>
|
||||
</Space>
|
||||
) : <Tag color="default">待配置</Tag>)
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -147,7 +167,7 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
<div style={{ color: '#f59e0b' }}>文字: {r.textCreditsCost}</div>
|
||||
)}
|
||||
{r.creditsCost > 0 && (
|
||||
<div style={{ color: '#6366f1' }}>视频: {r.creditsCost}</div>
|
||||
<div style={{ color: '#6366f1' }}>{r.genType === 'video'? "视频" : "图片"}: {r.creditsCost}</div>
|
||||
)}
|
||||
{r.textCreditsCost === 0 && r.creditsCost === 0 && (
|
||||
<Typography.Text style={{ color: '#94a3b8' }}>0</Typography.Text>
|
||||
@@ -193,16 +213,16 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
)}
|
||||
{r.status === 'failed' && (
|
||||
<Button size="small" type="primary" danger loading={updating === r.id}
|
||||
onClick={() => setGenModal({ record: r, ratio: r.aspectRatio || '16:9', resolution: r.resolution || '720p' })}>
|
||||
onClick={() => setGenModal({ record: r, ratio: r.aspectRatio || '16:9', resolution: r.resolution || '720p', image_size: r.imageSize })}>
|
||||
重试生成
|
||||
</Button>
|
||||
)}
|
||||
{r.status === 'prompt_optimized' && (
|
||||
<>
|
||||
<Button size="small" type="primary" loading={updating === r.id}
|
||||
onClick={() => setGenModal({ record: r, ratio: '16:9', resolution: '720p' })}
|
||||
onClick={() => setGenModal({ record: r, ratio: '16:9', resolution: '720p', image_size: r.imageSize })}
|
||||
style={{ background: '#6366f1', border: 'none' }}>
|
||||
生成视频
|
||||
生成{r.genType === 'video'? "视频" : "图片"}
|
||||
</Button>
|
||||
<Button size="small" danger loading={updating === r.id}
|
||||
onClick={() => {
|
||||
@@ -328,7 +348,7 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8' }}> ({preview.textTokensUsed} tokens)</Typography.Text>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>视频积分</Typography.Text>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>{preview.genType === 'image'? '图片' : '视频'}积分</Typography.Text>
|
||||
<Typography.Text strong style={{ fontSize: 14, color: '#6366f1' }}>{preview.creditsCost}</Typography.Text>
|
||||
{preview.videoTokensUsed > 0 && (
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8' }}> ({preview.videoTokensUsed} tokens)</Typography.Text>
|
||||
@@ -341,7 +361,8 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* Video Params */}
|
||||
{preview.duration ? (
|
||||
{preview.genType === 'video' && (
|
||||
preview.duration ? (
|
||||
<div style={{ display: 'flex', gap: 16, padding: 12, borderRadius: 10, background: '#f8f9fc' }}>
|
||||
{[
|
||||
{ label: '时长', value: `${preview.duration}秒` },
|
||||
@@ -358,6 +379,29 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
<div style={{ padding: 12, borderRadius: 10, background: '#f8f9fc', textAlign: 'center' }}>
|
||||
<Tag color="default">视频参数待用户配置</Tag>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* Image Params */}
|
||||
{preview.genType === 'image' && (
|
||||
preview.imageSize ? (
|
||||
<div style={{ display: 'flex', gap: 16, padding: 12, borderRadius: 10, background: '#f8f9fc' }}>
|
||||
{[
|
||||
{ label: '尺寸', value: preview.imagePx },
|
||||
{ label: '比例', value: preview.imageProportion },
|
||||
{ label: '分辨率', value: preview.imageSize },
|
||||
].map((item, i) => (
|
||||
<div key={i} style={{ flex: 1 }}>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>{item.label}</Typography.Text>
|
||||
<Typography.Text strong style={{ fontSize: 14 }}>{item.value}</Typography.Text>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ padding: 12, borderRadius: 10, background: '#f8f9fc', textAlign: 'center' }}>
|
||||
<Tag color="default">图片参数待用户配置</Tag>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* Reference images */}
|
||||
@@ -398,6 +442,18 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Image preview */}
|
||||
{preview.status === 'completed' && preview.imageUrl && preview.genType === 'image' && (
|
||||
<div>
|
||||
<Typography.Text style={{ fontSize: 12, color: '#94a3b8', display: 'block', marginBottom: 6 }}>生成图片</Typography.Text>
|
||||
<img
|
||||
// src={apiUrl(preview.imageUrl)}
|
||||
src={`http://ceshi.apiforeign.minzhong.cn${preview.imageUrl}`}
|
||||
style={{ width: '100%', minHeight: 100, borderRadius: 12, background: '#000' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error message */}
|
||||
{preview.status === 'failed' && preview.errorMessage && (
|
||||
<div style={{ padding: 12, borderRadius: 10, background: 'rgba(239,68,68,0.04)', border: '1px solid rgba(239,68,68,0.15)' }}>
|
||||
@@ -416,7 +472,7 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
|
||||
{/* Generate modal */}
|
||||
<Modal
|
||||
title={<Space><PlayCircleOutlined />生成视频</Space>}
|
||||
title={<Space>{genModal && (genModal.record.genType === 'video' ? <PlayCircleOutlined /> : <FileImageOutlined />)}{genModal && (genModal.record.genType === 'video' ? '生成视频' : '生成图片')}</Space>}
|
||||
open={!!genModal}
|
||||
onCancel={() => setGenModal(null)}
|
||||
onOk={handleGenerate}
|
||||
@@ -427,6 +483,8 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
>
|
||||
{genModal && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}>
|
||||
{genModal.record.genType === 'video' ?
|
||||
<>
|
||||
<div style={{ padding: 12, borderRadius: 10, background: '#f8f9fc' }}>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>时长</Typography.Text>
|
||||
<Typography.Text strong>{genModal.record.duration || 5}s</Typography.Text>
|
||||
@@ -445,6 +503,25 @@ const AdminGenerationRecords: React.FC = () => {
|
||||
options={['480p', '720p', '1080p'].map(r => ({ value: r, label: r }))}
|
||||
/>
|
||||
</div>
|
||||
</> :
|
||||
<>
|
||||
<div style={{ padding: 12, borderRadius: 10, background: '#f8f9fc' }}>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>尺寸</Typography.Text>
|
||||
<Typography.Text strong>{genModal.record.imagePx}</Typography.Text>
|
||||
</div>
|
||||
<div style={{ padding: 12, borderRadius: 10, background: '#f8f9fc' }}>
|
||||
<Typography.Text style={{ fontSize: 11, color: '#94a3b8', display: 'block' }}>比例</Typography.Text>
|
||||
<Typography.Text strong>{genModal.record.imageProportion}</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text style={{ fontSize: 12, color: '#64748b', display: 'block', marginBottom: 6 }}>分辨率</Typography.Text>
|
||||
<Select value={genModal.image_size} onChange={(v) => setGenModal(prev => prev ? { ...prev, image_size: v } : null)}
|
||||
style={{ width: '100%' }}
|
||||
options={['2K', '4K'].map(r => ({ value: r, label: r }))}
|
||||
/>
|
||||
</div>
|
||||
</> }
|
||||
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
@@ -168,4 +168,10 @@ export interface AdminGenerationRecord {
|
||||
errorMessage?: string;
|
||||
createdAt: string;
|
||||
generatedAt?: string;
|
||||
genType?: string,
|
||||
imageSize?: string,
|
||||
imageUrl?: string,
|
||||
imageTokensUsed?: number,
|
||||
imageProportion?: string,
|
||||
imagePx?: string,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user