Filter MoneyPrinter Comfy video templates
This commit is contained in:
@@ -146,6 +146,67 @@ function templateLabel(workflow: WorkflowSummary) {
|
|||||||
return '私有工作流';
|
return '私有工作流';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function workflowTimestampLabel(workflow: WorkflowSummary) {
|
||||||
|
const value = workflow.updatedAt || workflow.createdAt;
|
||||||
|
if (!value) return '';
|
||||||
|
const date = new Date(value);
|
||||||
|
if (Number.isNaN(date.getTime())) return '';
|
||||||
|
return date.toLocaleString('zh-CN', {
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function workflowOptionLabel(workflow: WorkflowSummary) {
|
||||||
|
const name = workflow.name?.trim() || '未命名工作流';
|
||||||
|
const time = workflowTimestampLabel(workflow);
|
||||||
|
const suffix = workflow.publicId ? workflow.publicId.slice(0, 8) : String(workflow.id);
|
||||||
|
return `${name} · ${templateLabel(workflow)}${time ? ` · ${time}` : ''} · ${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function workflowLooksVideoCapable(workflow: WorkflowSummary) {
|
||||||
|
const graphText = JSON.stringify(workflow.graph || {}).toLowerCase();
|
||||||
|
return [
|
||||||
|
'video',
|
||||||
|
'wan',
|
||||||
|
'ltx',
|
||||||
|
'seedance',
|
||||||
|
'kling',
|
||||||
|
'runway',
|
||||||
|
'hailuo',
|
||||||
|
'pixverse',
|
||||||
|
'image_to_video',
|
||||||
|
'text_to_video',
|
||||||
|
'savevideo',
|
||||||
|
'video combine',
|
||||||
|
'vhs_videocombine',
|
||||||
|
'output.preview_video',
|
||||||
|
'boosapi.text_to_video',
|
||||||
|
'boosapi.image_to_video',
|
||||||
|
].some((keyword) => graphText.includes(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
|
function moneyPrinterWorkflows(items: WorkflowSummary[]) {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
return items
|
||||||
|
.filter((workflow) => workflowLooksVideoCapable(workflow))
|
||||||
|
.filter((workflow) => {
|
||||||
|
const key = workflow.publicId || String(workflow.id);
|
||||||
|
if (seen.has(key)) return false;
|
||||||
|
seen.add(key);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.sort((a, b) => {
|
||||||
|
const aTemplate = a.isTemplate || a.visibility === 'template' || a.visibility === 'public';
|
||||||
|
const bTemplate = b.isTemplate || b.visibility === 'template' || b.visibility === 'public';
|
||||||
|
if (aTemplate !== bTemplate) return aTemplate ? -1 : 1;
|
||||||
|
return String(b.updatedAt || b.createdAt || '').localeCompare(String(a.updatedAt || a.createdAt || ''));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default function MoneyPrinter() {
|
export default function MoneyPrinter() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const audience: SessionAudience = location.pathname.startsWith('/user/') ? 'user' : 'admin';
|
const audience: SessionAudience = location.pathname.startsWith('/user/') ? 'user' : 'admin';
|
||||||
@@ -178,8 +239,14 @@ export default function MoneyPrinter() {
|
|||||||
const loadWorkflows = useCallback(async () => {
|
const loadWorkflows = useCallback(async () => {
|
||||||
const payload = await client.getWorkflows({ include_public: true });
|
const payload = await client.getWorkflows({ include_public: true });
|
||||||
const items = Array.isArray(payload.items) ? payload.items : [];
|
const items = Array.isArray(payload.items) ? payload.items : [];
|
||||||
setWorkflows(items);
|
const videoItems = moneyPrinterWorkflows(items);
|
||||||
setTemplateId((current) => current || items.find((item) => item.isTemplate || item.visibility === 'template' || item.visibility === 'public')?.publicId || '');
|
setWorkflows(videoItems);
|
||||||
|
setTemplateId((current) => {
|
||||||
|
if (current && videoItems.some((item) => item.publicId === current)) return current;
|
||||||
|
return videoItems.find((item) => item.isTemplate || item.visibility === 'template' || item.visibility === 'public')?.publicId
|
||||||
|
|| videoItems[0]?.publicId
|
||||||
|
|| '';
|
||||||
|
});
|
||||||
}, [client]);
|
}, [client]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -354,7 +421,7 @@ export default function MoneyPrinter() {
|
|||||||
<div className="money-printer-section-head">
|
<div className="money-printer-section-head">
|
||||||
<div>
|
<div>
|
||||||
<h2>Comfy API 工作流</h2>
|
<h2>Comfy API 工作流</h2>
|
||||||
<p>请选择真实 Comfy/Cloud 支持的视频工作流模板。系统只注入提示词、画幅、分辨率和时长,不再提交 BoosAPI 自定义节点。</p>
|
<p>Comfy/Comfy Cloud 使用原生 /api/prompt 工作流接口,不是 OpenAI /v1 兼容接口。请选择真实视频模板,系统只注入提示词、画幅、分辨率和时长。</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label className="money-printer-field">
|
<label className="money-printer-field">
|
||||||
@@ -363,7 +430,7 @@ export default function MoneyPrinter() {
|
|||||||
<option value="">请选择模板</option>
|
<option value="">请选择模板</option>
|
||||||
{workflows.map((workflow) => (
|
{workflows.map((workflow) => (
|
||||||
<option key={workflow.publicId} value={workflow.publicId}>
|
<option key={workflow.publicId} value={workflow.publicId}>
|
||||||
{workflow.name} · {templateLabel(workflow)}
|
{workflowOptionLabel(workflow)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Reference in New Issue
Block a user