完善视频提炼和视频复刻完善提交测试

This commit is contained in:
Azmat@qq.com
2026-08-28 10:15:15 +08:00
parent 52c5cdae1d
commit 849b14a0f6
33 changed files with 1475 additions and 208 deletions
+19 -3
View File
@@ -3,6 +3,7 @@ import type { ChangeEvent, CSSProperties, KeyboardEvent } from "react";
import { createPortal } from "react-dom";
import { Check, RefreshCw, Settings2, Trash2, Upload, User, UserPlus, X } from "lucide-react";
import { api } from "../api";
import { useFileDrop } from "../components/use-file-drop";
import { generationErrorText } from "../generation-error";
import type { ModelEntity } from "../types";
import { SystemLoading } from "../components/loading";
@@ -120,6 +121,11 @@ function ModelDetailModal({ model, close, onZoom, onSaved, onNotify, onBillingCh
setSaving(false);
}
}
const portraitDrop = useFileDrop(
(files) => selectPortrait(files[0]),
{ disabled: saving, accept: (f) => f.type.startsWith("image/") }
);
function selectPortrait(file?: File) {
if (!file || currentModel.is_official || saving) return;
clearPendingPortrait();
@@ -203,7 +209,8 @@ function ModelDetailModal({ model, close, onZoom, onSaved, onNotify, onBillingCh
</div>
<input ref={portraitFileRef} type="file" accept="image/*" hidden onChange={(event) => { const file = event.target.files?.[0]; event.target.value = ""; selectPortrait(file); }} />
<div
className={`placeholder model-detail-portrait${portraitUrl ? " has-mock-media" : ""}`}
className={`placeholder model-detail-portrait${portraitUrl ? " has-mock-media" : ""}${portraitDrop.dragging ? " is-dragover" : ""}`}
{...(model.is_official ? {} : portraitDrop.dropProps)}
style={portraitUrl ? mediaStyle(portraitUrl) : undefined}
role={portraitUrl ? "button" : undefined}
tabIndex={portraitUrl ? 0 : undefined}
@@ -307,9 +314,18 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
useEffect(() => { setSelected(new Set()); }, [tab]);
const modelDrop = useFileDrop(
(files) => { void acceptModelFile(files[0]); },
{ disabled: uploading, accept: (f) => f.type.startsWith("image/") }
);
async function onPick(e: ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
e.target.value = "";
await acceptModelFile(file);
}
async function acceptModelFile(file?: File | null) {
if (!file) return;
setUploading(true);
try {
@@ -357,7 +373,7 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
</button>
<button className="ml-primary" type="button" disabled={uploading} onClick={() => fileRef.current?.click()}>
<UserPlus />
<span>{uploading ? "上传中…" : "添加模特"}</span>
<span>{uploading ? "上传中…" : modelDrop.dragging ? "松开即可添加" : "添加模特"}</span>
</button>
<input ref={fileRef} type="file" accept="image/*" hidden onChange={onPick} />
</div>
@@ -388,7 +404,7 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
<span>点右上「添加模特」上传一张形象图,或在图片/视频流程里生成</span>
</div>
) : (
<div className="ml-grid">
<div className={`ml-grid${modelDrop.dragging ? " is-dragover" : ""}`} {...modelDrop.dropProps}>
{items.map((m) => {
const selectable = !m.is_official;
const isSelected = selected.has(m.id);