HEL-728: 四套主题与导航基础 #2
+29
-18
@@ -1,19 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>影工坊</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&family=Noto+Sans+SC:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script>
|
||||
(function () {
|
||||
var saved;
|
||||
try {
|
||||
saved = localStorage.getItem("aigc-theme");
|
||||
} catch (_) {}
|
||||
document.documentElement.dataset.theme =
|
||||
/^(night|day|grade|bluehour)$/.test(saved || "") ? saved : "night";
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/themes.css" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>影工坊</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&family=Noto+Sans+SC:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,218 +1,232 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { createQuery } from '@tanstack/svelte-query';
|
||||
import { toStore } from 'svelte/store';
|
||||
import { projects } from '$lib/api';
|
||||
import { t } from '$lib/i18n.svelte';
|
||||
import Icon from '$lib/components/ui/Icon.svelte';
|
||||
import Modal from '$lib/components/ui/Modal.svelte';
|
||||
import type { IconName } from '$lib/components/ui/icons';
|
||||
import { NAV } from './nav';
|
||||
import { goto } from "$app/navigation";
|
||||
import { createQuery } from "@tanstack/svelte-query";
|
||||
import { toStore } from "svelte/store";
|
||||
import { projects } from "$lib/api";
|
||||
import { t } from "$lib/i18n.svelte";
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import Modal from "$lib/components/ui/Modal.svelte";
|
||||
import type { IconName } from "$lib/components/ui/icons";
|
||||
import { NAV } from "./nav";
|
||||
|
||||
/** Ctrl/⌘K 搜索:跳到任一页面或项目(↑↓ 选择,Enter 打开,Esc 关闭). */
|
||||
let { open = $bindable(false) }: { open?: boolean } = $props();
|
||||
/** Ctrl/⌘K 搜索:跳到任一页面或项目(↑↓ 选择,Enter 打开,Esc 关闭). */
|
||||
let { open = $bindable(false) }: { open?: boolean } = $props();
|
||||
|
||||
interface Entry {
|
||||
key: string;
|
||||
group: 'pages' | 'projects';
|
||||
label: string;
|
||||
icon: IconName;
|
||||
href: string;
|
||||
}
|
||||
interface Entry {
|
||||
key: string;
|
||||
group: "pages" | "projects";
|
||||
label: string;
|
||||
icon: IconName;
|
||||
href: string;
|
||||
}
|
||||
|
||||
const listId = `palette-${Math.random().toString(36).slice(2, 9)}`;
|
||||
let query = $state('');
|
||||
let activeIndex = $state(0);
|
||||
let list = $state<HTMLDivElement | null>(null);
|
||||
const listId = `palette-${Math.random().toString(36).slice(2, 9)}`;
|
||||
let query = $state("");
|
||||
let activeIndex = $state(0);
|
||||
let list = $state<HTMLDivElement | null>(null);
|
||||
|
||||
const projectsQuery = createQuery(
|
||||
toStore(() => ({
|
||||
queryKey: ['projects'],
|
||||
queryFn: projects.list,
|
||||
enabled: open,
|
||||
staleTime: 30_000,
|
||||
})),
|
||||
);
|
||||
const projectsQuery = createQuery(
|
||||
toStore(() => ({
|
||||
queryKey: ["projects"],
|
||||
queryFn: projects.list,
|
||||
enabled: open,
|
||||
staleTime: 30_000,
|
||||
})),
|
||||
);
|
||||
|
||||
const entries = $derived.by<Entry[]>(() => {
|
||||
const pages: Entry[] = NAV.map((item) => ({
|
||||
key: `page-${item.id}`,
|
||||
group: 'pages',
|
||||
label: t(item.labelKey),
|
||||
icon: item.icon,
|
||||
href: item.href,
|
||||
}));
|
||||
const projectEntries: Entry[] = ($projectsQuery.data ?? []).map((p) => ({
|
||||
key: `project-${p.id}`,
|
||||
group: 'projects',
|
||||
label: p.title,
|
||||
icon: 'story',
|
||||
href: `/workbench/${p.id}`,
|
||||
}));
|
||||
const q = query.trim().toLowerCase();
|
||||
const all = [...pages, ...projectEntries];
|
||||
return q ? all.filter((e) => e.label.toLowerCase().includes(q)) : all;
|
||||
});
|
||||
const entries = $derived.by<Entry[]>(() => {
|
||||
const pages: Entry[] = NAV.map((item) => ({
|
||||
key: `page-${item.href}`,
|
||||
group: "pages",
|
||||
label: item.label,
|
||||
icon: item.icon,
|
||||
href: item.href,
|
||||
}));
|
||||
const projectEntries: Entry[] = ($projectsQuery.data ?? []).map((p) => ({
|
||||
key: `project-${p.id}`,
|
||||
group: "projects",
|
||||
label: p.title,
|
||||
icon: "story",
|
||||
href: `/workbench/${p.id}`,
|
||||
}));
|
||||
const q = query.trim().toLowerCase();
|
||||
const all = [...pages, ...projectEntries];
|
||||
return q ? all.filter((e) => e.label.toLowerCase().includes(q)) : all;
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
void query;
|
||||
activeIndex = 0;
|
||||
});
|
||||
$effect(() => {
|
||||
void query;
|
||||
activeIndex = 0;
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (!open) query = '';
|
||||
});
|
||||
$effect(() => {
|
||||
if (!open) query = "";
|
||||
});
|
||||
|
||||
function optionId(index: number) {
|
||||
return `${listId}-${index}`;
|
||||
}
|
||||
function optionId(index: number) {
|
||||
return `${listId}-${index}`;
|
||||
}
|
||||
|
||||
function go(entry: Entry) {
|
||||
open = false;
|
||||
void goto(entry.href);
|
||||
}
|
||||
function go(entry: Entry) {
|
||||
open = false;
|
||||
void goto(entry.href);
|
||||
}
|
||||
|
||||
function move(step: number) {
|
||||
if (entries.length === 0) return;
|
||||
activeIndex = (activeIndex + step + entries.length) % entries.length;
|
||||
list?.querySelector(`#${optionId(activeIndex)}`)?.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
function move(step: number) {
|
||||
if (entries.length === 0) return;
|
||||
activeIndex = (activeIndex + step + entries.length) % entries.length;
|
||||
list
|
||||
?.querySelector(`#${optionId(activeIndex)}`)
|
||||
?.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
move(1);
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
move(-1);
|
||||
} else if (event.key === 'Enter') {
|
||||
const entry = entries[activeIndex];
|
||||
if (entry) {
|
||||
event.preventDefault();
|
||||
go(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "ArrowDown") {
|
||||
event.preventDefault();
|
||||
move(1);
|
||||
} else if (event.key === "ArrowUp") {
|
||||
event.preventDefault();
|
||||
move(-1);
|
||||
} else if (event.key === "Enter") {
|
||||
const entry = entries[activeIndex];
|
||||
if (entry) {
|
||||
event.preventDefault();
|
||||
go(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function focusOnMount(node: HTMLInputElement) {
|
||||
requestAnimationFrame(() => node.focus());
|
||||
}
|
||||
function focusOnMount(node: HTMLInputElement) {
|
||||
requestAnimationFrame(() => node.focus());
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:open title={t('shell.searchTitle')}>
|
||||
<div class="palette">
|
||||
<div class="palette-search">
|
||||
<Icon name="search" size={16} />
|
||||
<input
|
||||
use:focusOnMount
|
||||
class="palette-input"
|
||||
type="text"
|
||||
bind:value={query}
|
||||
placeholder={t('shell.searchPlaceholder')}
|
||||
role="combobox"
|
||||
aria-expanded="true"
|
||||
aria-controls={listId}
|
||||
aria-autocomplete="list"
|
||||
aria-activedescendant={entries.length ? optionId(activeIndex) : undefined}
|
||||
aria-label={t('shell.searchTitle')}
|
||||
onkeydown={handleKeydown}
|
||||
/>
|
||||
</div>
|
||||
<div class="palette-list" id={listId} role="listbox" bind:this={list} aria-label={t('shell.searchTitle')}>
|
||||
{#if entries.length === 0}
|
||||
<p class="palette-empty">{t('shell.searchEmpty', { q: query.trim() })}</p>
|
||||
{/if}
|
||||
{#each entries as entry, i (entry.key)}
|
||||
{#if i === 0 || entries[i - 1].group !== entry.group}
|
||||
<div class="a-menu-group" role="presentation">
|
||||
{entry.group === 'pages' ? t('shell.searchGroupPages') : t('shell.searchGroupProjects')}
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
id={optionId(i)}
|
||||
class="a-menu-item"
|
||||
class:active={i === activeIndex}
|
||||
role="option"
|
||||
tabindex="-1"
|
||||
aria-selected={i === activeIndex}
|
||||
onpointermove={() => (activeIndex = i)}
|
||||
onmousedown={(e) => e.preventDefault()}
|
||||
onclick={() => go(entry)}
|
||||
onkeydown={handleKeydown}
|
||||
>
|
||||
<Icon name={entry.icon} size={15} />
|
||||
<span class="a-menu-label">{entry.label}</span>
|
||||
<span class="a-menu-meta mono">{entry.href}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<p class="palette-hint">
|
||||
<span class="a-kbd">↑↓</span>{t('shell.searchHintMove')}
|
||||
<span class="a-kbd">Enter</span>{t('shell.searchHintOpen')}
|
||||
<span class="a-kbd">Esc</span>{t('shell.searchHintClose')}
|
||||
</p>
|
||||
</div>
|
||||
<Modal bind:open title={t("shell.searchTitle")}>
|
||||
<div class="palette">
|
||||
<div class="palette-search">
|
||||
<Icon name="search" size={16} />
|
||||
<input
|
||||
use:focusOnMount
|
||||
class="palette-input"
|
||||
type="text"
|
||||
bind:value={query}
|
||||
placeholder={t("shell.searchPlaceholder")}
|
||||
role="combobox"
|
||||
aria-expanded="true"
|
||||
aria-controls={listId}
|
||||
aria-autocomplete="list"
|
||||
aria-activedescendant={entries.length
|
||||
? optionId(activeIndex)
|
||||
: undefined}
|
||||
aria-label={t("shell.searchTitle")}
|
||||
onkeydown={handleKeydown}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="palette-list"
|
||||
id={listId}
|
||||
role="listbox"
|
||||
bind:this={list}
|
||||
aria-label={t("shell.searchTitle")}
|
||||
>
|
||||
{#if entries.length === 0}
|
||||
<p class="palette-empty">
|
||||
{t("shell.searchEmpty", { q: query.trim() })}
|
||||
</p>
|
||||
{/if}
|
||||
{#each entries as entry, i (entry.key)}
|
||||
{#if i === 0 || entries[i - 1].group !== entry.group}
|
||||
<div class="a-menu-group" role="presentation">
|
||||
{entry.group === "pages"
|
||||
? t("shell.searchGroupPages")
|
||||
: t("shell.searchGroupProjects")}
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
id={optionId(i)}
|
||||
class="a-menu-item"
|
||||
class:active={i === activeIndex}
|
||||
role="option"
|
||||
tabindex="-1"
|
||||
aria-selected={i === activeIndex}
|
||||
onpointermove={() => (activeIndex = i)}
|
||||
onmousedown={(e) => e.preventDefault()}
|
||||
onclick={() => go(entry)}
|
||||
onkeydown={handleKeydown}
|
||||
>
|
||||
<Icon name={entry.icon} size={15} />
|
||||
<span class="a-menu-label">{entry.label}</span>
|
||||
<span class="a-menu-meta mono">{entry.href}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<p class="palette-hint">
|
||||
<span class="a-kbd">↑↓</span>{t("shell.searchHintMove")}
|
||||
<span class="a-kbd">Enter</span>{t("shell.searchHintOpen")}
|
||||
<span class="a-kbd">Esc</span>{t("shell.searchHintClose")}
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.palette {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-3);
|
||||
}
|
||||
.palette-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-3);
|
||||
padding: 0 var(--sp-5);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r-md);
|
||||
background: var(--bg-3);
|
||||
color: var(--text-3);
|
||||
transition: border-color var(--d-state) ease;
|
||||
}
|
||||
.palette-search:focus-within {
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.palette-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-family: inherit;
|
||||
font-size: var(--fs-section);
|
||||
}
|
||||
.palette-input::placeholder {
|
||||
color: var(--text-3);
|
||||
}
|
||||
.palette-list {
|
||||
max-height: min(360px, 50vh);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.palette-empty {
|
||||
margin: 0;
|
||||
padding: var(--sp-6) var(--sp-4);
|
||||
font-size: var(--fs-aux);
|
||||
color: var(--text-3);
|
||||
text-align: center;
|
||||
}
|
||||
.palette-hint {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
margin: 0;
|
||||
font-size: var(--fs-mini);
|
||||
color: var(--text-3);
|
||||
}
|
||||
.palette-hint .a-kbd:not(:first-child) {
|
||||
margin-left: var(--sp-3);
|
||||
}
|
||||
@media (hover: none) {
|
||||
.palette-hint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.palette {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-3);
|
||||
}
|
||||
.palette-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-3);
|
||||
padding: 0 var(--sp-5);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r-md);
|
||||
background: var(--bg-3);
|
||||
color: var(--text-3);
|
||||
transition: border-color var(--d-state) ease;
|
||||
}
|
||||
.palette-search:focus-within {
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.palette-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-family: inherit;
|
||||
font-size: var(--fs-section);
|
||||
}
|
||||
.palette-input::placeholder {
|
||||
color: var(--text-3);
|
||||
}
|
||||
.palette-list {
|
||||
max-height: min(360px, 50vh);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.palette-empty {
|
||||
margin: 0;
|
||||
padding: var(--sp-6) var(--sp-4);
|
||||
font-size: var(--fs-aux);
|
||||
color: var(--text-3);
|
||||
text-align: center;
|
||||
}
|
||||
.palette-hint {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
margin: 0;
|
||||
font-size: var(--fs-mini);
|
||||
color: var(--text-3);
|
||||
}
|
||||
.palette-hint .a-kbd:not(:first-child) {
|
||||
margin-left: var(--sp-3);
|
||||
}
|
||||
@media (hover: none) {
|
||||
.palette-hint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
<script lang="ts">
|
||||
import { THEMES, theme, setTheme, themeStorageUnavailable } from "$lib/theme";
|
||||
let { compact = false }: { compact?: boolean } = $props();
|
||||
function move(event: KeyboardEvent) {
|
||||
const steps: Record<string, number> = {
|
||||
ArrowRight: 1,
|
||||
ArrowDown: 1,
|
||||
ArrowLeft: -1,
|
||||
ArrowUp: -1,
|
||||
};
|
||||
const step = steps[event.key];
|
||||
if (!step && event.key !== "Home" && event.key !== "End") return;
|
||||
event.preventDefault();
|
||||
const group = (event.currentTarget as HTMLElement).closest(
|
||||
".choices",
|
||||
) as HTMLElement;
|
||||
const buttons = [...group.querySelectorAll<HTMLButtonElement>("button")];
|
||||
const current = buttons.indexOf(
|
||||
document.activeElement as HTMLButtonElement,
|
||||
);
|
||||
const next =
|
||||
event.key === "Home"
|
||||
? 0
|
||||
: event.key === "End"
|
||||
? buttons.length - 1
|
||||
: (current + step + buttons.length) % buttons.length;
|
||||
buttons[next]?.focus();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="choices" class:compact role="group" aria-label="外观主题">
|
||||
{#each THEMES as item}
|
||||
<button
|
||||
class="choice"
|
||||
class:selected={$theme === item.id}
|
||||
aria-pressed={$theme === item.id}
|
||||
onkeydown={move}
|
||||
onclick={() => setTheme(item.id)}
|
||||
>
|
||||
<span class="preview" data-theme={item.id} aria-hidden="true"
|
||||
><span class="rail"></span><span class="list"
|
||||
><i></i><i></i><i></i></span
|
||||
><span class="stage"><i></i><b></b></span></span
|
||||
>
|
||||
<span class="copy"
|
||||
><strong>{item.name}</strong><small>{item.english}</small><span
|
||||
>{item.description}</span
|
||||
></span
|
||||
>
|
||||
<span class="check" aria-hidden="true"
|
||||
>{$theme === item.id ? "✓" : ""}</span
|
||||
>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $themeStorageUnavailable}<p class="notice" role="status">
|
||||
浏览器禁止本地存储:本次有效,其他操作不受影响
|
||||
</p>{/if}
|
||||
|
||||
<style>
|
||||
.choices {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
.choices.compact {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.choice {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 18px;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--line-2);
|
||||
border-radius: var(--r-md);
|
||||
background: var(--bg-2);
|
||||
color: var(--tx-1);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
.choice:hover {
|
||||
border-color: var(--line-3);
|
||||
background: var(--bg-3);
|
||||
}
|
||||
.choice.selected {
|
||||
border-color: var(--gold);
|
||||
}
|
||||
.choice:focus-visible {
|
||||
outline: 2px solid var(--info);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.compact .choice {
|
||||
grid-template-columns: 76px minmax(0, 1fr) 18px;
|
||||
align-items: center;
|
||||
}
|
||||
.preview {
|
||||
grid-column: 1 / -1;
|
||||
height: 64px;
|
||||
border-radius: var(--r-sm);
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: 12px 22px 1fr;
|
||||
background: var(--bg-0);
|
||||
border: 1px solid var(--line-2);
|
||||
}
|
||||
.compact .preview {
|
||||
grid-column: auto;
|
||||
height: 48px;
|
||||
}
|
||||
.rail,
|
||||
.list {
|
||||
background: var(--bg-1);
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
.rail::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
margin: 6px auto;
|
||||
border-radius: 50%;
|
||||
background: var(--gold);
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
padding: 6px 3px;
|
||||
}
|
||||
.list i {
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: var(--line-3);
|
||||
}
|
||||
.list i:first-child {
|
||||
background: var(--sc-image);
|
||||
}
|
||||
.stage {
|
||||
padding: 5px 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.stage i {
|
||||
flex: 1;
|
||||
border-radius: 3px;
|
||||
background: var(--bg-3);
|
||||
border: 1px solid var(--line-2);
|
||||
}
|
||||
.stage b {
|
||||
height: 9px;
|
||||
width: 18px;
|
||||
align-self: end;
|
||||
border-radius: 2px;
|
||||
background: var(--grad-gold);
|
||||
}
|
||||
.copy {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2px 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
.copy strong {
|
||||
font-size: 13px;
|
||||
}
|
||||
.copy small {
|
||||
font: 10px var(--mono);
|
||||
color: var(--tx-3);
|
||||
align-self: center;
|
||||
}
|
||||
.copy > span {
|
||||
width: 100%;
|
||||
font-size: 11px;
|
||||
color: var(--tx-2);
|
||||
}
|
||||
.check {
|
||||
color: var(--gold);
|
||||
}
|
||||
.notice {
|
||||
font-size: 12px;
|
||||
color: var(--tx-2);
|
||||
margin: 12px 0 0;
|
||||
}
|
||||
@media (max-width: 1366px) {
|
||||
.choices:not(.compact) {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,123 +1,130 @@
|
||||
import type { IconName } from '$lib/components/ui/icons';
|
||||
import type { IconName } from "$lib/components/ui/icons";
|
||||
|
||||
// IDs are retained for the existing page contracts while B1–B4 replace layouts.
|
||||
export type NavId =
|
||||
| 'projects'
|
||||
| 'workbench'
|
||||
| 'image'
|
||||
| 'video'
|
||||
| 'tasks'
|
||||
| 'agents'
|
||||
| 'connections'
|
||||
| 'models'
|
||||
| 'library'
|
||||
| 'settings'
|
||||
| 'canvas'
|
||||
| 'workflows';
|
||||
|
||||
| "projects"
|
||||
| "workbench"
|
||||
| "image"
|
||||
| "video"
|
||||
| "tasks"
|
||||
| "agents"
|
||||
| "connections"
|
||||
| "models"
|
||||
| "library"
|
||||
| "settings"
|
||||
| "canvas"
|
||||
| "workflows";
|
||||
export interface NavItem {
|
||||
id: NavId;
|
||||
labelKey: string;
|
||||
icon: IconName;
|
||||
href: string;
|
||||
id: NavId;
|
||||
label: string;
|
||||
icon: IconName;
|
||||
href: string;
|
||||
scene: "project" | "image" | "agent" | "manage" | "asset";
|
||||
matches: (path: string) => boolean;
|
||||
}
|
||||
|
||||
// Order is fixed by spec-v2 §3: 项目 / 创作工作台 / 生图 / 生视频 / 生成任务 /
|
||||
// 智能体 / ComfyUI 连接 / 模型设置 / 设置. HEL-649 §二 puts the connection
|
||||
// and settings entries at the foot of the 60px rail.
|
||||
export const NAV_MAIN: NavItem[] = [
|
||||
{ id: 'projects', labelKey: 'shell.navProjects', icon: 'home', href: '/' },
|
||||
{
|
||||
id: 'workbench',
|
||||
labelKey: 'shell.navWorkbench',
|
||||
icon: 'story',
|
||||
href: '/workbench',
|
||||
},
|
||||
{ id: 'image', labelKey: 'shell.navImage', icon: 'image', href: '/image' },
|
||||
{ id: 'video', labelKey: 'shell.navVideo', icon: 'film', href: '/video' },
|
||||
{ id: 'tasks', labelKey: 'shell.navTasks', icon: 'queue', href: '/tasks' },
|
||||
{ id: 'canvas', labelKey: 'nav.canvas', icon: 'story', href: '/canvas' },
|
||||
{
|
||||
id: 'agents',
|
||||
labelKey: 'shell.navAgents',
|
||||
icon: 'sparkle',
|
||||
href: '/agents',
|
||||
},
|
||||
{
|
||||
id: "projects",
|
||||
label: "工作室",
|
||||
icon: "home",
|
||||
href: "/",
|
||||
scene: "project",
|
||||
matches: (p) => p === "/",
|
||||
},
|
||||
{
|
||||
id: "workbench",
|
||||
label: "项目",
|
||||
icon: "folder",
|
||||
href: "/workbench",
|
||||
scene: "project",
|
||||
matches: (p) => /^\/(workbench|project)(\/|$)/.test(p),
|
||||
},
|
||||
{
|
||||
id: "image",
|
||||
label: "创作台",
|
||||
icon: "image",
|
||||
href: "/create",
|
||||
scene: "image",
|
||||
matches: (p) =>
|
||||
["/create", "/image", "/video", "/playground", "/build-scene"].includes(
|
||||
p,
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "agents",
|
||||
label: "智能体",
|
||||
icon: "sparkle",
|
||||
href: "/agents",
|
||||
scene: "agent",
|
||||
matches: (p) => p === "/agents",
|
||||
},
|
||||
{
|
||||
id: "canvas",
|
||||
label: "画布",
|
||||
icon: "story",
|
||||
href: "/canvas",
|
||||
scene: "manage",
|
||||
matches: (p) => p.startsWith("/canvas"),
|
||||
},
|
||||
{
|
||||
id: "library",
|
||||
label: "素材库",
|
||||
icon: "assets",
|
||||
href: "/library",
|
||||
scene: "asset",
|
||||
matches: (p) => p === "/library",
|
||||
},
|
||||
];
|
||||
export const NAV_MANAGE: NavItem[] = [
|
||||
{
|
||||
id: "tasks",
|
||||
label: "任务",
|
||||
icon: "clock",
|
||||
href: "/tasks",
|
||||
scene: "manage",
|
||||
matches: (p) => p === "/tasks",
|
||||
},
|
||||
{
|
||||
id: "workflows",
|
||||
label: "工作流",
|
||||
icon: "playground",
|
||||
href: "/workflows",
|
||||
scene: "manage",
|
||||
matches: (p) => p === "/workflows",
|
||||
},
|
||||
{
|
||||
id: "connections",
|
||||
label: "模型连接",
|
||||
icon: "link",
|
||||
href: "/model-connections",
|
||||
scene: "manage",
|
||||
matches: (p) =>
|
||||
["/connections", "/models", "/model-connections"].includes(p),
|
||||
},
|
||||
];
|
||||
|
||||
export const NAV_FOOT: NavItem[] = [
|
||||
{
|
||||
id: 'connections',
|
||||
labelKey: 'shell.navConnections',
|
||||
icon: 'link',
|
||||
href: '/connections',
|
||||
},
|
||||
{
|
||||
id: 'models',
|
||||
labelKey: 'shell.navModels',
|
||||
icon: 'assets',
|
||||
href: '/models',
|
||||
},
|
||||
{
|
||||
id: 'workflows',
|
||||
labelKey: 'connections.wfTitle',
|
||||
icon: 'playground',
|
||||
href: '/workflows',
|
||||
},
|
||||
{
|
||||
id: 'library',
|
||||
labelKey: 'shell.navLibrary',
|
||||
icon: 'folder',
|
||||
href: '/library',
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
labelKey: 'shell.navSettings',
|
||||
icon: 'settings',
|
||||
href: '/settings',
|
||||
},
|
||||
{
|
||||
id: "settings",
|
||||
label: "设置",
|
||||
icon: "settings",
|
||||
href: "/settings",
|
||||
scene: "manage",
|
||||
matches: (p) => p === "/settings",
|
||||
},
|
||||
];
|
||||
|
||||
export const NAV: NavItem[] = [...NAV_MAIN, ...NAV_FOOT];
|
||||
|
||||
export interface TabItem {
|
||||
id: 'projects' | 'workbench' | 'generate';
|
||||
labelKey: string;
|
||||
icon: IconName;
|
||||
href: string;
|
||||
/** Pages that light this tab up. */
|
||||
covers: NavId[];
|
||||
}
|
||||
|
||||
/** ≤760px bottom tab bar (§二): 项目 / 创作 / 生成 / 更多. */
|
||||
export const TABS: TabItem[] = [
|
||||
{
|
||||
id: 'projects',
|
||||
labelKey: 'shell.tabProjects',
|
||||
icon: 'home',
|
||||
href: '/',
|
||||
covers: ['projects'],
|
||||
},
|
||||
{
|
||||
id: 'workbench',
|
||||
labelKey: 'shell.tabCreate',
|
||||
icon: 'story',
|
||||
href: '/workbench',
|
||||
covers: ['workbench'],
|
||||
},
|
||||
{
|
||||
id: 'generate',
|
||||
labelKey: 'shell.tabGenerate',
|
||||
icon: 'image',
|
||||
href: '/image',
|
||||
covers: ['image', 'video'],
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Every page a tab does not link to directly lives in the 更多 sheet. 生视频
|
||||
* is still its own route, so it is listed there too until the two
|
||||
* generation pages merge.
|
||||
*/
|
||||
export const MORE_ITEMS: NavItem[] = NAV.filter(
|
||||
(item) => !TABS.some((tab) => tab.href === item.href),
|
||||
);
|
||||
// Tools awaiting their replacement keep reachable entries in global search.
|
||||
export const NAV = [
|
||||
...NAV_MAIN,
|
||||
...NAV_MANAGE,
|
||||
...NAV_FOOT,
|
||||
{ id: "video", label: "视频创作", icon: "film", href: "/video" },
|
||||
{ id: "models", label: "大语言模型", icon: "assets", href: "/models" },
|
||||
{
|
||||
id: "connections",
|
||||
label: "ComfyUI 连接",
|
||||
icon: "link",
|
||||
href: "/connections",
|
||||
},
|
||||
{ id: "image", label: "试验台", icon: "playground", href: "/playground" },
|
||||
{ id: "video", label: "三维搭景", icon: "story", href: "/build-scene" },
|
||||
] as const;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
/** Approved HEL-726 themes. Colours live only in static/themes.css. */
|
||||
export const THEMES = [
|
||||
{
|
||||
id: "night",
|
||||
name: "夜片场",
|
||||
english: "Nocturne",
|
||||
description: "墨黑与钨丝金 · 沉浸式创作",
|
||||
},
|
||||
{
|
||||
id: "day",
|
||||
name: "日光棚",
|
||||
english: "Daylight",
|
||||
description: "暖白纸面 · 白天办公与长时间审稿",
|
||||
},
|
||||
{
|
||||
id: "grade",
|
||||
name: "调色间",
|
||||
english: "Grading",
|
||||
description: "中性深灰 · 判断作品色彩",
|
||||
},
|
||||
{
|
||||
id: "bluehour",
|
||||
name: "蓝调时刻",
|
||||
english: "Blue Hour",
|
||||
description: "靛蓝与珊瑚 · 提案与灵感发散",
|
||||
},
|
||||
] as const;
|
||||
export type ThemeId = (typeof THEMES)[number]["id"];
|
||||
export const THEME_KEY = "aigc-theme";
|
||||
export const theme = writable<ThemeId>("night");
|
||||
export const themeStorageUnavailable = writable(false);
|
||||
|
||||
export function isTheme(value: unknown): value is ThemeId {
|
||||
return THEMES.some((item) => item.id === value);
|
||||
}
|
||||
|
||||
export function setTheme(id: ThemeId) {
|
||||
if (typeof document === "undefined" || !isTheme(id)) return;
|
||||
// Only the root attribute changes: editors, uploads and jobs stay mounted.
|
||||
document.documentElement.dataset.theme = id;
|
||||
theme.set(id);
|
||||
try {
|
||||
localStorage.setItem(THEME_KEY, id);
|
||||
themeStorageUnavailable.set(false);
|
||||
} catch {
|
||||
themeStorageUnavailable.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
export function initTheme() {
|
||||
const current = document.documentElement.dataset.theme;
|
||||
theme.set(isTheme(current) ? current : "night");
|
||||
try {
|
||||
localStorage.getItem(THEME_KEY);
|
||||
} catch {
|
||||
themeStorageUnavailable.set(true);
|
||||
}
|
||||
const sync = (event: StorageEvent) => {
|
||||
if (event.key !== THEME_KEY && event.key !== null) return;
|
||||
const id = isTheme(event.newValue) ? event.newValue : "night";
|
||||
document.documentElement.dataset.theme = id;
|
||||
theme.set(id);
|
||||
};
|
||||
window.addEventListener("storage", sync);
|
||||
return () => window.removeEventListener("storage", sync);
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
<script lang="ts">
|
||||
import './app.css';
|
||||
import { onMount } from 'svelte';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
|
||||
import ToastHost from '$lib/components/ToastHost.svelte';
|
||||
import { initReduceMotion } from '$lib/reduceMotion.svelte';
|
||||
import "./app.css";
|
||||
import { initTheme } from "$lib/theme";
|
||||
import { onMount } from "svelte";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/svelte-query";
|
||||
import ToastHost from "$lib/components/ToastHost.svelte";
|
||||
import { initReduceMotion } from "$lib/reduceMotion.svelte";
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { refetchOnWindowFocus: false, retry: 1 },
|
||||
},
|
||||
});
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { refetchOnWindowFocus: false, retry: 1 },
|
||||
},
|
||||
});
|
||||
|
||||
onMount(() => initReduceMotion());
|
||||
onMount(() => initReduceMotion());
|
||||
onMount(initTheme);
|
||||
</script>
|
||||
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<slot />
|
||||
<ToastHost />
|
||||
<slot />
|
||||
<ToastHost />
|
||||
</QueryClientProvider>
|
||||
|
||||
+667
-811
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
// B0 compatibility gateway: existing working editors remain the destination
|
||||
// until the unified editor is delivered in B1. Preserve all source context.
|
||||
export function load({ url }: { url: URL }) {
|
||||
const kind = url.searchParams.get("kind") === "video" ? "video" : "image";
|
||||
redirect(307, `/${kind}${url.search}${new URL(url.href).hash}`);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
// Both existing management pages stay usable until B2 combines their tabs.
|
||||
export function load({ url }: { url: URL }) {
|
||||
const destination =
|
||||
url.searchParams.get("tab") === "llm" ? "/models" : "/connections";
|
||||
redirect(307, destination + url.search + new URL(url.href).hash);
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageLoad } from './$types';
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const prerender = false;
|
||||
export const ssr = false;
|
||||
|
||||
export const load: PageLoad = ({ params }) => {
|
||||
redirect(308, `/workbench/${params.id}`);
|
||||
export const load: PageLoad = ({ params, url }) => {
|
||||
redirect(
|
||||
308,
|
||||
`/workbench/${params.id}${url.search}${new URL(url.href).hash}`,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
|
||||
export function load() {
|
||||
redirect(308, '/');
|
||||
export function load({ url }: { url: URL }) {
|
||||
redirect(308, "/" + url.search + new URL(url.href).hash);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,547 @@
|
||||
/* HEL-726 approved themes. Loaded before the app for first-paint safety. */
|
||||
:root,
|
||||
[data-theme="night"] {
|
||||
color-scheme: dark;
|
||||
/* surfaces: ink black with a faint blue cast, never pure #000 */
|
||||
--bg-0: #07080c;
|
||||
--bg-1: #0c0e14;
|
||||
--bg-2: #12151d;
|
||||
--bg-3: #1a1e29;
|
||||
--bg-4: #232838;
|
||||
--line: rgb(var(--ink) / 0.06);
|
||||
--line-2: rgb(var(--ink) / 0.11);
|
||||
--line-3: rgb(var(--ink) / 0.18);
|
||||
/* text: warm paper white */
|
||||
--tx-1: #f3efe6;
|
||||
--tx-2: #aaa79e;
|
||||
--tx-3: #6f6d68;
|
||||
--tx-inv: #1a1206;
|
||||
/* key light: tungsten gold */
|
||||
--gold: #e9b04b;
|
||||
--gold-hi: #f8d68c;
|
||||
--gold-lo: #b8771f;
|
||||
--grad-gold: linear-gradient(135deg, #fbe1a1 0%, #efb54f 45%, #d98a26 100%);
|
||||
/* scene lights — each workspace has its own colour temperature */
|
||||
--sc-image: #3fd8c6;
|
||||
--sc-video: #ff8a3d;
|
||||
--sc-agent: #a879ff;
|
||||
--sc-project: #e9b04b;
|
||||
--sc-manage: #7f93b5;
|
||||
--scene: var(--gold);
|
||||
/* status */
|
||||
--ok: #43d39a;
|
||||
--warn: #f2b33d;
|
||||
--err: #ff5d6c;
|
||||
--info: #5aa9ff;
|
||||
/* type */
|
||||
--font:
|
||||
"PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei UI", "Microsoft YaHei",
|
||||
system-ui, sans-serif;
|
||||
--mono: "JetBrains Mono", "Cascadia Mono", Consolas, monospace;
|
||||
--fs-display: 28px;
|
||||
--fs-h1: 20px;
|
||||
--fs-h2: 16px;
|
||||
--fs-body: 13px;
|
||||
--fs-small: 12px;
|
||||
--fs-micro: 11px;
|
||||
/* space (4 base) */
|
||||
--s1: 4px;
|
||||
--s2: 8px;
|
||||
--s3: 12px;
|
||||
--s4: 16px;
|
||||
--s5: 20px;
|
||||
--s6: 24px;
|
||||
--s8: 32px;
|
||||
/* radius */
|
||||
--r-xs: 4px;
|
||||
--r-sm: 6px;
|
||||
--r-md: 10px;
|
||||
--r-lg: 14px;
|
||||
--r-xl: 20px;
|
||||
--r-pill: 999px;
|
||||
/* elevation */
|
||||
--sh-1: 0 1px 0 rgb(var(--ink) / 0.04) inset, 0 2px 8px rgba(0, 0, 0, 0.35);
|
||||
--sh-2: 0 1px 0 rgb(var(--ink) / 0.05) inset, 0 12px 32px rgba(0, 0, 0, 0.5);
|
||||
--sh-gold:
|
||||
0 6px 22px rgba(233, 160, 60, 0.35),
|
||||
0 0 0 1px rgba(255, 220, 150, 0.35) inset;
|
||||
/* motion */
|
||||
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
--ease-io: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
--t-fast: 120ms;
|
||||
--t-base: 200ms;
|
||||
--t-slow: 320ms;
|
||||
--t-reveal: 700ms;
|
||||
/* layout */
|
||||
--rail: 68px;
|
||||
--list: 272px;
|
||||
--hist: 92px;
|
||||
--head: 48px;
|
||||
/* ---- theme-semantic tokens (v2 · 主题化) ---- */
|
||||
--ink: 255 255 255; /* overlay channel: hover tint, hairlines (white in dark, ink in light) */
|
||||
--hi: white; /* scene-coloured text is mixed toward this for contrast */
|
||||
--on-scene: #140a03; /* text on a solid scene/status colour */
|
||||
--on-ok: #06140e;
|
||||
--sc-asset: #ff86b0; /* 素材资产 helper colour (agent roster) */
|
||||
--glass: color-mix(in srgb, var(--bg-1) 70%, transparent);
|
||||
--scrim: rgba(4, 5, 8, 0.6);
|
||||
--well: var(--bg-0); /* inputs, segmented track */
|
||||
--media-shadow:
|
||||
0 30px 80px rgba(0, 0, 0, 0.6), 0 0 0 1px rgb(255 255 255 / 0.07);
|
||||
--sh-gold-hover:
|
||||
0 8px 28px rgba(233, 160, 60, 0.5), 0 0 0 1px rgba(255, 230, 170, 0.5) inset;
|
||||
--brand-grad: radial-gradient(
|
||||
circle at 30% 25%,
|
||||
#fff3cf 0,
|
||||
#efb54f 35%,
|
||||
#9b5a12 100%
|
||||
);
|
||||
--brand-glow: 0 0 24px rgba(233, 176, 75, 0.35);
|
||||
--brand-ink: #1b1206;
|
||||
--display-grad: linear-gradient(
|
||||
90deg,
|
||||
var(--gold-hi),
|
||||
var(--gold) 60%,
|
||||
#ff9b5a
|
||||
);
|
||||
--glow: 1; /* 1 = glows on (dark themes), 0 = off (light / neutral) */
|
||||
/* signature effects */
|
||||
--gen-bg: #0b0d12;
|
||||
--grain: rgba(255, 255, 255, 0.08);
|
||||
--beam: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
color-mix(in srgb, var(--scene) 30%, transparent),
|
||||
rgba(255, 255, 255, 0.25),
|
||||
transparent
|
||||
);
|
||||
--lattice: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='24' viewBox='0 0 14 24'%3E%3Cpath d='M7 0l7 4v8l-7 4-7-4V4zM7 16v8' fill='none' stroke='white' stroke-opacity='.16' stroke-width='.8'/%3E%3C/svg%3E");
|
||||
--scanline: rgb(var(--ink) / 0.012);
|
||||
--stage-tint: 7%;
|
||||
/* agent atmosphere */
|
||||
--aur-1: #7c4dff;
|
||||
--aur-2: #ff5fa8;
|
||||
--aur-3: #2fd5c5;
|
||||
--aur-op: 0.33;
|
||||
--agent-hero: linear-gradient(
|
||||
120deg,
|
||||
rgba(32, 20, 58, 0.9),
|
||||
rgba(14, 12, 26, 0.92) 55%,
|
||||
rgba(10, 22, 30, 0.9)
|
||||
);
|
||||
--agent-title: linear-gradient(90deg, #fff, #d9c6ff 50%, #ffb3d9);
|
||||
--orb-core: radial-gradient(
|
||||
circle at 35% 30%,
|
||||
#fff 0,
|
||||
#e3d4ff 12%,
|
||||
#a879ff 40%,
|
||||
#4b1fa8 75%,
|
||||
transparent 76%
|
||||
);
|
||||
--particle: 214, 190, 255;
|
||||
--fail-a: #1a1215;
|
||||
--fail-b: #140f12;
|
||||
}
|
||||
|
||||
[data-theme="day"] {
|
||||
color-scheme: light;
|
||||
--bg-0: #e9e4da;
|
||||
--bg-1: #f4f1ea;
|
||||
--bg-2: #fbf9f5;
|
||||
--bg-3: #ffffff;
|
||||
--bg-4: #efe9df;
|
||||
--ink: 38 30 18;
|
||||
--line: rgb(38 30 18 / 0.09);
|
||||
--line-2: rgb(38 30 18 / 0.15);
|
||||
--line-3: rgb(38 30 18 / 0.26);
|
||||
--tx-1: #1f1b15;
|
||||
--tx-2: #55504a;
|
||||
--tx-3: #736d65;
|
||||
--tx-inv: #ffffff;
|
||||
--gold: #a65a0c;
|
||||
--gold-hi: #8a4a06;
|
||||
--gold-lo: #c98a3a;
|
||||
--grad-gold: linear-gradient(135deg, #bd6512 0%, #a9580d 55%, #984d08 100%);
|
||||
--sc-image: #0b8378;
|
||||
--sc-video: #c2511a;
|
||||
--sc-agent: #6d45d0;
|
||||
--sc-project: #a65a0c;
|
||||
--sc-manage: #4c6286;
|
||||
--sc-asset: #b93a72;
|
||||
--ok: #11804f;
|
||||
--warn: #9a6400;
|
||||
--err: #c42b41;
|
||||
--info: #2263c2;
|
||||
--hi: #141109;
|
||||
--on-scene: #ffffff;
|
||||
--on-ok: #ffffff;
|
||||
--sh-1:
|
||||
0 1px 0 rgba(255, 255, 255, 0.7) inset, 0 1px 2px rgba(60, 44, 20, 0.1);
|
||||
--sh-2:
|
||||
0 1px 0 rgba(255, 255, 255, 0.8) inset, 0 12px 32px rgba(60, 44, 20, 0.14),
|
||||
0 2px 6px rgba(60, 44, 20, 0.06);
|
||||
--sh-gold:
|
||||
0 4px 14px rgba(166, 90, 12, 0.28), 0 0 0 1px rgba(120, 60, 0, 0.18) inset;
|
||||
--sh-gold-hover:
|
||||
0 6px 20px rgba(166, 90, 12, 0.38), 0 0 0 1px rgba(120, 60, 0, 0.24) inset;
|
||||
--glass: color-mix(in srgb, var(--bg-1) 88%, transparent);
|
||||
--scrim: rgba(40, 32, 20, 0.34);
|
||||
--well: #ffffff;
|
||||
--media-shadow:
|
||||
0 14px 36px rgba(50, 38, 18, 0.2), 0 0 0 1px rgba(38, 30, 18, 0.1);
|
||||
--brand-grad: linear-gradient(145deg, #2c261d, #14110c);
|
||||
--brand-glow: 0 2px 8px rgba(40, 30, 15, 0.25);
|
||||
--brand-ink: #f2c46d;
|
||||
--display-grad: linear-gradient(90deg, #a65a0c, #c2511a);
|
||||
--glow: 0;
|
||||
--gen-bg: #e3ddd1;
|
||||
--grain: rgba(40, 30, 18, 0.1);
|
||||
--beam: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
color-mix(in srgb, var(--scene) 24%, transparent),
|
||||
rgba(255, 255, 255, 0.85),
|
||||
transparent
|
||||
);
|
||||
--lattice: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='24' viewBox='0 0 14 24'%3E%3Cpath d='M7 0l7 4v8l-7 4-7-4V4zM7 16v8' fill='none' stroke='%23261e12' stroke-opacity='.16' stroke-width='.8'/%3E%3C/svg%3E");
|
||||
--scanline: transparent;
|
||||
--stage-tint: 6%;
|
||||
--aur-1: #b9a0ff;
|
||||
--aur-2: #ffb39a;
|
||||
--aur-3: #8fe0d4;
|
||||
--aur-op: 0.42;
|
||||
--agent-hero: linear-gradient(120deg, #efe7ff, #faf7f1 55%, #e4f3ef);
|
||||
--agent-title: linear-gradient(90deg, #24163f, #5b34c4 55%, #a2346f);
|
||||
--orb-core: radial-gradient(
|
||||
circle at 35% 30%,
|
||||
#fff 0,
|
||||
#efe6ff 14%,
|
||||
#a98cf0 42%,
|
||||
#6d45d0 75%,
|
||||
transparent 76%
|
||||
);
|
||||
--particle: 109, 69, 208;
|
||||
--fail-a: #f6e3e3;
|
||||
--fail-b: #efd6d7;
|
||||
}
|
||||
|
||||
[data-theme="grade"] {
|
||||
color-scheme: dark;
|
||||
--bg-0: #1b1b1c;
|
||||
--bg-1: #222223;
|
||||
--bg-2: #29292b;
|
||||
--bg-3: #323234;
|
||||
--bg-4: #3c3c3f;
|
||||
--ink: 255 255 255;
|
||||
--line: rgb(255 255 255 / 0.075);
|
||||
--line-2: rgb(255 255 255 / 0.13);
|
||||
--line-3: rgb(255 255 255 / 0.22);
|
||||
--tx-1: #ecebe8;
|
||||
--tx-2: #acaba6;
|
||||
--tx-3: #85847f;
|
||||
--tx-inv: #141516;
|
||||
--r-xs: 2px;
|
||||
--r-sm: 4px;
|
||||
--r-md: 6px;
|
||||
--r-lg: 8px;
|
||||
--r-xl: 10px;
|
||||
--gold: #d9dde2;
|
||||
--gold-hi: #f2f4f6;
|
||||
--gold-lo: #9aa1aa;
|
||||
--grad-gold: linear-gradient(180deg, #f6f7f8 0%, #d5d9de 100%);
|
||||
--sc-image: #6fc2b7;
|
||||
--sc-video: #d8a06c;
|
||||
--sc-agent: #a598d8;
|
||||
--sc-project: #d4bc8a;
|
||||
--sc-manage: #909cae;
|
||||
--sc-asset: #d394b0;
|
||||
--ok: #4cc38f;
|
||||
--warn: #e3a93b;
|
||||
--err: #ee5d70;
|
||||
--info: #5d9fe3;
|
||||
--hi: white;
|
||||
--on-scene: #141516;
|
||||
--on-ok: #06140e;
|
||||
--sh-1:
|
||||
0 1px 0 rgba(255, 255, 255, 0.035) inset, 0 2px 6px rgba(0, 0, 0, 0.35);
|
||||
--sh-2:
|
||||
0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 12px 30px rgba(0, 0, 0, 0.45);
|
||||
--sh-gold:
|
||||
0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.55) inset;
|
||||
--sh-gold-hover:
|
||||
0 6px 18px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.7) inset;
|
||||
--glass: color-mix(in srgb, var(--bg-1) 82%, transparent);
|
||||
--scrim: rgba(0, 0, 0, 0.55);
|
||||
--well: #18181a;
|
||||
--media-shadow:
|
||||
0 18px 44px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.07);
|
||||
--brand-grad: linear-gradient(145deg, #f1f2f3, #aeb3ba);
|
||||
--brand-glow: none;
|
||||
--brand-ink: #17181a;
|
||||
--display-grad: linear-gradient(90deg, #ffffff, #bfc5cc);
|
||||
--glow: 0;
|
||||
--gen-bg: #1a1b1d;
|
||||
--grain: rgba(255, 255, 255, 0.06);
|
||||
--beam: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.07),
|
||||
rgba(255, 255, 255, 0.22),
|
||||
transparent
|
||||
);
|
||||
--scanline: transparent;
|
||||
--stage-tint: 0%;
|
||||
--aur-1: #5d5a80;
|
||||
--aur-2: #7a6070;
|
||||
--aur-3: #4f7470;
|
||||
--aur-op: 0.16;
|
||||
--agent-hero: linear-gradient(120deg, #202027, #1b1c1e 60%, #1b2020);
|
||||
--agent-title: linear-gradient(90deg, #ffffff, #d4d0ea);
|
||||
--orb-core: radial-gradient(
|
||||
circle at 35% 30%,
|
||||
#fff 0,
|
||||
#e7e5f2 14%,
|
||||
#a598d8 44%,
|
||||
#3e3a5c 76%,
|
||||
transparent 77%
|
||||
);
|
||||
--particle: 205, 205, 215;
|
||||
--fail-a: #211a1b;
|
||||
--fail-b: #1b1617;
|
||||
}
|
||||
|
||||
[data-theme="bluehour"] {
|
||||
color-scheme: dark;
|
||||
--bg-0: #0a1029;
|
||||
--bg-1: #0f1838;
|
||||
--bg-2: #162148;
|
||||
--bg-3: #1f2c5c;
|
||||
--bg-4: #2a386e;
|
||||
--r-sm: 8px;
|
||||
--r-md: 12px;
|
||||
--r-lg: 18px;
|
||||
--r-xl: 26px;
|
||||
--ink: 214 224 255;
|
||||
--line: rgb(214 224 255 / 0.07);
|
||||
--line-2: rgb(214 224 255 / 0.12);
|
||||
--line-3: rgb(214 224 255 / 0.2);
|
||||
--tx-1: #eef1fb;
|
||||
--tx-2: #a9b1cc;
|
||||
--tx-3: #7680a2;
|
||||
--tx-inv: #2b0c05;
|
||||
--gold: #ff9a6c;
|
||||
--gold-hi: #ffc7a8;
|
||||
--gold-lo: #d9603f;
|
||||
--grad-gold: linear-gradient(135deg, #ffd3b4 0%, #ff9a6c 45%, #f0644f 100%);
|
||||
--sc-image: #4fd6ea;
|
||||
--sc-video: #ffbb55;
|
||||
--sc-agent: #b592ff;
|
||||
--sc-project: #ff9a6c;
|
||||
--sc-manage: #8aa0dc;
|
||||
--sc-asset: #ff86c0;
|
||||
--ok: #4fd69c;
|
||||
--warn: #ffc94d;
|
||||
--err: #ff4d6d;
|
||||
--info: #69b4ff;
|
||||
--hi: white;
|
||||
--on-scene: #1a0b04;
|
||||
--on-ok: #05150e;
|
||||
--sh-1:
|
||||
0 1px 0 rgba(214, 224, 255, 0.05) inset, 0 2px 8px rgba(0, 0, 10, 0.4);
|
||||
--sh-2:
|
||||
0 1px 0 rgba(214, 224, 255, 0.06) inset, 0 12px 32px rgba(0, 0, 12, 0.55);
|
||||
--sh-gold:
|
||||
0 6px 24px rgba(255, 120, 90, 0.38),
|
||||
0 0 0 1px rgba(255, 214, 186, 0.42) inset;
|
||||
--sh-gold-hover:
|
||||
0 8px 30px rgba(255, 120, 90, 0.52),
|
||||
0 0 0 1px rgba(255, 226, 206, 0.55) inset;
|
||||
--scrim: rgba(4, 6, 16, 0.62);
|
||||
--media-shadow:
|
||||
0 30px 80px rgba(0, 0, 14, 0.62), 0 0 0 1px rgba(214, 224, 255, 0.08);
|
||||
--brand-grad: radial-gradient(
|
||||
circle at 30% 25%,
|
||||
#ffe4d2 0,
|
||||
#ff9a6c 38%,
|
||||
#a3363a 100%
|
||||
);
|
||||
--brand-glow: 0 0 26px rgba(255, 140, 100, 0.42);
|
||||
--brand-ink: #2b0c05;
|
||||
--display-grad: linear-gradient(90deg, #ffd3b4, #ff9a6c 55%, #ff7096);
|
||||
--glow: 1;
|
||||
--gen-bg: #0b1124;
|
||||
--grain: rgba(214, 224, 255, 0.08);
|
||||
--beam: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
color-mix(in srgb, var(--scene) 34%, transparent),
|
||||
rgba(255, 236, 220, 0.3),
|
||||
transparent
|
||||
);
|
||||
--stage-tint: 10%;
|
||||
--aur-1: #3e5bff;
|
||||
--aur-2: #ff7a8a;
|
||||
--aur-3: #2fd5e5;
|
||||
--aur-op: 0.36;
|
||||
--agent-hero: linear-gradient(
|
||||
120deg,
|
||||
rgba(26, 32, 84, 0.92),
|
||||
rgba(12, 16, 40, 0.94) 55%,
|
||||
rgba(44, 18, 52, 0.9)
|
||||
);
|
||||
--agent-title: linear-gradient(90deg, #ffffff, #c9d4ff 50%, #ffb8a0);
|
||||
--orb-core: radial-gradient(
|
||||
circle at 35% 30%,
|
||||
#fff 0,
|
||||
#ffe1cf 12%,
|
||||
#ff9a6c 38%,
|
||||
#5a2fb0 76%,
|
||||
transparent 77%
|
||||
);
|
||||
--particle: 255, 206, 186;
|
||||
--fail-a: #1d1220;
|
||||
--fail-b: #160e1a;
|
||||
}
|
||||
|
||||
@media (max-width: 1366px) {
|
||||
:root {
|
||||
--list: 248px;
|
||||
--hist: 84px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1280px) {
|
||||
:root {
|
||||
--rail: 60px;
|
||||
--list: 236px;
|
||||
--hist: 76px;
|
||||
--head: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compatibility names for existing pages; no independent colour palette. */
|
||||
:root {
|
||||
--accent-grad-hover: var(--grad-gold);
|
||||
--accent-ring: color-mix(in srgb, var(--gold) 25%, transparent);
|
||||
--accent-wash: var(--accent-soft);
|
||||
--btn-glow-hover: var(--sh-gold-hover);
|
||||
--composer-bg: var(--glass);
|
||||
--composer-focus: var(--bg-2);
|
||||
--float-bg: var(--bg-2);
|
||||
--on-media: #fff;
|
||||
--on-media-line: #ffffff66;
|
||||
--sel-shadow: 0 0 0 1px var(--gold);
|
||||
--bg: var(--bg-0);
|
||||
--paper: var(--bg-2);
|
||||
--lime: color-mix(in srgb, var(--sc-image) 14%, var(--bg-2));
|
||||
--rose: color-mix(in srgb, var(--sc-asset) 14%, var(--bg-2));
|
||||
--text: var(--tx-1);
|
||||
--text-2: var(--tx-2);
|
||||
--text-3: var(--tx-3);
|
||||
--accent: var(--gold);
|
||||
--accent-hi: var(--gold-hi);
|
||||
--accent-lo: var(--gold-lo);
|
||||
--accent-ink: var(--tx-inv);
|
||||
--accent-soft: color-mix(in srgb, var(--gold) 9%, transparent);
|
||||
--accent-line: color-mix(in srgb, var(--gold) 35%, transparent);
|
||||
--accent-grad: var(--grad-gold);
|
||||
--accent-glow: var(--sh-gold);
|
||||
--btn-glow: var(--sh-gold);
|
||||
--page-glow: linear-gradient(transparent, transparent);
|
||||
--ok-soft: color-mix(in srgb, var(--ok) 9%, transparent);
|
||||
--run: var(--info);
|
||||
--run-soft: color-mix(in srgb, var(--info) 9%, transparent);
|
||||
--run-grad: linear-gradient(90deg, var(--info), var(--sc-agent));
|
||||
--err-solid: var(--err);
|
||||
--err-soft: color-mix(in srgb, var(--err) 9%, transparent);
|
||||
--err-line: color-mix(in srgb, var(--err) 40%, transparent);
|
||||
--warn-soft: color-mix(in srgb, var(--warn) 9%, transparent);
|
||||
--overlay: var(--scrim);
|
||||
--media-scrim: #101017ee;
|
||||
--media-text: #fff;
|
||||
--media-line: #ffffff66;
|
||||
--stage-bg: var(--bg-0);
|
||||
--fs-title: 15px;
|
||||
--fs-section: 14px;
|
||||
--fs-body-sm: 12.5px;
|
||||
--fs-aux: 12px;
|
||||
--fs-mini: 11px;
|
||||
--lh-body: 1.55;
|
||||
--sp-1: 4px;
|
||||
--sp-2: 6px;
|
||||
--sp-3: 8px;
|
||||
--sp-4: 10px;
|
||||
--sp-5: 12px;
|
||||
--sp-6: 16px;
|
||||
--sp-7: 20px;
|
||||
--sp-8: 28px;
|
||||
--shadow-float: var(--sh-2);
|
||||
--rail-w: var(--rail);
|
||||
--topbar-h: var(--head);
|
||||
--tabbar-h: 0px;
|
||||
--sprocket: none;
|
||||
--frame-w: 0px;
|
||||
--frame-arm: 12px;
|
||||
--frame-inset: -4px;
|
||||
--paper-w: 4px;
|
||||
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
|
||||
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
|
||||
--d-press: 160ms;
|
||||
--d-state: 160ms;
|
||||
--d-pop: 180ms;
|
||||
--d-leave: 200ms;
|
||||
--d-enter: 220ms;
|
||||
--d-drawer: 250ms;
|
||||
--d-flash: 900ms;
|
||||
--d-progress: 400ms;
|
||||
--press-scale: 0.97;
|
||||
--avatar-1: color-mix(in srgb, var(--sc-project) 20%, var(--bg-2));
|
||||
--avatar-2: color-mix(in srgb, var(--sc-image) 20%, var(--bg-2));
|
||||
--avatar-3: color-mix(in srgb, var(--sc-video) 20%, var(--bg-2));
|
||||
--avatar-4: color-mix(in srgb, var(--sc-asset) 20%, var(--bg-2));
|
||||
--avatar-5: color-mix(in srgb, var(--sc-agent) 20%, var(--bg-2));
|
||||
--id-1: var(--sc-project);
|
||||
--id-2: var(--sc-image);
|
||||
--id-3: var(--sc-video);
|
||||
--id-4: var(--sc-asset);
|
||||
--id-5: var(--sc-agent);
|
||||
--surface: var(--bg-2);
|
||||
--surface-2: var(--bg-3);
|
||||
--surface-3: var(--bg-4);
|
||||
--border: var(--line);
|
||||
--border-strong: var(--line-2);
|
||||
--border-hover: var(--line-2);
|
||||
--accent-dim: var(--accent-soft);
|
||||
--success: var(--ok);
|
||||
--success-dim: var(--ok-soft);
|
||||
--info-dim: color-mix(in srgb, var(--info) 9%, transparent);
|
||||
--error: var(--err);
|
||||
--error-dim: var(--err-soft);
|
||||
--warning: var(--warn);
|
||||
--bg-primary: var(--bg);
|
||||
--bg-surface: var(--bg-2);
|
||||
--bg-elevated: var(--bg-3);
|
||||
--text-primary: var(--text);
|
||||
--text-secondary: var(--text-2);
|
||||
--text-muted: var(--text-3);
|
||||
--font-a-mono: var(--mono);
|
||||
--font-display: var(--font);
|
||||
--font-body: var(--font);
|
||||
--font-mono: var(--mono);
|
||||
--radius-sm: var(--r-sm);
|
||||
--radius-md: var(--r-md);
|
||||
--radius-lg: var(--r-lg);
|
||||
--space-sm: var(--sp-3);
|
||||
--space-md: var(--sp-6);
|
||||
--pill-bg: var(--bg-3);
|
||||
--pill-border: var(--line-2);
|
||||
--pill-radius: var(--r-pill);
|
||||
--pill-height: 36px;
|
||||
--pill-padding: 0 14px;
|
||||
--pill-font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
html {
|
||||
background: var(--bg-0);
|
||||
color: var(--tx-1);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
# 夜片场 Nocturne Set — AIGC 工作台设计规范 v1(待白栖知确认)
|
||||
|
||||
> 视觉总监出具。本文件和 `index.html`(交互样本)、`shots/*.png` 一起,是施工和验收的唯一品味依据。样本中的画面都是程序生成的示意图,不是真实生成结果,也不调用任何接口。
|
||||
|
||||
## 0. 一句话方向
|
||||
|
||||
**深夜片场:墨黑的棚里只亮一盏钨丝灯,作品是唯一被照亮的东西。**
|
||||
本项目本质是“从故事到成片”的制片工具,所以主题元素取自片场,而不是暗房或印刷:取景框角标(选中)、扫描光束(生成中)、显影(结果到达)、场记编号与时间码(等宽数字)、每个工作区一种“场景色温”。参考站学的是它的骨架:紧凑、左侧双栏、底部输入座、参数胶囊、按场景变化的主题色;没有照抄它的配色。
|
||||
|
||||
## 1. 事实盘点(已核实)
|
||||
|
||||
| 项 | 事实 | 来源 |
|
||||
|---|---|---|
|
||||
| 前端路由 | 项目首页 `/`、工作台 `/workbench/[id]`、生图 `/image`、生视频 `/video`、任务 `/tasks`、智能体 `/agents`、画布 `/canvas/[id]`、素材库 `/library`、ComfyUI 连接 `/connections`、模型设置 `/models`、设置 `/settings`、三维搭景 `/build-scene`、试验台 `/playground` | 仓库 `calliope-web/src/routes` |
|
||||
| 五阶段 | 剧本 → 视觉 → 分镜 → 素材 → 镜头脚本;每阶段一个智能体,草稿需人工确认后才交给下一阶段,可恢复已确认版 | `i18n/zh.ts` workbench.* |
|
||||
| 工作流文件 | 仓库 `example_ComfyUI_workflows` 共 **156** 个文件:**10** 个是 API 格式,**146** 个是 ComfyUI 界面格式(需重新导出 API 格式并做输入映射才能执行) | 逐个文件检查 `nodes`/`last_node_id` 字段 |
|
||||
| 已可执行 | 测试站 `/api/workflows` 当前 **9** 条(图片 5、视频 4) | 测试站接口,只读 |
|
||||
| 素材槽 | 参考图(1–N)、遮罩、首帧、尾帧(可选)、参考视频、参考音频;按工作流声明出现 | studio.* 文案 + 组件 |
|
||||
| 模型设置 | 当前仅开放 LLM;图片/视频模型标“后续开放” | models.* |
|
||||
| 历次投诉 | 结果被挤小、历史穿插在生成区、大片空白、窗口不全、生成按钮要滚动才看到、视频自动播放且空格乱切、找不到播放键、百余工作流难找、智能体只做成了聊天 | 主卡 10/13–10/14 评论 |
|
||||
|
||||
## 2. 页面分工与核心路径
|
||||
|
||||
**用户要做的三件事**,决定了三个主场;其余页面都是它们的仓库或后台。
|
||||
|
||||
| 用户要做什么 | 从哪里进入 | 连续操作 | 看到/处理结果 | 回到项目 |
|
||||
|---|---|---|---|---|
|
||||
| A. 推进一个片子 | 工作室首页「继续创作」大卡 / 项目卡 | 项目页顶部五阶段 → 当前阶段的内容网格 → 右侧本阶段助手(补充要求/重新生成) | 草稿条提示“待确认”,底栏固定「确认,进入下一阶段」 | 本身就在项目里 |
|
||||
| B. 生成一张图/一段视频 | 侧栏「创作台」或项目镜头卡「去生视频」 | 左列找工作流 → 底座放素材、写正反提示词 → 参数胶囊 → 生成 | 中间舞台整幅显示;右侧历史竖条单独存在,点开时顶部提示“正在查看历史”,可复用或回到最新 | 结果下方「存入项目」→ 选项目与阶段,进入“待确认” |
|
||||
| C. 让助手干活 | 侧栏「智能体」或项目阶段的「对话」 | 首页大输入框写想法、绑定项目/模型/技能 → 任务页看计划、工具调用 | 右侧成果栏是可编辑草稿(分镜表/角色/提示词),单镜可重画 | 「带回项目待确认」→ 项目页出现紫色草稿条 |
|
||||
|
||||
**导航(左侧 68px 总导航,图标+文字常显)**:工作室、项目、创作台、智能体、画布、素材库 | 任务、工作流、模型连接 | 底部:队列、动效开关、设置。
|
||||
- 双左栏只在创作台出现(总导航 68 + 工作流列 272),两栏分别回答“去哪个功能”和“用哪个工作流”,宽度差一倍,不会混淆。
|
||||
- 原「生图」「生视频」两个路由合并为创作台,用顶部分段切换;切换时各自记住工作流、参数和输入。
|
||||
- 原「ComfyUI 连接」与「模型设置」合为「模型连接」,四个页签:ComfyUI 连接 / 大语言模型 / 图片模型 / 视频模型。
|
||||
|
||||
**设计判断(为什么这样分)**
|
||||
1. 创作台舞台是“作品优先”:不放详情、不放历史,结果按真实比例 `contain` 适配剩余空间;操作条固定在作品正下方,不覆盖画面。
|
||||
2. 历史是独立竖条(92px),只承担“回看”;回看是显式状态(蓝色提示条),绝不替换当前输入。
|
||||
3. 工作流先按“我要做什么”(任务胶囊)缩小,再按模型族分组,置顶永远在最上;长文件名只在悬停/表头次要位置出现,主名是人话名。
|
||||
4. “待配置”的工作流默认隐藏(开关「仅可运行」),避免把 146 个未映射文件冒充可用工具;关掉开关能看到并引导去映射。
|
||||
5. 智能体不是聊天:任务列表 + 计划 + 工具卡 + 成果栏三栏,成果有归属(项目·阶段)和确认流程。
|
||||
6. 管理页(任务/工作流/模型连接/素材库)共用“左筛选 220 / 中列表 / 右详情 360”,详情不跳页。
|
||||
|
||||
## 3. 设计 Token
|
||||
|
||||
```css
|
||||
/* 表面 */ --bg-0:#07080c; --bg-1:#0c0e14; --bg-2:#12151d; --bg-3:#1a1e29; --bg-4:#232838;
|
||||
/* 描边 */ --line:rgba(255,255,255,.06); --line-2:.11; --line-3:.18;
|
||||
/* 文字 */ --tx-1:#f3efe6; --tx-2:#aaa79e; --tx-3:#6f6d68; --tx-inv:#1a1206;
|
||||
/* 主光 */ --gold:#e9b04b; --gold-hi:#f8d68c; --gold-lo:#b8771f;
|
||||
--grad-gold:linear-gradient(135deg,#fbe1a1,#efb54f 45%,#d98a26);
|
||||
/* 场景色温 */ --sc-image:#3fd8c6; --sc-video:#ff8a3d; --sc-agent:#a879ff; --sc-project:#e9b04b; --sc-manage:#7f93b5;
|
||||
/* 状态 */ --ok:#43d39a; --warn:#f2b33d; --err:#ff5d6c; --info:#5aa9ff;
|
||||
/* 字号 */ --fs-display:28px/700; --fs-h1:20px/600; --fs-h2:16px/600; --fs-body:13px/400 lh1.55; --fs-small:12px; --fs-micro:11px;
|
||||
/* 字体 */ --font:"PingFang SC","HarmonyOS Sans SC","Microsoft YaHei UI",sans-serif; --mono:"JetBrains Mono",Consolas,monospace;
|
||||
/* 间距 */ --s1:4 --s2:8 --s3:12 --s4:16 --s5:20 --s6:24 --s8:32;
|
||||
/* 圆角 */ --r-xs:4 --r-sm:6 --r-md:10 --r-lg:14 --r-xl:20 --r-pill:999;
|
||||
/* 阴影 */ --sh-1 内高光+2/8; --sh-2 内高光+12/32 黑50%; --sh-gold 金色外发光(仅主按钮);
|
||||
/* 动效 */ --ease-out:cubic-bezier(.22,1,.36,1); --ease-io:(.65,0,.35,1); --ease-spring:(.34,1.56,.64,1);
|
||||
--t-fast:120ms; --t-base:200ms; --t-slow:320ms; --t-reveal:700ms;
|
||||
/* 布局 */ --rail:68; --list:272; --hist:92; --head:48;
|
||||
```
|
||||
|
||||
**色彩规则**
|
||||
- 一个页面只有一个金色主按钮(生成 / 确认 / 带回项目 / 开始任务)。
|
||||
- 场景色只用于“位置与焦点”:选中边框、取景框角标、进度条、焦点光环、导航指示条;禁止做大面积底色。智能体页是唯一允许场景色做氛围(极光、光球)的页面。
|
||||
- 数字信息(编号、时间码、比例、种子、延迟)一律等宽字体。
|
||||
|
||||
## 4. 组件与状态
|
||||
|
||||
| 组件 | 尺寸 | 默认 | 悬停 | 选中/按下 | 禁用/异常 |
|
||||
|---|---|---|---|---|---|
|
||||
| 按钮 `.btn` | 26/32/38 高 | bg-3 + line-2 | bg-4 + line-3 | 下移 1px | — |
|
||||
| 主按钮 `.btn.primary` | 32/38 | 金渐变 + sh-gold | 提亮 6% + 扫光一次 | 下移 1px | 去饱和 60% 亮度,旁边红字写“还缺:…” |
|
||||
| 胶囊 `.chip` | 24–26 | bg-2 | 文字变亮 | 场景色 13% 底 + 60% 描边 | — |
|
||||
| 参数胶囊 `.pchip` | 28 | 透明 4% | 描边变亮 | 点开弹层 | — |
|
||||
| 工作流行 `.wfi` | 50 | 透明 | 光栅悬停 + 3% 底 | 场景色渐变底 + 35% 描边 | 待配置:族色块灰化、名字降一级、黄标签 |
|
||||
| 素材槽 `.slot` | 56(矮屏 50) | 虚线 line-3 | 场景色虚线 | 实线 + 缩略图 + 悬停出现 × | 必填未填:黄色虚线 |
|
||||
| 作品框 `.frame` | 适配 | 取景框角标常显 | — | — | 失败:斜纹底 + 原因 + 重试 |
|
||||
| 视频播放器 | 画面 + 40 控制栏 | **暂停**,中央大播放键 | 大播放键放大 1.08 | 播放后大键隐藏,控制栏常显 | — |
|
||||
| 草稿条 | 44 | 紫色渐变 + 描边 | — | — | — |
|
||||
| 弹层 `.pop` | ≤620×64vh | 底部固定“取消/保存”,内部滚动 | — | — | — |
|
||||
|
||||
**交互铁律**
|
||||
- 视频永不自动播放;切换结果保持暂停;空格只在播放器获得焦点时切换。
|
||||
- 生成按钮、确认按钮、带回项目按钮永远在首屏固定位置,不随内容滚走。
|
||||
- 参数弹层“取消不改参数”;图片与视频分别记忆参数。
|
||||
- 切换工作流保留提示词;新工作流有反向提示词时自动出现右栏(左正右反)。
|
||||
- 置顶不切换当前工作流、不清空输入;置顶分图片/视频保存。
|
||||
|
||||
## 5. 图标与插图
|
||||
|
||||
- 图标:1.7px 线性描边、圆角端点、24 网格;尺寸 14/18/22。不用填充图标,置顶激活例外(填充金色)。
|
||||
- 工作流族色块:34px 圆角方块 + 族缩写(Qwen/Kr2/FLX/Z/H3/Wan/GPT/NB/可灵/即梦),待配置时灰化。
|
||||
- 插图:阶段助手卡与工作室大卡用真实项目产物做底图(无产物时用场景色渐变 + 胶片颗粒),不用卡通吉祥物。
|
||||
|
||||
## 6. 动效规范
|
||||
|
||||
| 名称 | 触发 | 时长 · 曲线 | 可打断 | 减少动效 |
|
||||
|---|---|---|---|---|
|
||||
| 页面进入 | 切一级页 | 320ms · ease-out,上移 6px 淡入 | 是 | 直接出现 |
|
||||
| 光栅悬停 | 指针进入列表行/卡片 | 320ms 渐显,跟随指针的光斑 + 蜂窝纹 | 是 | 只变背景亮度 |
|
||||
| 取景框 | 选中工作流/作品/历史 | 200ms · ease-out,角标外扩 2px | 是 | 保留角标 |
|
||||
| 扫描光束 | 生成中 | 1.6s 循环 · ease-io | 取消即停 | 只留进度条 |
|
||||
| 显影 | 结果到达 | 700ms · ease-out(模糊/过曝 → 清晰) | 点击跳过 | 淡入 |
|
||||
| 主按钮扫光 | 悬停主按钮 | 700ms 一次 | 是 | 关闭 |
|
||||
| 弹层 | 打开参数/菜单 | 200ms · 上移 6px + 缩放 .98 | Esc / 点外部 | 直接出现 |
|
||||
| 提示 Toast | 操作完成 | 320ms spring,3.2s 消失 | 是 | 淡入 |
|
||||
| 智能体氛围 | 进入智能体页 | 极光 18s 漂移、粒子上升、光球呼吸 4.5s | 离开页面即停 | 全部关闭 |
|
||||
|
||||
**性能降级**:粒子用单 canvas、≤46 个,离开页面停止 rAF;极光用 3 个模糊圆、transform 动画;`prefers-reduced-motion` 或侧栏「动效」开关关闭时加 `html.reduce`,去掉所有位移/循环,仅保留颜色与状态变化。
|
||||
|
||||
## 7. 桌面断点
|
||||
|
||||
| 窗口宽 | 总导航 | 工作流列 | 历史栏 | 其他 |
|
||||
|---|---|---|---|---|
|
||||
| ≥1600 | 68 | 272 | 92 | 工作室右栏 340,智能体成果栏 420 |
|
||||
| 1367–1599 | 68 | 272 | 92 | 标准(1440×900 样稿) |
|
||||
| 1281–1366 | 68 | 248 | 84 | 页头隐藏工作流文件名 |
|
||||
| ≤1280 | 60 | 236 | 76 | 页头 44;历史栏可收起 |
|
||||
| 高 ≤800 | 导航压缩 | 提示词 48 高、素材槽 50;长提示词点「展开」到 28vh,内部滚动 |
|
||||
|
||||
最小支持 1280×720(已出样稿 `14-create-image-1280x720.png`、`15-agent-task-1280x720.png`)。不做手机版。
|
||||
|
||||
## 8. 待确认事项(请总管转白栖知)
|
||||
|
||||
1. **主题方向**:「夜片场」(墨黑 + 钨丝金 + 各区场景色温)是否认可?这是本卡唯一主方向,不再并列给多套。
|
||||
2. **生图/生视频合并**为一个「创作台」,顶部切换图片/视频(各自记忆)——是否同意?
|
||||
3. **试验台(Playground)并入创作台**、旧入口下线;**三维搭景**不进一级导航,入口放在项目「镜头脚本」阶段和视频参考槽——是否同意?
|
||||
4. 「仅可运行」默认打开:146 个未映射文件默认不出现在创作台,只在「工作流库」里显示待配置——是否接受?
|
||||
5. ComfyUI 连接与模型设置合并为「模型连接」一页四个页签——是否同意?
|
||||
6. 云端图片/视频模型(GPT-Image-2、Nano Banana、可灵、即梦)在样本中按“已接入”展示;当前后端只开放 LLM,接入属于新增能力,需另行排期。
|
||||
|
||||
## 9. 施工提示(给总工/施工员)
|
||||
|
||||
- Token 直接替换现有 `app.css` 变量体系;组件按第 4 节状态表逐一对照。
|
||||
- 舞台尺寸用容器实测(ResizeObserver)计算 contain 尺寸,不用固定高度;视频控件高度计入。
|
||||
- 历史栏、工作流列、成果栏、弹层内容都各自滚动;页面本身不滚(工作室、规范页除外)。
|
||||
- 验收看图看操作:1440×900、1366×768、1280×720 三档下,作品完整、主按钮可见、视频默认暂停。
|
||||
@@ -0,0 +1,105 @@
|
||||
# 夜片场 · 多主题规范 v2(待白栖知看样确认)
|
||||
|
||||
> 视觉总监出具,在 HEL-716《夜片场》规范 v1 的基础上**增补**主题。v1 中的布局、组件、动效和断点全部继续有效,本文件只写新增和改动的部分。样本使用的是示例画面和演示状态,不调用真实生成、不产生费用。
|
||||
|
||||
## 0. 原则
|
||||
|
||||
**同一个片场,换一种灯光。** 四套主题共用同一套布局、功能、操作顺序和动效,只改变语义变量和少量“气质”参数(圆角、发光开关、氛围层)。组件 CSS 里只能引用语义变量,不允许写死颜色;主题差异只能写在 `[data-theme="…"]` 块中。
|
||||
|
||||
| ID | 中文名 | 气质与适用场景 | 默认 |
|
||||
|---|---|---|---|
|
||||
| `night` | **夜片场** Nocturne | 墨黑底、钨丝金主键、各工作区有自己的场景色温。夜间、沉浸式创作。 | ✅ 默认(即已认可的原版,一个像素都没改) |
|
||||
| `day` | **日光棚** Daylight | 暖白纸面、墨色文字、深琥珀主键;不使用发光,靠描边、实色和对比度区分。白天办公、长时间审稿。 | |
|
||||
| `grade` | **调色间** Grading | 中性深灰、白色主键、场景色降低饱和度、舞台不加色调;圆角收紧到 2–8px,更像工具。用于判断作品色彩,适合长时间看片。 | |
|
||||
| `bluehour` | **蓝调时刻** Blue Hour | 靛蓝到紫的天色渐变、珊瑚橙主键、圆角放大到 8–26px、主按钮做成胶囊形,氛围最浓。用于提案、展示和灵感发散。 | |
|
||||
|
||||
## 1. 语义变量(施工直接使用)
|
||||
|
||||
基础变量名沿用 v1;v2 新增的语义变量标 ★。
|
||||
|
||||
| 语义 | 变量 | 夜片场 | 日光棚 | 调色间 | 蓝调时刻 |
|
||||
|---|---|---|---|---|---|
|
||||
| 页面底 / 输入凹槽 | `--bg-0` | #07080c | #e9e4da | #1b1b1c | #0a1029 |
|
||||
| 面板(导航、列表、历史栏) | `--bg-1` | #0c0e14 | #f4f1ea | #222223 | #0f1838 |
|
||||
| 卡片 | `--bg-2` | #12151d | #fbf9f5 | #29292b | #162148 |
|
||||
| 浮起层 / 按钮 | `--bg-3` | #1a1e29 | #ffffff | #323234 | #1f2c5c |
|
||||
| 悬停 | `--bg-4` | #232838 | #efe9df | #3c3c3f | #2a386e |
|
||||
| 主文字 | `--tx-1` | #f3efe6 | #1f1b15 | #ecebe8 | #eef1fb |
|
||||
| 次要文字 | `--tx-2` | #aaa79e | #55504a | #acaba6 | #a9b1cc |
|
||||
| 弱文字(≥4.3:1,浅色主题同样适用) | `--tx-3` | #6f6d68 | #736d65 | #85847f | #7680a2 |
|
||||
| 叠加通道 ★(悬停、细线用 `rgb(var(--ink)/a)`) | `--ink` | 255 255 255 | 38 30 18 | 255 255 255 | 214 224 255 |
|
||||
| 边框 1/2/3 | `--line*` | 白 .06/.11/.18 | 墨 .09/.15/.26 | 白 .075/.13/.22 | 冷白 .07/.12/.2 |
|
||||
| 主操作(“去做”,全页唯一) | `--gold` / `--grad-gold` | #e9b04b 金 | #a65a0c 深琥珀 | #d9dde2 校色白 | #ff9a6c 珊瑚 |
|
||||
| 主操作上的文字 | `--tx-inv` | #1a1206 | #ffffff | #141516 | #2b0c05 |
|
||||
| 场景 · 图片 | `--sc-image` | #3fd8c6 | #0b8378 | #6fc2b7 | #4fd6ea |
|
||||
| 场景 · 视频 | `--sc-video` | #ff8a3d | #c2511a | #d8a06c | #ffbb55 |
|
||||
| 场景 · 智能体 | `--sc-agent` | #a879ff | #6d45d0 | #a598d8 | #b592ff |
|
||||
| 场景 · 项目 | `--sc-project` | #e9b04b | #a65a0c | #d4bc8a | #ff9a6c |
|
||||
| 场景 · 管理 | `--sc-manage` | #7f93b5 | #4c6286 | #909cae | #8aa0dc |
|
||||
| 场景 · 素材资产 ★ | `--sc-asset` | #ff86b0 | #b93a72 | #d394b0 | #ff86c0 |
|
||||
| 成功 | `--ok` | #43d39a | #11804f | #4cc38f | #4fd69c |
|
||||
| 提醒 / 待配置 | `--warn` | #f2b33d | #9a6400 | #e3a93b | #ffc94d |
|
||||
| 错误 / 失败 | `--err` | #ff5d6c | #c42b41 | #ee5d70 | #ff4d6d |
|
||||
| 信息 / 历史回看 | `--info` | #5aa9ff | #2263c2 | #5d9fe3 | #69b4ff |
|
||||
| 场景色文字混色端 ★ | `--hi` | white | #141109 | white | white |
|
||||
| 场景/状态实底上的文字 ★ | `--on-scene` / `--on-ok` | 深色 | #fff | 深色 | 深色 |
|
||||
| 输入框底 ★ | `--well` | bg-0 | #ffffff | #18181a | bg-0 |
|
||||
| 页头毛玻璃 ★ | `--glass` | bg-1 70% | bg-1 88% | bg-1 82% | 定制 55% |
|
||||
| 遮罩层 ★ | `--scrim` | 黑 .6 | 暖墨 .34 | 黑 .55 | 深蓝 .62 |
|
||||
| 作品阴影 ★ | `--media-shadow` | 重 | 轻、暖 | 中 | 重、偏蓝 |
|
||||
| 发光开关 ★ | `--glow` | 1 | 0 | 0 | 1 |
|
||||
|
||||
另有特效变量 ★:`--gen-bg`(生成中底色)、`--beam`(扫描光)、`--grain`(颗粒)、`--lattice`(光栅蜂窝纹)、`--scanline`、`--stage-tint`(舞台场景色晕 0–10%)、`--aur-1/2/3`、`--aur-op`(极光)、`--agent-hero`、`--agent-title`、`--orb-core`、`--particle`、`--brand-grad/-glow/-ink`、`--display-grad`、`--fail-a/b`。完整取值见交互样本 `<style>` 中的四个主题块;也可以在样本「规范 → 05 主题」里查看,那里直接读取实际变量。
|
||||
|
||||
**场景色与状态色**:两组颜色在每套主题里都单独取值,不互相借用。场景色只表示“你在哪个工作区”(选中边框、取景框、进度、焦点);状态色只表示“结果怎么样”。调色间里场景色降低饱和度,状态色保持鲜明,两者不会混淆。
|
||||
**不随主题变的元素**:作品框底色、视频控制条、作品上的角标(编号、时长、草图标签)、灯箱,在所有主题都保持深色,避免主题给作品染色。工作流模型族色块也保持不变,方便跨主题识别。
|
||||
|
||||
## 2. 特色效果按主题适配
|
||||
|
||||
| 效果 | 夜片场 | 日光棚 | 调色间 | 蓝调时刻 |
|
||||
|---|---|---|---|---|
|
||||
| 扫描光(生成中) | 场景色 + 白光 | 场景色 24% + 纸白高光,不发光 | 中性白,无色彩 | 场景色 34% + 暖白 |
|
||||
| 显影(结果到达) | 模糊/过曝 → 清晰 | `developDay`:模糊 + 棕褐色调 → 清晰(像相纸显影) | `developGrade`:去饱和 → 清晰 | 同夜片场 |
|
||||
| 取景框角标 | 场景色偏白 | 场景色偏墨(更深) | 场景色 | 场景色 |
|
||||
| 光栅悬停 | 白色蜂窝纹 | 墨色蜂窝纹 | 白色 | 冷白色 |
|
||||
| 发光(导航条、进度条、阶段下划线、状态点) | 有 | **无** | **无** | 有 |
|
||||
| 智能体氛围 | 紫粉青极光 .33 | 淡紫/桃/薄荷 .42 | 低饱和 .16 | 蓝/珊瑚/青 .36 |
|
||||
|
||||
浅色主题不靠发光,也不靠低对比文字来区分信息:选中用实色描边加浅底,禁用的主按钮用浅灰底加灰字(不只是降低透明度)。
|
||||
|
||||
## 3. 切换与记忆规则
|
||||
|
||||
- **入口**:侧栏底部「主题」(图标是当前主题的四色圆点)→ 弹层列出四个主题:实时缩略预览、中文名、英文名、色调和一句话用途,当前项有 ✓。「设置 → 外观主题」有同样的四张卡片。键盘可用:方向键在选项间移动,Enter 选择,Esc 关闭并把焦点还给入口按钮。
|
||||
- **只改 `html[data-theme]`**:不重新渲染页面,所以提示词、上传素材、参数、工作流选择、历史回看、项目阶段草稿、智能体任务和成果都保持原样(样本自测已覆盖,见第 6 节)。
|
||||
- **记忆**:存 `localStorage['aigc-theme']`;`<head>` 里的内联脚本在首次绘制前读取,避免先闪一下夜片场。读到非法值或读取失败时回退到 `night`。
|
||||
- **存储不可用**:切换照常生效,弹层底部提示“浏览器禁止本地存储:本次有效,其他操作不受影响”,不报错,也不阻止其他操作。
|
||||
- **默认是夜片场**,不跟随系统的深浅色设置(深浅色只是主题的一个属性,不是选择主题的依据)。正式产品如需按账号同步,再把同一个值存到用户设置里,本地存储作为缓存。
|
||||
- 「动效开/关」已移到主题弹层底部(同属外观设置),侧栏底部仍然是 4 个按钮,1280×720 下不会溢出。
|
||||
|
||||
## 4. 动效与减少动效
|
||||
|
||||
| 名称 | 触发 | 时长 · 曲线 | 可否打断 | 减少动效时 |
|
||||
|---|---|---|---|---|
|
||||
| 切换主题「开灯」 | 选择新主题 | 520ms · `--ease-out`;新主题从点击位置圆形展开(View Transitions) | 是,再次选择会接管 | 立即替换 |
|
||||
| 不支持 View Transitions 时 | 同上 | 280ms 颜色淡入淡出(`html.theme-anim`,340ms 后移除) | 是 | 立即替换 |
|
||||
| 其余动效 | 同 v1 | 同 v1 | 同 v1 | 同 v1 |
|
||||
|
||||
`prefers-reduced-motion` 或手动关闭动效时加上 `html.reduce`:主题立即切换,极光、粒子、光束隐藏,只保留颜色和状态变化。粒子颜色在切换主题时从 `--particle` 重新读取。
|
||||
|
||||
## 5. 本卡同时修正(按已定分工)
|
||||
|
||||
- 云端 GPT-Image-2、Nano Banana Pro、可灵、即梦:在创作台归入「云端模型 · 尚未接入(后续批次)」,灰色色块加虚线「未接入」标签;选中后,生成按钮禁用并提示“尚未接入:云端接口属后续批次,当前不可生成”,页头连接状态为灰点“云端接口尚未接入”。「模型连接」页的云端卡片改为虚线卡片“未接入 / 等待接入”,图片模型、视频模型页签标注“后续”。历史和任务里不再出现云端生成的结果。
|
||||
- 三维搭景和试验台的组织方式标签由“待确认”改为“已确认”。
|
||||
- 工作流库表格改为固定列宽,长文件名用省略号截断,1366 宽时“状态”列不再被挤出可视区。
|
||||
|
||||
## 6. 检查结果
|
||||
|
||||
- 尺寸:四套主题都检查了 1440×900、1366×768(视频首尾帧)和 1280×720(图片竖图)。主按钮在首屏、作品按比例完整显示、视频默认暂停、列表各自滚动、侧栏底部不溢出(见附图 04、05)。
|
||||
- 全站一致性:工作室、创作台(图片/视频)、智能体首页/任务、项目工作台、工作流库、模型连接、设置、规范页都只使用语义变量(附图 02、03、10–16)。
|
||||
- 自测(样本地址加 `?selftest=1`,在无界面浏览器中运行):17/17 通过,包括在四套主题之间依次切换后提示词、上传、参数、工作流、历史回看、项目阶段和智能体状态不变;切换后选择被记住;存储被禁止时仍能切换且有提示;云端未接入时生成按钮被禁用。另外验证了重新打开页面会沿用上次的选择。
|
||||
|
||||
## 7. 施工提示
|
||||
|
||||
1. 先把 v1 组件中写死的 `rgba(...)` 和十六进制颜色换成本文的语义变量(样本已完成,可直接对照)。规则是:白色叠加 → `rgb(var(--ink)/a)`;场景色/状态色叠加 → `color-mix(in srgb,var(--x) N%,transparent)`;场景色文字 → 与 `var(--hi)` 混合。
|
||||
2. 主题块的选择器写成 `[data-theme="x"]`,不要写成 `html[...]`,这样局部预览(缩略图、规范对照表)也能套用主题。
|
||||
3. 新主题须等白栖知看样确认后再正式施工;最终上线哪几套、是否保留切换入口,以他的确认为准。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
c32f1f7e6814350d2f5470e900b5a697bf8f34f02eac3837eca9a7a3fe9b25d4 /opt/aigc-home/releases/formal-v5-35fd07a.tgz
|
||||
f1fb2e4167a7e552de69f7857347ca95a1ebf0f1a5ab1d075692ccf1ae5a103b /opt/aigc-home/releases/backup-HEL665-v5-35fd07a-20261015.tgz
|
||||
8374951e292df80f43aac3425a7aaa312e59f3a0b953b45a4d051934612ff304 /opt/aigc-home/releases/rollback-HEL665-v5-35fd07a-20261015.sh
|
||||
old-source-present
|
||||
old-static-present
|
||||
@@ -0,0 +1,31 @@
|
||||
{"image_wf": 1, "video_wf": 2, "endpoint": "cba0eaa4-57f2-4f57-99b1-ba7b6f0b0835"}
|
||||
{'dual': 3, 'h3': 4, 'project': 1}
|
||||
RUN e2e/reference/check.cjs
|
||||
PASS 真实工作流显示正反向左右分栏
|
||||
PASS 工作流列表可应对超过 48 项
|
||||
PASS 列表搜索过滤真实元数据
|
||||
PASS 置顶不切换工作流、不清空草稿
|
||||
PASS 参数取消不改当前值
|
||||
PASS 参数保存应用到当前工作流
|
||||
PASS 真实生成请求提交且取得结果
|
||||
PASS 正反向与种子写入任务
|
||||
locator.click: Timeout 12000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for locator('.result-item').first()[22m
|
||||
|
||||
at /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/e2e/reference/check.cjs:146:45 {
|
||||
log: [ " - waiting for locator('.result-item').first()" ],
|
||||
name: 'TimeoutError'
|
||||
}
|
||||
RUN e2e/reference/check-copy-fallback.cjs
|
||||
locator.waitFor: Timeout 15000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for getByRole('button', { name: /编辑内容并带回项目/ }) to be visible[22m
|
||||
|
||||
at /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/e2e/reference/check-copy-fallback.cjs:44:54 {
|
||||
log: [
|
||||
" - waiting for getByRole('button', { name: /编辑内容并带回项目/ }) to be visible"
|
||||
],
|
||||
name: 'TimeoutError'
|
||||
}
|
||||
FAILED SCRIPTS ['e2e/reference/check.cjs', 'e2e/reference/check-copy-fallback.cjs']
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
> calliope-web@1.5.8 lint
|
||||
> prettier --check . && eslint .
|
||||
|
||||
Checking formatting...
|
||||
[warn] package-lock.json
|
||||
[warn] package.json
|
||||
[warn] scripts/check-storage-ssr.mjs
|
||||
[warn] src/app.html
|
||||
[warn] src/hooks.client.ts
|
||||
[warn] src/hooks.server.ts
|
||||
[warn] src/lib/actions/spotlight.ts
|
||||
[warn] src/lib/agentComposer.ts
|
||||
[warn] src/lib/agentTasks.ts
|
||||
[warn] src/lib/assetPicker.ts
|
||||
[warn] src/lib/comfy/classifyInput.ts
|
||||
[warn] src/lib/comfy/parser.ts
|
||||
[warn] src/lib/comfy/promptInput.ts
|
||||
[warn] src/lib/comfy/resolution.ts
|
||||
[warn] src/lib/comfy/types.ts
|
||||
[warn] src/lib/comfy/useUpload.svelte.ts
|
||||
[warn] src/lib/components/agent/agentPalette.ts
|
||||
[warn] src/lib/components/generate/context.ts
|
||||
[warn] src/lib/components/generate/schema.ts
|
||||
[warn] src/lib/components/generate/takeDelete.svelte.ts
|
||||
[warn] src/lib/components/generate/takes.ts
|
||||
[warn] src/lib/components/shell/nav.ts
|
||||
[warn] src/lib/components/ui/icons.ts
|
||||
[warn] src/lib/components/ui/modalLayers.ts
|
||||
[warn] src/lib/components/ui/README.md
|
||||
[warn] src/lib/dbtime.ts
|
||||
[warn] src/lib/durationBudget.ts
|
||||
[warn] src/lib/endpointKind.ts
|
||||
[warn] src/lib/events.ts
|
||||
[warn] src/lib/formOptions.ts
|
||||
[warn] src/lib/i18n.svelte.ts
|
||||
[warn] src/lib/i18n/de.ts
|
||||
[warn] src/lib/i18n/en.ts
|
||||
[warn] src/lib/i18n/es.ts
|
||||
[warn] src/lib/i18n/fr.ts
|
||||
[warn] src/lib/i18n/ja.ts
|
||||
[warn] src/lib/i18n/ko.ts
|
||||
[warn] src/lib/i18n/zh.ts
|
||||
[warn] src/lib/jobProgress.ts
|
||||
[warn] src/lib/jobStatus.ts
|
||||
[warn] src/lib/missingOutputs.svelte.ts
|
||||
[warn] src/lib/promptTemplates.ts
|
||||
[warn] src/lib/reduceMotion.svelte.ts
|
||||
[warn] src/lib/referenceAgent.ts
|
||||
[warn] src/lib/shot/api.ts
|
||||
[warn] src/lib/shot/calibration/compositionPresets.ts
|
||||
[warn] src/lib/shot/calibration/shotSolver.ts
|
||||
[warn] src/lib/shot/helpers/cameraUtils.ts
|
||||
[warn] src/lib/shot/helpers/jointConfig.ts
|
||||
[warn] src/lib/shot/helpers/mannequinFactory.ts
|
||||
[warn] src/lib/shot/helpers/mirror.ts
|
||||
[warn] src/lib/shot/helpers/posture.ts
|
||||
[warn] src/lib/shot/helpers/primitiveFactory.ts
|
||||
[warn] src/lib/shot/motion/sampleTrack.ts
|
||||
[warn] src/lib/shot/shotStore.svelte.ts
|
||||
[warn] src/lib/shot/types/mannequin-js.d.ts
|
||||
[warn] src/lib/storage.ts
|
||||
[warn] src/lib/toast.ts
|
||||
[warn] src/lib/wideLayout.ts
|
||||
[warn] src/routes/+layout.ts
|
||||
[warn] src/routes/+page.ts
|
||||
[warn] src/routes/app.css
|
||||
[warn] src/routes/project/[id]/+page.ts
|
||||
[warn] src/routes/projects/+page.ts
|
||||
[warn] svelte.config.js
|
||||
[warn] tailwind.config.js
|
||||
[warn] tsconfig.json
|
||||
[warn] vite.config.ts
|
||||
[warn] Code style issues found in 68 files. Run Prettier with --write to fix.
|
||||
@@ -0,0 +1,413 @@
|
||||
FFFFF [100%]
|
||||
=================================== FAILURES ===================================
|
||||
________________________ test_comfy_server_info_scoping ________________________
|
||||
|
||||
def test_comfy_server_info_scoping():
|
||||
"""Native health check stays visible in both blind and linked sessions."""
|
||||
from calliope.agent.harness import tools as harness_tools
|
||||
|
||||
blind = ToolContext(session_id=1, project_id=None)
|
||||
linked = ToolContext(session_id=1, project_id=99)
|
||||
|
||||
> blind_names = {e["function"]["name"] for e in harness_tools.openai_tools_payload(blind)}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
tests/test_agent_comfy_mcp.py:370:
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
src/calliope/agent/harness/tools.py:27: in openai_tools_payload
|
||||
return _registry.openai_payload(ctx)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/registry.py:219: in openai_payload
|
||||
if self._visible(t, ctx)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/registry.py:203: in _visible
|
||||
if not user_allows_render(ctx):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:156: in user_allows_render
|
||||
if has_structured_approval(ctx, "render"):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:277: in has_structured_approval
|
||||
answer = latest_answer(ctx.session_id)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:260: in latest_answer
|
||||
events = read_events(session_id)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|
||||
session_id = 1
|
||||
|
||||
def read_events(session_id: int) -> list[SessionEvent]:
|
||||
conn = _db()
|
||||
try:
|
||||
> rows = conn.execute(
|
||||
"SELECT * FROM agent_events WHERE session_id = ? ORDER BY seq", (session_id,)
|
||||
).fetchall()
|
||||
E sqlite3.OperationalError: no such table: agent_events
|
||||
|
||||
src/calliope/agent/harness/log.py:146: OperationalError
|
||||
----------------------------- Captured stderr call -----------------------------
|
||||
2026-10-21 20:00:31,637 | INFO | calliope.harness | Harness composed: 79 tools
|
||||
------------------------------ Captured log call -------------------------------
|
||||
INFO calliope.harness:__init__.py:214 Harness composed: 79 tools
|
||||
___________ test_h3_messages_bind_neighbor_shots_and_keep_file_slots ___________
|
||||
|
||||
def test_h3_messages_bind_neighbor_shots_and_keep_file_slots():
|
||||
from calliope.agent.prompts import build_minimax_h3_ref_messages
|
||||
from calliope.agent.video_agent import resolve_h3_references
|
||||
from calliope.comfyui.parser import parse_dynamic_inputs
|
||||
|
||||
plan = {
|
||||
"overview": {"style": "noir", "lighting": "sodium"},
|
||||
"requirements": {"lighting": "sodium lamps only"},
|
||||
"shots": [
|
||||
{
|
||||
"clip_id": 1,
|
||||
"window": "00:00.000-00:04.000",
|
||||
"action": "enter",
|
||||
"camera": "push in",
|
||||
"lighting": "dim sodium",
|
||||
"speakers": "MAYA: hello",
|
||||
"spatial": "screen left",
|
||||
"state_after": "door open",
|
||||
},
|
||||
{
|
||||
"clip_id": 2,
|
||||
"window": "00:04.000-00:08.000",
|
||||
"action": "turn",
|
||||
"camera": "hold",
|
||||
"lighting": "dim sodium",
|
||||
"speakers": "",
|
||||
"spatial": "screen left",
|
||||
"state_after": "",
|
||||
},
|
||||
{
|
||||
"clip_id": 3,
|
||||
"window": "00:08.000-00:12.000",
|
||||
"action": "leave",
|
||||
"camera": "pull out",
|
||||
"lighting": "brighter",
|
||||
"speakers": "",
|
||||
"spatial": "",
|
||||
"state_after": "hallway empty",
|
||||
},
|
||||
],
|
||||
}
|
||||
lock = continuity_lock_text(plan, 2)
|
||||
assert "Previous shot" in lock
|
||||
assert "Next shot" in lock
|
||||
assert "Do not recast a subject" in lock
|
||||
assert "screen direction" in lock
|
||||
assert "enter" in lock and "leave" in lock
|
||||
|
||||
scene = {"heading": "INT. HALL", "action": "She turns.", "duration_sec": 4, "dialog": ""}
|
||||
subjects = [
|
||||
{
|
||||
"index": 1,
|
||||
"kind": "reference",
|
||||
"name": "mercs",
|
||||
"appearance": "",
|
||||
"path": r"E:\assets\mercs.png",
|
||||
}
|
||||
]
|
||||
messages = build_minimax_h3_ref_messages(scene, subjects, continuity=lock)
|
||||
text = messages[1]["content"]
|
||||
assert "Previous shot" in text
|
||||
assert "Next shot" in text
|
||||
assert "screen direction" in text
|
||||
assert "do not substitute another character or location" in text
|
||||
|
||||
workflow = {
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
}
|
||||
inputs = parse_dynamic_inputs(workflow)
|
||||
resolved, paths, _videos = resolve_h3_references(
|
||||
inputs,
|
||||
{"148": r"E:\assets\hero.png", "149": r"E:\assets\mercs.png"},
|
||||
[{"name": "Maya", "appearance": "olive jacket", "sheet_path": r"E:\assets\maya.png"}],
|
||||
{"name": "Metro Line", "description": "rain-slick rooftops"},
|
||||
r"E:\assets\metro.png",
|
||||
)
|
||||
> assert resolved[1]["name"] == "mercs"
|
||||
E AssertionError: assert 'E:\\assets\\mercs' == 'mercs'
|
||||
E
|
||||
E - mercs
|
||||
E + E:\assets\mercs
|
||||
|
||||
tests/test_continuity.py:249: AssertionError
|
||||
___________ test_resolve_h3_references_prefers_form_files_over_story ___________
|
||||
|
||||
def test_resolve_h3_references_prefers_form_files_over_story():
|
||||
"""Slot files the user picked replace the story cast; empty slots keep it."""
|
||||
from calliope.agent.video_agent import resolve_h3_references
|
||||
from calliope.comfyui.parser import parse_dynamic_inputs
|
||||
|
||||
workflow = {
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
"150": {
|
||||
"class_type": "LoadVideo",
|
||||
"inputs": {"video": ""},
|
||||
"_meta": {"title": "Motion (Input:video)"},
|
||||
},
|
||||
}
|
||||
inputs = parse_dynamic_inputs(workflow)
|
||||
characters = [
|
||||
{
|
||||
"name": "Maya",
|
||||
"appearance": "olive jacket",
|
||||
"sheet_path": r"E:\assets\maya.png",
|
||||
}
|
||||
]
|
||||
location = {"name": "Metro Line", "description": "rain-slick rooftops"}
|
||||
loc_image = r"E:\assets\metro.png"
|
||||
|
||||
empty_subjects, empty_paths, empty_videos = resolve_h3_references(
|
||||
inputs, {}, characters, location, loc_image
|
||||
)
|
||||
assert [s["name"] for s in empty_subjects] == ["Maya", "Metro Line"]
|
||||
assert empty_paths == [r"E:\assets\maya.png", r"E:\assets\metro.png"]
|
||||
assert empty_videos == []
|
||||
|
||||
subjects, paths, videos = resolve_h3_references(
|
||||
inputs,
|
||||
{
|
||||
"148": r"E:\assets\maya.png",
|
||||
"149": r"E:\assets\mercs.png",
|
||||
"150": r"E:\assets\fight.mp4",
|
||||
},
|
||||
characters,
|
||||
location,
|
||||
loc_image,
|
||||
)
|
||||
assert subjects[0]["kind"] == "character"
|
||||
assert subjects[0]["name"] == "Maya"
|
||||
assert subjects[1]["kind"] == "reference"
|
||||
> assert subjects[1]["name"] == "mercs"
|
||||
E AssertionError: assert 'E:\\assets\\mercs' == 'mercs'
|
||||
E
|
||||
E - mercs
|
||||
E + E:\assets\mercs
|
||||
|
||||
tests/test_h3_profile.py:215: AssertionError
|
||||
___________ test_preview_prompt_uses_form_references_not_story_cast ____________
|
||||
|
||||
client = <starlette.testclient.TestClient object at 0x7f3b525d3830>
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f3b525d0c80>
|
||||
|
||||
def test_preview_prompt_uses_form_references_not_story_cast(client, monkeypatch):
|
||||
"""The Video-tab image and video slots are the prompt's subjects.
|
||||
|
||||
Story character + location text must not replace files the user picked,
|
||||
and Regenerate (force) must not return a draft written before those files.
|
||||
"""
|
||||
pid = _mk_project(client, "Preview refs")
|
||||
scene = _add_scene(client, pid, 1, action="She swings the extinguisher.")
|
||||
clip_id = _scene_default_clip(pid, scene["id"])
|
||||
|
||||
wf = {
|
||||
"10": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"inputs": {"text": ""},
|
||||
"_meta": {"title": "Main Prompt (Input:prompt)"},
|
||||
},
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
"150": {
|
||||
"class_type": "LoadVideo",
|
||||
"inputs": {"video": ""},
|
||||
"_meta": {"title": "Motion (Input:video)"},
|
||||
},
|
||||
}
|
||||
conn = get_db(settings.db_path)
|
||||
try:
|
||||
cur = conn.execute(
|
||||
"""
|
||||
INSERT INTO workflows (name, kind, workflow_json, input_schema, output_schema,
|
||||
prompt_profile, is_enabled)
|
||||
VALUES (?, 'video', ?, '[]', '[]', 'minimax_h3_ref', 1)
|
||||
""",
|
||||
("H3 refs", json.dumps(wf)),
|
||||
)
|
||||
wf_id = cur.lastrowid
|
||||
char = conn.execute(
|
||||
"""
|
||||
INSERT INTO characters (project_id, name, appearance, sheet_path)
|
||||
VALUES (?, 'Maya', 'olive jacket', ?)
|
||||
""",
|
||||
(pid, r"E:\story\maya-sheet.png"),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO scene_characters (scene_id, character_id) VALUES (?, ?)",
|
||||
(scene["id"], char.lastrowid),
|
||||
)
|
||||
loc = conn.execute(
|
||||
"""
|
||||
INSERT INTO locations (project_id, name, description, reference_image_path)
|
||||
VALUES (?, 'Metro Line', 'rain-slick rooftops', ?)
|
||||
""",
|
||||
(pid, r"E:\story\metro.png"),
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE scenes SET location_id = ? WHERE id = ?",
|
||||
(loc.lastrowid, scene["id"]),
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE clips SET workflow_id = ? WHERE id = ?", (wf_id, clip_id)
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
seen: dict = {}
|
||||
|
||||
async def fake_rewrite(scene_, subjects, **kwargs):
|
||||
seen["subjects"] = subjects
|
||||
seen["videos"] = kwargs.get("videos")
|
||||
seen["calls"] = seen.get("calls", 0) + 1
|
||||
return "REWRITE FROM REFS"
|
||||
|
||||
monkeypatch.setattr("calliope.agent.video_agent._h3_rewrite", fake_rewrite)
|
||||
|
||||
form = {
|
||||
"148": r"E:\refs\hero.png",
|
||||
"149": r"E:\refs\mercs.png",
|
||||
"150": r"E:\refs\fight.mp4",
|
||||
}
|
||||
r = client.post(
|
||||
f"/api/jobs/projects/{pid}/preview-prompt",
|
||||
json={"clip_id": clip_id, "input_values": form},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["prompt"] == "REWRITE FROM REFS"
|
||||
assert body["from_draft"] is False
|
||||
names = [s["name"] for s in seen["subjects"]]
|
||||
> assert names == ["hero", "mercs"]
|
||||
E AssertionError: assert ['E:\\refs\\h...\refs\\mercs'] == ['hero', 'mercs']
|
||||
E
|
||||
E At index 0 diff: 'E:\\refs\\hero' != 'hero'
|
||||
E Use -v to get more diff
|
||||
|
||||
tests/test_scene_settings.py:487: AssertionError
|
||||
---------------------------- Captured stderr setup -----------------------------
|
||||
2026-10-21 20:00:31,702 | INFO | calliope | Calliope started — db=/tmp/multica-task-3084682389/tmpj2vinw90/calliope.db dry_run=True
|
||||
2026-10-21 20:00:31,702 | INFO | calliope.worker | Queue worker started
|
||||
------------------------------ Captured log setup ------------------------------
|
||||
INFO calliope:main.py:112 Calliope started — db=/tmp/multica-task-3084682389/tmpj2vinw90/calliope.db dry_run=True
|
||||
INFO calliope.worker:worker.py:79 Queue worker started
|
||||
----------------------------- Captured stderr call -----------------------------
|
||||
2026-10-21 20:00:31,707 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
2026-10-21 20:00:31,721 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects/1/scenes "HTTP/1.1 200 OK"
|
||||
2026-10-21 20:00:31,733 | INFO | httpx2 | HTTP Request: POST http://testserver/api/jobs/projects/1/preview-prompt "HTTP/1.1 200 OK"
|
||||
------------------------------ Captured log call -------------------------------
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects/1/scenes "HTTP/1.1 200 OK"
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/jobs/projects/1/preview-prompt "HTTP/1.1 200 OK"
|
||||
--------------------------- Captured stderr teardown ---------------------------
|
||||
2026-10-21 20:00:32,204 | INFO | calliope.worker | Queue worker stopped
|
||||
2026-10-21 20:00:32,204 | INFO | calliope | Calliope shutting down
|
||||
---------------------------- Captured log teardown -----------------------------
|
||||
INFO calliope.worker:worker.py:185 Queue worker stopped
|
||||
INFO calliope:main.py:118 Calliope shutting down
|
||||
_________________ test_script_regenerate_keeps_expanded_count __________________
|
||||
|
||||
client = <starlette.testclient.TestClient object at 0x7f3b524d76b0>
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f3b525d2180>
|
||||
|
||||
def test_script_regenerate_keeps_expanded_count(client, monkeypatch):
|
||||
calls: list[int] = []
|
||||
|
||||
async def fake_structured(messages, temperature=0.7):
|
||||
user = messages[1]["content"]
|
||||
# Parse required count from prompt
|
||||
n = 4
|
||||
for line in user.splitlines():
|
||||
if line.startswith("required_scene_count:"):
|
||||
n = int(line.split(":", 1)[1].strip())
|
||||
break
|
||||
calls.append(n)
|
||||
return {
|
||||
"scenes": [
|
||||
{
|
||||
"order_index": i,
|
||||
"heading": f"SCENE {i}",
|
||||
"action": f"action {i}",
|
||||
"dialog": "",
|
||||
"duration_sec": 5,
|
||||
"character_ids": [],
|
||||
"location_id": None,
|
||||
}
|
||||
for i in range(1, n + 1)
|
||||
]
|
||||
}
|
||||
|
||||
monkeypatch.setattr("calliope.agent.script_agent.generate_structured", fake_structured)
|
||||
|
||||
r = client.post("/api/projects", json={"title": "Expand", "idea": "desert", "target_duration": "30 seconds"})
|
||||
pid = r.json()["id"]
|
||||
|
||||
# Seed 4 scenes via generate
|
||||
r = client.post(f"/api/projects/{pid}/generate-script", json={"replace": True})
|
||||
> assert r.status_code == 200
|
||||
E assert 500 == 200
|
||||
E + where 500 = <Response [500 Internal Server Error]>.status_code
|
||||
|
||||
tests/test_script_scene_count.py:59: AssertionError
|
||||
---------------------------- Captured stderr setup -----------------------------
|
||||
2026-10-21 20:00:32,234 | INFO | calliope | Calliope started — db=/tmp/multica-task-3084682389/tmp2hqlzdiy/calliope.db dry_run=True
|
||||
2026-10-21 20:00:32,234 | INFO | calliope.worker | Queue worker started
|
||||
------------------------------ Captured log setup ------------------------------
|
||||
INFO calliope:main.py:112 Calliope started — db=/tmp/multica-task-3084682389/tmp2hqlzdiy/calliope.db dry_run=True
|
||||
INFO calliope.worker:worker.py:79 Queue worker started
|
||||
----------------------------- Captured stderr call -----------------------------
|
||||
2026-10-21 20:00:32,238 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
2026-10-21 20:00:32,264 | INFO | calliope.llm | LLM stream request to http://127.0.0.1:11434/v1/chat/completions with model llama3.2
|
||||
2026-10-21 20:00:32,266 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects/1/generate-script "HTTP/1.1 500 Internal Server Error"
|
||||
------------------------------ Captured log call -------------------------------
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
INFO calliope.llm:llm.py:360 LLM stream request to http://127.0.0.1:11434/v1/chat/completions with model llama3.2
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects/1/generate-script "HTTP/1.1 500 Internal Server Error"
|
||||
--------------------------- Captured stderr teardown ---------------------------
|
||||
2026-10-21 20:00:32,735 | INFO | calliope.worker | Queue worker stopped
|
||||
2026-10-21 20:00:32,736 | INFO | calliope | Calliope shutting down
|
||||
---------------------------- Captured log teardown -----------------------------
|
||||
INFO calliope.worker:worker.py:185 Queue worker stopped
|
||||
INFO calliope:main.py:118 Calliope shutting down
|
||||
=============================== warnings summary ===============================
|
||||
../../aigc-home/calliope-backend/.venv/lib/python3.12/site-packages/starlette/testclient.py:53
|
||||
/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/calliope-backend/.venv/lib/python3.12/site-packages/starlette/testclient.py:53: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
|
||||
_PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]
|
||||
|
||||
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
||||
=========================== short test summary info ============================
|
||||
FAILED tests/test_agent_comfy_mcp.py::test_comfy_server_info_scoping - sqlite...
|
||||
FAILED tests/test_continuity.py::test_h3_messages_bind_neighbor_shots_and_keep_file_slots
|
||||
FAILED tests/test_h3_profile.py::test_resolve_h3_references_prefers_form_files_over_story
|
||||
FAILED tests/test_scene_settings.py::test_preview_prompt_uses_form_references_not_story_cast
|
||||
FAILED tests/test_script_scene_count.py::test_script_regenerate_keeps_expanded_count
|
||||
5 failed, 1 warning in 1.19s
|
||||
@@ -0,0 +1,33 @@
|
||||
# HEL-728 B0 版本核实与回退记录
|
||||
|
||||
核实日期:2026-10-21。服务器仅执行只读查询;未部署、重启服务或修改配置/数据。
|
||||
|
||||
| 对象 | 精确版本 / 结论 |
|
||||
| --- | --- |
|
||||
| `origin/main` | `1fc8bdb8bb2a88ccace6f21a507fd77bcf22f532` |
|
||||
| `origin/deploy/hel-691` | `2b3bbf9`,是第五版的祖先,不是当前部署版本 |
|
||||
| `origin/feat/hel-665-refract`、PR #1 head | `35fd07af24e62add1f96f6a9c38e363f8e23d778` |
|
||||
| 当前测试站 | `DEPLOYED_REVISION` 标为第五版 `35fd07a`;前端 191 文件、后端 79 个 Python 文件逐项 SHA-256 全匹配该提交 |
|
||||
| 静态构建 | 当前 static 与 `stage-HEL665-v5-35fd07a-20261015/build` 全目录 `diff -qr` 无差异;两份 index.html 的 SHA-256 均为 `acd3ba6e0ab29b92f5133358398f3544baa0ce2bea03560004a42e812b6abc8a` |
|
||||
| PR #1 | https://gitea.xbay.cc/leefer/aigc-home/pulls/1 :open、未合并、目标 main、head=35fd07a |
|
||||
| B0 底稿 | 从完整第五版另开 `feat/hel-728-night-foundation`,没有合并旧 PR 或更改 main |
|
||||
|
||||
第五版领先 main 22 个提交、领先 deploy/hel-691 10 个提交。HEL-692、HEL-695 的实装和后续修复均在该祖先链上:从 aaddd3d 到 35fd07a 的创作草稿/端点归属、手动播放、智能体编辑成果、阶段建议与确认隔离保留。第五版也完整包含 HEL-681/682 批量导入和 HEL-684 生成结果回流。
|
||||
|
||||
HEL-727 把两个 API 返回 422 作为部署版本依据的结论已由源码/发布包实证纠正。当前差异均已解释,没有以旧 deploy 分支覆盖后续工作。
|
||||
|
||||
本任务专用检出初始 `git status --short` 为空,无未提交/未推送工作被覆盖。服务器应用目录不是 Git 检出,以全部源码哈希替代 git status 核实,没有发现与第五版不同的产品源码。已有 `.before-*` 和发布备份保留。未触碰其他任务私有工作区。
|
||||
|
||||
本地保全引用:`backup/hel-728-main-1fc8bdb` 与 `backup/hel-728-v5-35fd07a`。完整证据见同目录 `server-audit.txt`、`server-backend.txt`、`backup-hashes.txt`。
|
||||
|
||||
## 已存在的服务器备份
|
||||
|
||||
目录 `/opt/aigc-home/releases`:
|
||||
|
||||
- `formal-v5-35fd07a.tgz`:当前第五版发布包。
|
||||
- `backup-HEL665-v5-35fd07a-20261015.tgz`:部署第五版之前的静态页、前端源码、workbench 路由及版本标记。
|
||||
- `rollback-HEL665-v5-35fd07a-20261015.sh`:第五版回退脚本,旧源码/静态目录均仍存在。**此脚本会回到第五版之前,不能当成本批将来的回退脚本。**
|
||||
|
||||
备份和脚本哈希已留档。本批尚未部署,因此当前站点无需回退。后续由总工部署 B0 时,须先重新核对当前源码/构建哈希及活动任务,并备份当前第五版,才能替换 B0 静态页、前端源码和新增的 app.html/themes.css。B0 回退应恢复这份第五版完整备份;无需数据库回退。本批无后端、数据迁移或用户配置改动。
|
||||
|
||||
代码回退:以 `35fd07af24e62add1f96f6a9c38e363f8e23d778` 为基线重新构建第五版,或恢复总工部署前生成的完整备份。不要只切回 `deploy/hel-691`。
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"checks": [
|
||||
"默认主题为夜片场",
|
||||
"night 保留原编辑组件和正反向草稿",
|
||||
"day 保留原编辑组件和正反向草稿",
|
||||
"grade 保留原编辑组件和正反向草稿",
|
||||
"bluehour 保留原编辑组件和正反向草稿",
|
||||
"刷新恢复主题和草稿",
|
||||
"方向键移动主题选项焦点",
|
||||
"Esc 关闭并恢复入口焦点",
|
||||
"创作台兼容入口保留全部参数及片段",
|
||||
"隔离真实队列已收到任务",
|
||||
"night 上传素材和运行中编辑状态保留",
|
||||
"day 上传素材和运行中编辑状态保留",
|
||||
"grade 上传素材和运行中编辑状态保留",
|
||||
"bluehour 上传素材和运行中编辑状态保留",
|
||||
"切主题后原任务完成且产物归属不变",
|
||||
"切主题保留视频节点和暂停状态",
|
||||
"切主题保留智能体任务输入组件和草稿",
|
||||
"切主题保留未保存设置",
|
||||
"1440,900 night 导航入口和四主题完整可见",
|
||||
"1440,900 day 导航入口和四主题完整可见",
|
||||
"1440,900 grade 导航入口和四主题完整可见",
|
||||
"1440,900 bluehour 导航入口和四主题完整可见",
|
||||
"1366,768 night 导航入口和四主题完整可见",
|
||||
"1366,768 day 导航入口和四主题完整可见",
|
||||
"1366,768 grade 导航入口和四主题完整可见",
|
||||
"1366,768 bluehour 导航入口和四主题完整可见",
|
||||
"1280,720 night 导航入口和四主题完整可见",
|
||||
"1280,720 day 导航入口和四主题完整可见",
|
||||
"1280,720 grade 导航入口和四主题完整可见",
|
||||
"1280,720 bluehour 导航入口和四主题完整可见",
|
||||
"模型连接入口保留页签参数",
|
||||
"旧项目链接保留阶段参数",
|
||||
"全局搜索保留 视频创作",
|
||||
"全局搜索保留 大语言模型",
|
||||
"全局搜索保留 试验台",
|
||||
"全局搜索保留 三维搭景",
|
||||
"night 首次绘制前恢复主题及底色",
|
||||
"day 首次绘制前恢复主题及底色",
|
||||
"grade 首次绘制前恢复主题及底色",
|
||||
"bluehour 首次绘制前恢复主题及底色",
|
||||
"存储被禁用仍可切换且显示提示",
|
||||
"存储被禁用保留输入",
|
||||
"无效存储回退夜片场",
|
||||
"浏览器无运行错误"
|
||||
],
|
||||
"errors": []
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
|
||||
> calliope-web@1.5.8 build
|
||||
> vite build
|
||||
|
||||
vite v6.4.3 building SSR bundle for production...
|
||||
transforming...
|
||||
8:10:50 PM [vite-plugin-svelte] src/lib/components/workbench/ShotStagePanel.svelte:156:5 `<video>` elements must have a `<track kind="captions">`
|
||||
https://svelte.dev/e/a11y_media_has_caption
|
||||
154: {#if shot.description}<p class="vshot-desc">{shot.description}</p>{/if}
|
||||
155: {#if shot.job?.status === 'done' && shot.job.output}
|
||||
156: <video
|
||||
^
|
||||
157: class="vshot-video"
|
||||
158: src={assetUrl(shot.job.output) ?? undefined}
|
||||
"handleConnectionChange" and "handleAttributionWarning" are imported from external module "@xyflow/system" but never used in "node_modules/@xyflow/svelte/dist/lib/hooks/useNodeConnections.svelte.js", "node_modules/@xyflow/svelte/dist/lib/components/Handle/Handle.svelte" and "node_modules/@xyflow/svelte/dist/lib/components/Attribution/Attribution.svelte".
|
||||
✓ 533 modules transformed.
|
||||
rendering chunks...
|
||||
vite v6.4.3 building for production...
|
||||
transforming...
|
||||
8:10:53 PM [vite-plugin-svelte] src/lib/components/workbench/ShotStagePanel.svelte:156:5 `<video>` elements must have a `<track kind="captions">`
|
||||
https://svelte.dev/e/a11y_media_has_caption
|
||||
154: {#if shot.description}<p class="vshot-desc">{shot.description}</p>{/if}
|
||||
155: {#if shot.job?.status === 'done' && shot.job.output}
|
||||
156: <video
|
||||
^
|
||||
157: class="vshot-video"
|
||||
158: src={assetUrl(shot.job.output) ?? undefined}
|
||||
✓ 778 modules transformed.
|
||||
rendering chunks...
|
||||
computing gzip size...
|
||||
.svelte-kit/output/client/_app/version.json 0.03 kB │ gzip: 0.05 kB
|
||||
.svelte-kit/output/client/.vite/manifest.json 28.72 kB │ gzip: 3.35 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/reduceMotion.BrXLPzfy.css 0.08 kB │ gzip: 0.10 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/14.IyyrLGyK.css 0.22 kB │ gzip: 0.15 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/6.C62bpzl4.css 0.22 kB │ gzip: 0.15 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/Skeleton.BQeWIsLh.css 0.39 kB │ gzip: 0.22 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/SafeMedia.Cf_dgjFv.css 0.51 kB │ gzip: 0.31 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/EmptyState.BXjpyO2u.css 0.58 kB │ gzip: 0.31 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/Spinner.us8fwMZC.css 0.73 kB │ gzip: 0.37 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/ConfirmDialog.DOfiQL0c.css 0.91 kB │ gzip: 0.38 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/ProgressBar.DG8dH-U_.css 1.44 kB │ gzip: 0.58 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/22.ChQ8T8dK.css 1.50 kB │ gzip: 0.56 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/20.D7w-Sx1Y.css 1.66 kB │ gzip: 0.55 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/AgentPlanPanel.BMGRQZdH.css 2.24 kB │ gzip: 0.74 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/ImageLightbox.DN4QbnbA.css 2.55 kB │ gzip: 0.76 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/types.DUMMEwmy.css 4.86 kB │ gzip: 1.13 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/17.CdHWgDYY.css 4.90 kB │ gzip: 1.33 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/AgentComposer.BhJ_F-aX.css 4.90 kB │ gzip: 1.31 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/18.D3s-Wa9z.css 5.02 kB │ gzip: 1.31 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/WorkflowBay.CrZOCTCD.css 5.20 kB │ gzip: 1.40 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/AProjectCard.BhK9fW6H.css 5.39 kB │ gzip: 1.47 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/11.CpN-OyyL.css 5.63 kB │ gzip: 1.45 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/8.BK-8H9u5.css 9.05 kB │ gzip: 2.13 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/3.CxKDlY5x.css 9.73 kB │ gzip: 2.04 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/AgentChat.C5wVAvmg.css 11.44 kB │ gzip: 2.53 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/13.DdkN80tf.css 11.76 kB │ gzip: 2.55 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/AppShell.Bk5S4WfJ.css 14.10 kB │ gzip: 3.27 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/5.DoWQHLuE.css 15.17 kB │ gzip: 3.13 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/0.C2N0LW81.css 19.69 kB │ gzip: 3.99 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/WorkflowLibrary.CN-_i5Sc.css 27.67 kB │ gzip: 4.81 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/4.BQ063dE_.css 29.80 kB │ gzip: 5.74 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/7.B1E9ZlPG.css 29.94 kB │ gzip: 5.07 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/21.BY02oOwl.css 30.01 kB │ gzip: 4.94 kB
|
||||
.svelte-kit/output/client/_app/immutable/assets/StudioDesk.DiLnYEIx.css 31.15 kB │ gzip: 6.17 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/5.hx3kxUVa.js 0.09 kB │ gzip: 0.10 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Bzak7iHL.js 0.10 kB │ gzip: 0.10 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/IKQcdn9t.js 0.12 kB │ gzip: 0.12 kB
|
||||
.svelte-kit/output/client/_app/immutable/entry/start.BUwQ6lIJ.js 0.12 kB │ gzip: 0.11 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/B0XwC4Ot.js 0.15 kB │ gzip: 0.14 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BsCRBkET.js 0.18 kB │ gzip: 0.16 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Sbfne8nC.js 0.19 kB │ gzip: 0.17 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/FwfFJvU_.js 0.19 kB │ gzip: 0.16 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/DEfCzHLx.js 0.23 kB │ gzip: 0.18 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Ba1assjq.js 0.26 kB │ gzip: 0.22 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/16.sWMaj3Bi.js 0.26 kB │ gzip: 0.23 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BXFzAH0P.js 0.28 kB │ gzip: 0.18 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/15.DYsaZg84.js 0.29 kB │ gzip: 0.25 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CK7WZZfM.js 0.31 kB │ gzip: 0.18 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/12.CF9Zu6pN.js 0.33 kB │ gzip: 0.27 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/9.BVfZlOMu.js 0.34 kB │ gzip: 0.28 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/2.BDtoJguU.js 0.37 kB │ gzip: 0.25 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BWaKaORA.js 0.37 kB │ gzip: 0.26 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/1.Bm5c1i2N.js 0.40 kB │ gzip: 0.28 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/10.DPw0t24L.js 0.41 kB │ gzip: 0.26 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/19.EN81mzhv.js 0.41 kB │ gzip: 0.26 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/6n2EhuN1.js 0.46 kB │ gzip: 0.30 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/DNKIhv1n.js 0.47 kB │ gzip: 0.34 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BpBwGJjl.js 0.49 kB │ gzip: 0.34 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/-UyI9lYi.js 0.51 kB │ gzip: 0.30 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/D41pZ3kD.js 0.56 kB │ gzip: 0.32 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/5hKhZLI5.js 0.62 kB │ gzip: 0.36 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BXakyGcx.js 0.71 kB │ gzip: 0.43 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/8OLyFVGd.js 0.75 kB │ gzip: 0.42 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CN9eJxB2.js 0.76 kB │ gzip: 0.42 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CNhvvmZJ.js 0.83 kB │ gzip: 0.42 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/DCtQckrV.js 1.09 kB │ gzip: 0.62 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/14.CvNq-suX.js 1.09 kB │ gzip: 0.66 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/6.BpRKot_7.js 1.20 kB │ gzip: 0.71 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Dp1pzeXC.js 1.27 kB │ gzip: 0.73 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/wbPk3Yxo.js 1.37 kB │ gzip: 0.66 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/D3mdsp0g.js 1.43 kB │ gzip: 0.66 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/PEmPcvxY.js 1.49 kB │ gzip: 0.78 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/whH4D4QZ.js 1.49 kB │ gzip: 0.75 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/LuZC9yWf.js 1.99 kB │ gzip: 1.05 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/t712vir_.js 2.24 kB │ gzip: 0.99 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/20.COu3iy7d.js 2.37 kB │ gzip: 1.38 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/C5fjXKkg.js 2.47 kB │ gzip: 1.12 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BPNbeFLK.js 2.77 kB │ gzip: 1.28 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/22.C5Nwx_zE.js 2.92 kB │ gzip: 1.61 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CnYh2b86.js 2.95 kB │ gzip: 1.24 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Bie-hupT.js 3.08 kB │ gzip: 1.57 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/DK7AMg8o.js 3.23 kB │ gzip: 1.55 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/DDlx89yg.js 4.27 kB │ gzip: 1.51 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/C1VtnVx0.js 6.86 kB │ gzip: 3.09 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BFgrkAWo.js 8.09 kB │ gzip: 3.27 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/PWQRmEWD.js 10.09 kB │ gzip: 2.31 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/18.Dqn9lNj5.js 10.20 kB │ gzip: 3.92 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CELneDUs.js 10.41 kB │ gzip: 4.44 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/0.B9UHNpdV.js 11.98 kB │ gzip: 4.40 kB
|
||||
.svelte-kit/output/client/_app/immutable/entry/app.BgS0U9Aq.js 12.58 kB │ gzip: 4.11 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/StFt4UCs.js 14.41 kB │ gzip: 5.54 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/11.CYMf0Aop.js 17.10 kB │ gzip: 6.44 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CHDY03l9.js 17.32 kB │ gzip: 6.96 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CI5J-U9v.js 17.44 kB │ gzip: 6.33 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/3.lt50pTEv.js 19.56 kB │ gzip: 6.87 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Cj6gCTdL.js 20.25 kB │ gzip: 7.21 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/8.c25p5xbs.js 21.27 kB │ gzip: 7.28 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/17.C8PkQczY.js 23.50 kB │ gzip: 7.73 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Dmrd7xQR.js 23.98 kB │ gzip: 9.32 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/13.CGct_Wju.js 24.87 kB │ gzip: 8.36 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/CKnAzW_q.js 36.67 kB │ gzip: 14.42 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BwCNePTm.js 41.30 kB │ gzip: 15.68 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BR687OLR.js 49.24 kB │ gzip: 17.84 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/4.C6iXVhZu.js 50.59 kB │ gzip: 17.70 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/21.Cz9clG7U.js 54.65 kB │ gzip: 15.14 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Bmp6xnce.js 71.50 kB │ gzip: 26.91 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/C5t8Nts6.js 87.12 kB │ gzip: 27.47 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/Bvurq_58.js 92.46 kB │ gzip: 32.40 kB
|
||||
.svelte-kit/output/client/_app/immutable/nodes/7.D95zSIUA.js 211.51 kB │ gzip: 68.00 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/BQUFPnBP.js 684.72 kB │ gzip: 180.05 kB
|
||||
.svelte-kit/output/client/_app/immutable/chunks/vMwlJ6hm.js 774.61 kB │ gzip: 226.22 kB
|
||||
|
||||
(!) Some chunks are larger than 500 kB after minification. Consider:
|
||||
- Using dynamic import() to code-split the application
|
||||
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
|
||||
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
|
||||
✓ built in 3.57s
|
||||
.svelte-kit/output/server/.vite/manifest.json 25.84 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/Icon.BrXLPzfy.css 0.08 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.C62bpzl4.css 0.22 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.IyyrLGyK.css 0.22 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/Skeleton.BQeWIsLh.css 0.39 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/SafeMedia.Cf_dgjFv.css 0.51 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/EmptyState.BXjpyO2u.css 0.58 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/Spinner.us8fwMZC.css 0.73 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/ConfirmDialog.C_pBcjz1.css 0.89 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/ProgressBar.DG8dH-U_.css 1.44 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.ChQ8T8dK.css 1.50 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.D7w-Sx1Y.css 1.66 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/AgentPlanPanel.BMGRQZdH.css 2.24 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/ImageLightbox.DhBJATfN.css 2.53 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.Bn3DGoQS.css 3.55 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/AgentComposer.JZyE_n9K.css 4.85 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/RefImageGrid.DUMMEwmy.css 4.86 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.D3s-Wa9z.css 5.02 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/WorkflowBay.CrZOCTCD.css 5.20 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/AProjectCard.BHJv_kAx.css 5.30 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.CpN-OyyL.css 5.63 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.u1ByS4kk.css 9.02 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.k-tm080m.css 9.35 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.CxKDlY5x.css 9.73 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/AgentChat.DGaLhJTa.css 11.41 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.CHFzkBke.css 11.66 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/AppShell.q20u3EwN.css 14.02 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_layout.MRWQDt5E.css 19.46 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/WorkflowLibrary.QeU6Pxlx.css 27.65 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.BPi-Y6Y8.css 29.59 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.UfnkmHg7.css 29.89 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/_page.BY02oOwl.css 30.01 kB
|
||||
.svelte-kit/output/server/_app/immutable/assets/StudioDesk.y8URPnQJ.css 31.03 kB
|
||||
.svelte-kit/output/server/entries/pages/build-scene/_page.ts.js 0.04 kB
|
||||
.svelte-kit/output/server/entries/pages/canvas/_page.ts.js 0.04 kB
|
||||
.svelte-kit/output/server/entries/pages/canvas/_id_/_page.ts.js 0.04 kB
|
||||
.svelte-kit/output/server/entries/pages/playground/_page.ts.js 0.04 kB
|
||||
.svelte-kit/output/server/entries/pages/workflows/_page.ts.js 0.04 kB
|
||||
.svelte-kit/output/server/entries/pages/_layout.ts.js 0.06 kB
|
||||
.svelte-kit/output/server/entries/pages/agents/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/library/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/models/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/settings/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/workbench/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/workbench/_id_/_page.ts.js 0.08 kB
|
||||
.svelte-kit/output/server/entries/pages/_page.ts.js 0.12 kB
|
||||
.svelte-kit/output/server/entries/hooks.server.js 0.13 kB
|
||||
.svelte-kit/output/server/entries/pages/projects/_page.ts.js 0.21 kB
|
||||
.svelte-kit/output/server/chunks/index-server.js 0.22 kB
|
||||
.svelte-kit/output/server/env.js 0.23 kB
|
||||
.svelte-kit/output/server/entries/pages/project/_id_/_page.ts.js 0.26 kB
|
||||
.svelte-kit/output/server/entries/pages/create/_page.ts.js 0.30 kB
|
||||
.svelte-kit/output/server/chunks/client.js 0.31 kB
|
||||
.svelte-kit/output/server/entries/pages/model-connections/_page.ts.js 0.31 kB
|
||||
.svelte-kit/output/server/internal.js 0.35 kB
|
||||
.svelte-kit/output/server/entries/fallbacks/error.svelte.js 0.35 kB
|
||||
.svelte-kit/output/server/chunks/state.svelte.js 0.45 kB
|
||||
.svelte-kit/output/server/chunks/Skeleton.js 0.48 kB
|
||||
.svelte-kit/output/server/chunks/Spinner.js 0.52 kB
|
||||
.svelte-kit/output/server/entries/pages/canvas/_id_/_layout.svelte.js 0.55 kB
|
||||
.svelte-kit/output/server/entries/pages/image/_page.svelte.js 0.55 kB
|
||||
.svelte-kit/output/server/entries/pages/video/_page.svelte.js 0.55 kB
|
||||
.svelte-kit/output/server/chunks/index2.js 0.57 kB
|
||||
.svelte-kit/output/server/chunks/server.js 0.62 kB
|
||||
.svelte-kit/output/server/entries/pages/canvas/_page.svelte.js 0.66 kB
|
||||
.svelte-kit/output/server/entries/pages/playground/_page.svelte.js 0.67 kB
|
||||
.svelte-kit/output/server/chunks/utils2.js 0.72 kB
|
||||
.svelte-kit/output/server/chunks/ids.js 0.77 kB
|
||||
.svelte-kit/output/server/chunks/Icon.svelte_svelte_type_style_lang.js 0.86 kB
|
||||
.svelte-kit/output/server/chunks/endpointKind.js 0.95 kB
|
||||
.svelte-kit/output/server/chunks/createMutation.js 1.02 kB
|
||||
.svelte-kit/output/server/chunks/EmptyState.js 1.10 kB
|
||||
.svelte-kit/output/server/chunks/toast.js 1.14 kB
|
||||
.svelte-kit/output/server/chunks/SafeMedia.js 1.65 kB
|
||||
.svelte-kit/output/server/chunks/ProgressBar.js 1.93 kB
|
||||
.svelte-kit/output/server/chunks/useUpload.svelte.js 2.15 kB
|
||||
.svelte-kit/output/server/chunks/context.js 2.27 kB
|
||||
.svelte-kit/output/server/chunks/clone.js 2.33 kB
|
||||
.svelte-kit/output/server/chunks/takeDelete.svelte.js 2.56 kB
|
||||
.svelte-kit/output/server/chunks/index3.js 2.77 kB
|
||||
.svelte-kit/output/server/entries/pages/workbench/_page.svelte.js 2.82 kB
|
||||
.svelte-kit/output/server/entries/pages/_layout.svelte.js 3.08 kB
|
||||
.svelte-kit/output/server/chunks/ConfirmDialog.js 3.25 kB
|
||||
.svelte-kit/output/server/entries/pages/workflows/_page.svelte.js 4.10 kB
|
||||
.svelte-kit/output/server/chunks/internal.js 4.19 kB
|
||||
.svelte-kit/output/server/chunks/exports.js 5.54 kB
|
||||
.svelte-kit/output/server/chunks/Icon.js 6.16 kB
|
||||
.svelte-kit/output/server/entries/pages/agents/_page.svelte.js 8.49 kB
|
||||
.svelte-kit/output/server/chunks/AProjectCard.js 10.17 kB
|
||||
.svelte-kit/output/server/entries/pages/tasks/_page.svelte.js 13.41 kB
|
||||
.svelte-kit/output/server/entries/pages/settings/_page.svelte.js 15.31 kB
|
||||
.svelte-kit/output/server/entries/pages/_page.svelte.js 18.29 kB
|
||||
.svelte-kit/output/server/entries/pages/library/_page.svelte.js 20.35 kB
|
||||
.svelte-kit/output/server/chunks/AppShell.svelte_svelte_type_style_lang.js 20.49 kB
|
||||
.svelte-kit/output/server/chunks/WorkflowBay.js 20.80 kB
|
||||
.svelte-kit/output/server/chunks/RefImageGrid.js 26.16 kB
|
||||
.svelte-kit/output/server/chunks/root.js 29.42 kB
|
||||
.svelte-kit/output/server/chunks/AgentComposer.js 31.59 kB
|
||||
.svelte-kit/output/server/chunks/utils.js 34.14 kB
|
||||
.svelte-kit/output/server/entries/pages/models/_page.svelte.js 36.45 kB
|
||||
.svelte-kit/output/server/remote-entry.js 36.81 kB
|
||||
.svelte-kit/output/server/chunks/AppShell.js 39.08 kB
|
||||
.svelte-kit/output/server/entries/pages/build-scene/_page.svelte.js 51.56 kB
|
||||
.svelte-kit/output/server/entries/pages/workbench/_id_/_page.svelte.js 52.95 kB
|
||||
.svelte-kit/output/server/chunks/index.js 101.49 kB
|
||||
.svelte-kit/output/server/chunks/StudioDesk.js 113.69 kB
|
||||
.svelte-kit/output/server/index.js 130.14 kB
|
||||
.svelte-kit/output/server/entries/pages/canvas/_id_/_page.svelte.js 144.05 kB
|
||||
.svelte-kit/output/server/entries/pages/connections/_page.svelte.js 150.23 kB
|
||||
.svelte-kit/output/server/chunks/i18n.svelte.js 846.64 kB
|
||||
✓ built in 6.69s
|
||||
|
||||
Run npm run preview to preview your production build locally.
|
||||
|
||||
> Using @sveltejs/adapter-static
|
||||
Wrote site to "build"
|
||||
✔ done
|
||||
@@ -0,0 +1,2 @@
|
||||
Checking formatting...
|
||||
All matched files use Prettier code style!
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
> calliope-web@1.5.8 check
|
||||
> svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
|
||||
|
||||
Loading svelte-check in workspace: /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/calliope-web
|
||||
Getting Svelte diagnostics...
|
||||
|
||||
/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/calliope-web/src/lib/components/workbench/ShotStagePanel.svelte:156:6
|
||||
Warn: `<video>` elements must have a `<track kind="captions">`
|
||||
https://svelte.dev/e/a11y_media_has_caption (svelte)
|
||||
{#if shot.job?.status === 'done' && shot.job.output}
|
||||
<video
|
||||
class="vshot-video"
|
||||
src={assetUrl(shot.job.output) ?? undefined}
|
||||
controls
|
||||
preload="metadata"
|
||||
></video>
|
||||
{/if}
|
||||
|
||||
====================================
|
||||
svelte-check found 0 errors and 1 warning in 1 file
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
Oops! Something went wrong! :(
|
||||
|
||||
ESLint: 9.39.5
|
||||
|
||||
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
|
||||
|
||||
From ESLint v9.0.0, the default configuration file is now eslint.config.js.
|
||||
If you are using a .eslintrc.* file, please follow the migration guide
|
||||
to update your configuration file to the new format:
|
||||
|
||||
https://eslint.org/docs/latest/use/configure/migration-guide
|
||||
|
||||
If you still have problems after following the migration guide, please stop by
|
||||
https://eslint.org/chat/help to chat with the team.
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
> calliope-web@1.5.8 test
|
||||
> node scripts/check-storage-ssr.mjs && node scripts/check-random-uuid.mjs && node scripts/check-skill-frontmatter.mjs && node scripts/check-export-frame.mjs
|
||||
|
||||
ok method-less localStorage (Node SSR shape) degrades to null without throwing
|
||||
ok absent localStorage degrades to null
|
||||
ok throwing localStorage access degrades to null
|
||||
ok setItem failure is swallowed
|
||||
ok working storage round-trips and removes
|
||||
ok no unsafe `typeof localStorage` guards in src/
|
||||
|
||||
storage SSR checks passed.
|
||||
ok insecure-context crypto (getRandomValues only) yields unique v4 UUIDs
|
||||
ok method-less crypto degrades to unique best-effort ids without throwing
|
||||
ok absent crypto degrades to unique best-effort ids without throwing
|
||||
ok native randomUUID preferred when available
|
||||
ok no direct `crypto.randomUUID()` calls in src/
|
||||
|
||||
randomId insecure-context checks passed.
|
||||
ok edit load strips the frontmatter block
|
||||
ok edit load keeps the body
|
||||
ok strip boundary is exact
|
||||
ok strip is idempotent
|
||||
ok second edit-save-reload adds no layer
|
||||
ok plain body unchanged
|
||||
ok page imports the shared strip helper
|
||||
ok no \A-anchored strip regex left behind
|
||||
skill frontmatter checks passed.
|
||||
ok first try is ~1 frame before the end, never the end itself
|
||||
ok later tries step strictly further back
|
||||
ok tries stay within ~1s of the end
|
||||
ok short clip clamps to 0 without duplicates
|
||||
ok unknown / zero duration falls back to t=0
|
||||
ok base name from /api/file?path=…
|
||||
ok base name from a Windows path
|
||||
ok base name from a plain URL
|
||||
ok unsafe characters are replaced
|
||||
ok blob URL without a name falls back to 'video'
|
||||
ok PNG name names the video, the tag and the frame time
|
||||
ok spaces in the tag become dashes
|
||||
ok fully transparent sample → empty
|
||||
ok pure black → black
|
||||
ok near-black encoder noise (16..18) → black
|
||||
ok mid-grey picture → not blank
|
||||
ok dim but visible picture (≈50) → not blank
|
||||
ok dark night scene with a bright highlight → not blank
|
||||
ok 404 → not-found
|
||||
ok 403 → forbidden
|
||||
ok 500 → network
|
||||
ok 206 / 200 are not errors
|
||||
export-frame checks passed.
|
||||
@@ -0,0 +1,13 @@
|
||||
# HEL-728 B0 实现说明
|
||||
|
||||
以 HEL-716/726 确认附件和 HEL-727 模块边界为依据,只建设主题、导航与兼容基础;完整业务页面重排和动效分别留在 B1–B5。
|
||||
|
||||
- `calliope-web/static/themes.css` 是四套语义颜色、字体、尺寸、圆角和特效 token 的唯一产品定义来源。取值直接来自 HEL-726 HTML;现有组件变量在此映射到语义变量,没有另设配色。作品控制、灯箱的固定深色保留。`routes/app.css` 保留公共组件与动效规则,已有金色/紫色按钮和光栅改为消费 token。
|
||||
- `src/app.html` 在绘制前验证 `aigc-theme`,失败回退夜片场;同步加载阻塞渲染的 themes.css,框架代码尚未执行时也有正确底色。`lib/theme.ts` 只改根元素属性,不改路由、不创建 QueryClient、不重建编辑器。写存储失败时继续本次切换,并明确提示;跨标签页存储事件同步主题。
|
||||
- `ThemeChoices.svelte` 在侧栏统一 Modal 和设置外观区复用,含四主题实时 token 预览、中文名/用途、方向键/Enter 操作。Esc/焦点返回复用既有 Modal。侧栏与主题选择适配三档桌面;减少动效沿用现有全局机制。
|
||||
- `shell/nav.ts` 为外壳和全局搜索提供单一导航定义。工作室/项目/创作台/智能体/画布/素材库,以及任务/工作流/模型连接按确认顺序组织。模型页与 ComfyUI 页面保留可见切换链接,原视频、试验台、三维搭景仍可从全局搜索到达。
|
||||
- `/create?kind=video`、`/model-connections?tab=llm` 是 B0 兼容入口,分别转到已有视频/LLM 页面;默认转到图片/ComfyUI 页面。后续页面未实现前不转向空页。原 `/image`、`/video`、`/connections`、`/models`、`/playground`、`/build-scene` 保持现有功能。
|
||||
- 修复既有 `/projects`、`/project/[id]` 的跳转参数丢失;新入口和旧项目入口保留查询及片段,项目来源、工作流、模式、提示词等不改写。设置的旧页签转向也保留原参数。
|
||||
- `design/nocturne` 保存已确认的 v1/v2 规范与 HTML,仅清除行尾空白;均为设计演示,未作为产品运行代码或假生成结果使用。
|
||||
|
||||
B0 没有新增依赖、生成接口、主题测试副本、数据库变更、密钥或线上配置变更。已有页面局部硬编码视觉的全站替换与最终特效验收仍属于 B5,本批没有宣称完成全站重设计。
|
||||
@@ -0,0 +1,48 @@
|
||||
{"image_wf": 71, "video_wf": 72, "endpoint": "1c758e36-793b-4c11-8e08-c139bba68b02"}
|
||||
{'dual': 3, 'h3': 4, 'project': 6}
|
||||
RUN e2e/reference/check.cjs
|
||||
PASS 真实工作流显示正反向左右分栏
|
||||
PASS 工作流列表可应对超过 48 项
|
||||
PASS 列表搜索过滤真实元数据
|
||||
PASS 置顶不切换工作流、不清空草稿
|
||||
PASS 参数取消不改当前值
|
||||
PASS 参数保存应用到当前工作流
|
||||
PASS 真实生成请求提交且取得结果
|
||||
PASS 正反向与种子写入任务
|
||||
locator.click: Timeout 12000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for locator('.result-item').first()[22m
|
||||
|
||||
at /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/e2e/reference/check.cjs:146:45 {
|
||||
log: [ " - waiting for locator('.result-item').first()" ],
|
||||
name: 'TimeoutError'
|
||||
}
|
||||
RUN e2e/reference/check-copy-fallback.cjs
|
||||
locator.waitFor: Timeout 15000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for getByRole('button', { name: /编辑内容并带回项目/ }) to be visible[22m
|
||||
|
||||
at /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/e2e/reference/check-copy-fallback.cjs:44:54 {
|
||||
log: [
|
||||
" - waiting for getByRole('button', { name: /编辑内容并带回项目/ }) to be visible"
|
||||
],
|
||||
name: 'TimeoutError'
|
||||
}
|
||||
RUN e2e/hel728.cjs
|
||||
PASS 默认主题为夜片场
|
||||
PASS night 保留原编辑组件和正反向草稿
|
||||
PASS day 保留原编辑组件和正反向草稿
|
||||
PASS grade 保留原编辑组件和正反向草稿
|
||||
PASS bluehour 保留原编辑组件和正反向草稿
|
||||
PASS 刷新恢复主题和草稿
|
||||
PASS 方向键移动主题选项焦点
|
||||
PASS Esc 关闭并恢复入口焦点
|
||||
locator.waitFor: Timeout 30000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for locator('#desk-prompt') to be visible[22m
|
||||
|
||||
at /home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/e2e/hel728.cjs:23:74 {
|
||||
log: [ " - waiting for locator('#desk-prompt') to be visible" ],
|
||||
name: 'TimeoutError'
|
||||
}
|
||||
FAILED SCRIPTS ['e2e/reference/check.cjs', 'e2e/reference/check-copy-fallback.cjs', 'e2e/hel728.cjs']
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
> calliope-web@1.5.8 lint
|
||||
> prettier --check . && eslint .
|
||||
|
||||
Checking formatting...
|
||||
[warn] package-lock.json
|
||||
[warn] package.json
|
||||
[warn] scripts/check-storage-ssr.mjs
|
||||
[warn] src/hooks.client.ts
|
||||
[warn] src/hooks.server.ts
|
||||
[warn] src/lib/actions/spotlight.ts
|
||||
[warn] src/lib/agentComposer.ts
|
||||
[warn] src/lib/agentTasks.ts
|
||||
[warn] src/lib/assetPicker.ts
|
||||
[warn] src/lib/comfy/classifyInput.ts
|
||||
[warn] src/lib/comfy/parser.ts
|
||||
[warn] src/lib/comfy/promptInput.ts
|
||||
[warn] src/lib/comfy/resolution.ts
|
||||
[warn] src/lib/comfy/types.ts
|
||||
[warn] src/lib/comfy/useUpload.svelte.ts
|
||||
[warn] src/lib/components/agent/agentPalette.ts
|
||||
[warn] src/lib/components/generate/context.ts
|
||||
[warn] src/lib/components/generate/schema.ts
|
||||
[warn] src/lib/components/generate/takeDelete.svelte.ts
|
||||
[warn] src/lib/components/generate/takes.ts
|
||||
[warn] src/lib/components/ui/icons.ts
|
||||
[warn] src/lib/components/ui/modalLayers.ts
|
||||
[warn] src/lib/components/ui/README.md
|
||||
[warn] src/lib/dbtime.ts
|
||||
[warn] src/lib/durationBudget.ts
|
||||
[warn] src/lib/endpointKind.ts
|
||||
[warn] src/lib/events.ts
|
||||
[warn] src/lib/formOptions.ts
|
||||
[warn] src/lib/i18n.svelte.ts
|
||||
[warn] src/lib/i18n/de.ts
|
||||
[warn] src/lib/i18n/en.ts
|
||||
[warn] src/lib/i18n/es.ts
|
||||
[warn] src/lib/i18n/fr.ts
|
||||
[warn] src/lib/i18n/ja.ts
|
||||
[warn] src/lib/i18n/ko.ts
|
||||
[warn] src/lib/i18n/zh.ts
|
||||
[warn] src/lib/jobProgress.ts
|
||||
[warn] src/lib/jobStatus.ts
|
||||
[warn] src/lib/missingOutputs.svelte.ts
|
||||
[warn] src/lib/promptTemplates.ts
|
||||
[warn] src/lib/reduceMotion.svelte.ts
|
||||
[warn] src/lib/referenceAgent.ts
|
||||
[warn] src/lib/shot/api.ts
|
||||
[warn] src/lib/shot/calibration/compositionPresets.ts
|
||||
[warn] src/lib/shot/calibration/shotSolver.ts
|
||||
[warn] src/lib/shot/helpers/cameraUtils.ts
|
||||
[warn] src/lib/shot/helpers/jointConfig.ts
|
||||
[warn] src/lib/shot/helpers/mannequinFactory.ts
|
||||
[warn] src/lib/shot/helpers/mirror.ts
|
||||
[warn] src/lib/shot/helpers/posture.ts
|
||||
[warn] src/lib/shot/helpers/primitiveFactory.ts
|
||||
[warn] src/lib/shot/motion/sampleTrack.ts
|
||||
[warn] src/lib/shot/shotStore.svelte.ts
|
||||
[warn] src/lib/shot/types/mannequin-js.d.ts
|
||||
[warn] src/lib/storage.ts
|
||||
[warn] src/lib/toast.ts
|
||||
[warn] src/lib/wideLayout.ts
|
||||
[warn] src/routes/+layout.ts
|
||||
[warn] src/routes/+page.ts
|
||||
[warn] svelte.config.js
|
||||
[warn] tailwind.config.js
|
||||
[warn] tsconfig.json
|
||||
[warn] vite.config.ts
|
||||
[warn] Code style issues found in 63 files. Run Prettier with --write to fix.
|
||||
@@ -0,0 +1,442 @@
|
||||
.................................F...................................... [ 8%]
|
||||
........................................................................ [ 17%]
|
||||
........................................................................ [ 25%]
|
||||
........................................................................ [ 34%]
|
||||
..................................F..................................... [ 42%]
|
||||
........F............................................................... [ 51%]
|
||||
........................................................................ [ 59%]
|
||||
........................................................................ [ 68%]
|
||||
...F..........F......................................................... [ 76%]
|
||||
.........s.............................................................. [ 85%]
|
||||
........................................................................ [ 93%]
|
||||
sssss................................................ [100%]
|
||||
=================================== FAILURES ===================================
|
||||
________________________ test_comfy_server_info_scoping ________________________
|
||||
|
||||
def test_comfy_server_info_scoping():
|
||||
"""Native health check stays visible in both blind and linked sessions."""
|
||||
from calliope.agent.harness import tools as harness_tools
|
||||
|
||||
blind = ToolContext(session_id=1, project_id=None)
|
||||
linked = ToolContext(session_id=1, project_id=99)
|
||||
|
||||
> blind_names = {e["function"]["name"] for e in harness_tools.openai_tools_payload(blind)}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
tests/test_agent_comfy_mcp.py:370:
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
src/calliope/agent/harness/tools.py:27: in openai_tools_payload
|
||||
return _registry.openai_payload(ctx)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/registry.py:219: in openai_payload
|
||||
if self._visible(t, ctx)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/registry.py:203: in _visible
|
||||
if not user_allows_render(ctx):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:156: in user_allows_render
|
||||
if has_structured_approval(ctx, "render"):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:277: in has_structured_approval
|
||||
answer = latest_answer(ctx.session_id)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
src/calliope/agent/harness/policy.py:260: in latest_answer
|
||||
events = read_events(session_id)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|
||||
session_id = 1
|
||||
|
||||
def read_events(session_id: int) -> list[SessionEvent]:
|
||||
conn = _db()
|
||||
try:
|
||||
> rows = conn.execute(
|
||||
"SELECT * FROM agent_events WHERE session_id = ? ORDER BY seq", (session_id,)
|
||||
).fetchall()
|
||||
E sqlite3.OperationalError: no such table: agent_events
|
||||
|
||||
src/calliope/agent/harness/log.py:146: OperationalError
|
||||
___________ test_h3_messages_bind_neighbor_shots_and_keep_file_slots ___________
|
||||
|
||||
def test_h3_messages_bind_neighbor_shots_and_keep_file_slots():
|
||||
from calliope.agent.prompts import build_minimax_h3_ref_messages
|
||||
from calliope.agent.video_agent import resolve_h3_references
|
||||
from calliope.comfyui.parser import parse_dynamic_inputs
|
||||
|
||||
plan = {
|
||||
"overview": {"style": "noir", "lighting": "sodium"},
|
||||
"requirements": {"lighting": "sodium lamps only"},
|
||||
"shots": [
|
||||
{
|
||||
"clip_id": 1,
|
||||
"window": "00:00.000-00:04.000",
|
||||
"action": "enter",
|
||||
"camera": "push in",
|
||||
"lighting": "dim sodium",
|
||||
"speakers": "MAYA: hello",
|
||||
"spatial": "screen left",
|
||||
"state_after": "door open",
|
||||
},
|
||||
{
|
||||
"clip_id": 2,
|
||||
"window": "00:04.000-00:08.000",
|
||||
"action": "turn",
|
||||
"camera": "hold",
|
||||
"lighting": "dim sodium",
|
||||
"speakers": "",
|
||||
"spatial": "screen left",
|
||||
"state_after": "",
|
||||
},
|
||||
{
|
||||
"clip_id": 3,
|
||||
"window": "00:08.000-00:12.000",
|
||||
"action": "leave",
|
||||
"camera": "pull out",
|
||||
"lighting": "brighter",
|
||||
"speakers": "",
|
||||
"spatial": "",
|
||||
"state_after": "hallway empty",
|
||||
},
|
||||
],
|
||||
}
|
||||
lock = continuity_lock_text(plan, 2)
|
||||
assert "Previous shot" in lock
|
||||
assert "Next shot" in lock
|
||||
assert "Do not recast a subject" in lock
|
||||
assert "screen direction" in lock
|
||||
assert "enter" in lock and "leave" in lock
|
||||
|
||||
scene = {"heading": "INT. HALL", "action": "She turns.", "duration_sec": 4, "dialog": ""}
|
||||
subjects = [
|
||||
{
|
||||
"index": 1,
|
||||
"kind": "reference",
|
||||
"name": "mercs",
|
||||
"appearance": "",
|
||||
"path": r"E:\assets\mercs.png",
|
||||
}
|
||||
]
|
||||
messages = build_minimax_h3_ref_messages(scene, subjects, continuity=lock)
|
||||
text = messages[1]["content"]
|
||||
assert "Previous shot" in text
|
||||
assert "Next shot" in text
|
||||
assert "screen direction" in text
|
||||
assert "do not substitute another character or location" in text
|
||||
|
||||
workflow = {
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
}
|
||||
inputs = parse_dynamic_inputs(workflow)
|
||||
resolved, paths, _videos = resolve_h3_references(
|
||||
inputs,
|
||||
{"148": r"E:\assets\hero.png", "149": r"E:\assets\mercs.png"},
|
||||
[{"name": "Maya", "appearance": "olive jacket", "sheet_path": r"E:\assets\maya.png"}],
|
||||
{"name": "Metro Line", "description": "rain-slick rooftops"},
|
||||
r"E:\assets\metro.png",
|
||||
)
|
||||
> assert resolved[1]["name"] == "mercs"
|
||||
E AssertionError: assert 'E:\\assets\\mercs' == 'mercs'
|
||||
E
|
||||
E - mercs
|
||||
E + E:\assets\mercs
|
||||
|
||||
tests/test_continuity.py:249: AssertionError
|
||||
___________ test_resolve_h3_references_prefers_form_files_over_story ___________
|
||||
|
||||
def test_resolve_h3_references_prefers_form_files_over_story():
|
||||
"""Slot files the user picked replace the story cast; empty slots keep it."""
|
||||
from calliope.agent.video_agent import resolve_h3_references
|
||||
from calliope.comfyui.parser import parse_dynamic_inputs
|
||||
|
||||
workflow = {
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
"150": {
|
||||
"class_type": "LoadVideo",
|
||||
"inputs": {"video": ""},
|
||||
"_meta": {"title": "Motion (Input:video)"},
|
||||
},
|
||||
}
|
||||
inputs = parse_dynamic_inputs(workflow)
|
||||
characters = [
|
||||
{
|
||||
"name": "Maya",
|
||||
"appearance": "olive jacket",
|
||||
"sheet_path": r"E:\assets\maya.png",
|
||||
}
|
||||
]
|
||||
location = {"name": "Metro Line", "description": "rain-slick rooftops"}
|
||||
loc_image = r"E:\assets\metro.png"
|
||||
|
||||
empty_subjects, empty_paths, empty_videos = resolve_h3_references(
|
||||
inputs, {}, characters, location, loc_image
|
||||
)
|
||||
assert [s["name"] for s in empty_subjects] == ["Maya", "Metro Line"]
|
||||
assert empty_paths == [r"E:\assets\maya.png", r"E:\assets\metro.png"]
|
||||
assert empty_videos == []
|
||||
|
||||
subjects, paths, videos = resolve_h3_references(
|
||||
inputs,
|
||||
{
|
||||
"148": r"E:\assets\maya.png",
|
||||
"149": r"E:\assets\mercs.png",
|
||||
"150": r"E:\assets\fight.mp4",
|
||||
},
|
||||
characters,
|
||||
location,
|
||||
loc_image,
|
||||
)
|
||||
assert subjects[0]["kind"] == "character"
|
||||
assert subjects[0]["name"] == "Maya"
|
||||
assert subjects[1]["kind"] == "reference"
|
||||
> assert subjects[1]["name"] == "mercs"
|
||||
E AssertionError: assert 'E:\\assets\\mercs' == 'mercs'
|
||||
E
|
||||
E - mercs
|
||||
E + E:\assets\mercs
|
||||
|
||||
tests/test_h3_profile.py:215: AssertionError
|
||||
___________ test_preview_prompt_uses_form_references_not_story_cast ____________
|
||||
|
||||
client = <starlette.testclient.TestClient object at 0x7ff7be3182c0>
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff7bc9b2180>
|
||||
|
||||
def test_preview_prompt_uses_form_references_not_story_cast(client, monkeypatch):
|
||||
"""The Video-tab image and video slots are the prompt's subjects.
|
||||
|
||||
Story character + location text must not replace files the user picked,
|
||||
and Regenerate (force) must not return a draft written before those files.
|
||||
"""
|
||||
pid = _mk_project(client, "Preview refs")
|
||||
scene = _add_scene(client, pid, 1, action="She swings the extinguisher.")
|
||||
clip_id = _scene_default_clip(pid, scene["id"])
|
||||
|
||||
wf = {
|
||||
"10": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"inputs": {"text": ""},
|
||||
"_meta": {"title": "Main Prompt (Input:prompt)"},
|
||||
},
|
||||
"148": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 1 (Input:image)"},
|
||||
},
|
||||
"149": {
|
||||
"class_type": "LoadImage",
|
||||
"inputs": {"image": ""},
|
||||
"_meta": {"title": "Ref 2 (Input:image)"},
|
||||
},
|
||||
"150": {
|
||||
"class_type": "LoadVideo",
|
||||
"inputs": {"video": ""},
|
||||
"_meta": {"title": "Motion (Input:video)"},
|
||||
},
|
||||
}
|
||||
conn = get_db(settings.db_path)
|
||||
try:
|
||||
cur = conn.execute(
|
||||
"""
|
||||
INSERT INTO workflows (name, kind, workflow_json, input_schema, output_schema,
|
||||
prompt_profile, is_enabled)
|
||||
VALUES (?, 'video', ?, '[]', '[]', 'minimax_h3_ref', 1)
|
||||
""",
|
||||
("H3 refs", json.dumps(wf)),
|
||||
)
|
||||
wf_id = cur.lastrowid
|
||||
char = conn.execute(
|
||||
"""
|
||||
INSERT INTO characters (project_id, name, appearance, sheet_path)
|
||||
VALUES (?, 'Maya', 'olive jacket', ?)
|
||||
""",
|
||||
(pid, r"E:\story\maya-sheet.png"),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO scene_characters (scene_id, character_id) VALUES (?, ?)",
|
||||
(scene["id"], char.lastrowid),
|
||||
)
|
||||
loc = conn.execute(
|
||||
"""
|
||||
INSERT INTO locations (project_id, name, description, reference_image_path)
|
||||
VALUES (?, 'Metro Line', 'rain-slick rooftops', ?)
|
||||
""",
|
||||
(pid, r"E:\story\metro.png"),
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE scenes SET location_id = ? WHERE id = ?",
|
||||
(loc.lastrowid, scene["id"]),
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE clips SET workflow_id = ? WHERE id = ?", (wf_id, clip_id)
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
seen: dict = {}
|
||||
|
||||
async def fake_rewrite(scene_, subjects, **kwargs):
|
||||
seen["subjects"] = subjects
|
||||
seen["videos"] = kwargs.get("videos")
|
||||
seen["calls"] = seen.get("calls", 0) + 1
|
||||
return "REWRITE FROM REFS"
|
||||
|
||||
monkeypatch.setattr("calliope.agent.video_agent._h3_rewrite", fake_rewrite)
|
||||
|
||||
form = {
|
||||
"148": r"E:\refs\hero.png",
|
||||
"149": r"E:\refs\mercs.png",
|
||||
"150": r"E:\refs\fight.mp4",
|
||||
}
|
||||
r = client.post(
|
||||
f"/api/jobs/projects/{pid}/preview-prompt",
|
||||
json={"clip_id": clip_id, "input_values": form},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["prompt"] == "REWRITE FROM REFS"
|
||||
assert body["from_draft"] is False
|
||||
names = [s["name"] for s in seen["subjects"]]
|
||||
> assert names == ["hero", "mercs"]
|
||||
E AssertionError: assert ['E:\\refs\\h...\refs\\mercs'] == ['hero', 'mercs']
|
||||
E
|
||||
E At index 0 diff: 'E:\\refs\\hero' != 'hero'
|
||||
E Use -v to get more diff
|
||||
|
||||
tests/test_scene_settings.py:487: AssertionError
|
||||
---------------------------- Captured stderr setup -----------------------------
|
||||
2026-10-21 19:58:18,478 | INFO | calliope | Calliope started — db=/tmp/multica-task-3084682389/tmp_95dfjk4/calliope.db dry_run=True
|
||||
2026-10-21 19:58:18,478 | INFO | calliope.worker | Queue worker started
|
||||
------------------------------ Captured log setup ------------------------------
|
||||
INFO calliope:main.py:112 Calliope started — db=/tmp/multica-task-3084682389/tmp_95dfjk4/calliope.db dry_run=True
|
||||
INFO calliope.worker:worker.py:79 Queue worker started
|
||||
----------------------------- Captured stderr call -----------------------------
|
||||
2026-10-21 19:58:18,482 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
2026-10-21 19:58:18,495 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects/1/scenes "HTTP/1.1 200 OK"
|
||||
2026-10-21 19:58:18,506 | INFO | httpx2 | HTTP Request: POST http://testserver/api/jobs/projects/1/preview-prompt "HTTP/1.1 200 OK"
|
||||
------------------------------ Captured log call -------------------------------
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects/1/scenes "HTTP/1.1 200 OK"
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/jobs/projects/1/preview-prompt "HTTP/1.1 200 OK"
|
||||
--------------------------- Captured stderr teardown ---------------------------
|
||||
2026-10-21 19:58:18,980 | INFO | calliope.worker | Queue worker stopped
|
||||
2026-10-21 19:58:18,980 | INFO | calliope | Calliope shutting down
|
||||
---------------------------- Captured log teardown -----------------------------
|
||||
INFO calliope.worker:worker.py:185 Queue worker stopped
|
||||
INFO calliope:main.py:118 Calliope shutting down
|
||||
_________________ test_script_regenerate_keeps_expanded_count __________________
|
||||
|
||||
client = <starlette.testclient.TestClient object at 0x7ff7bd902660>
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff7bc9b2180>
|
||||
|
||||
def test_script_regenerate_keeps_expanded_count(client, monkeypatch):
|
||||
calls: list[int] = []
|
||||
|
||||
async def fake_structured(messages, temperature=0.7):
|
||||
user = messages[1]["content"]
|
||||
# Parse required count from prompt
|
||||
n = 4
|
||||
for line in user.splitlines():
|
||||
if line.startswith("required_scene_count:"):
|
||||
n = int(line.split(":", 1)[1].strip())
|
||||
break
|
||||
calls.append(n)
|
||||
return {
|
||||
"scenes": [
|
||||
{
|
||||
"order_index": i,
|
||||
"heading": f"SCENE {i}",
|
||||
"action": f"action {i}",
|
||||
"dialog": "",
|
||||
"duration_sec": 5,
|
||||
"character_ids": [],
|
||||
"location_id": None,
|
||||
}
|
||||
for i in range(1, n + 1)
|
||||
]
|
||||
}
|
||||
|
||||
monkeypatch.setattr("calliope.agent.script_agent.generate_structured", fake_structured)
|
||||
|
||||
r = client.post("/api/projects", json={"title": "Expand", "idea": "desert", "target_duration": "30 seconds"})
|
||||
pid = r.json()["id"]
|
||||
|
||||
# Seed 4 scenes via generate
|
||||
r = client.post(f"/api/projects/{pid}/generate-script", json={"replace": True})
|
||||
> assert r.status_code == 200
|
||||
E assert 500 == 200
|
||||
E + where 500 = <Response [500 Internal Server Error]>.status_code
|
||||
|
||||
tests/test_script_scene_count.py:59: AssertionError
|
||||
---------------------------- Captured stderr setup -----------------------------
|
||||
2026-10-21 19:58:19,584 | INFO | calliope | Calliope started — db=/tmp/multica-task-3084682389/tmpl0t0r_mx/calliope.db dry_run=True
|
||||
2026-10-21 19:58:19,584 | INFO | calliope.worker | Queue worker started
|
||||
------------------------------ Captured log setup ------------------------------
|
||||
INFO calliope:main.py:112 Calliope started — db=/tmp/multica-task-3084682389/tmpl0t0r_mx/calliope.db dry_run=True
|
||||
INFO calliope.worker:worker.py:79 Queue worker started
|
||||
----------------------------- Captured stderr call -----------------------------
|
||||
2026-10-21 19:58:19,588 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
2026-10-21 19:58:19,604 | INFO | calliope.llm | LLM stream request to http://127.0.0.1:11434/v1/chat/completions with model llama3.2
|
||||
2026-10-21 19:58:19,606 | INFO | httpx2 | HTTP Request: POST http://testserver/api/projects/1/generate-script "HTTP/1.1 500 Internal Server Error"
|
||||
------------------------------ Captured log call -------------------------------
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects "HTTP/1.1 200 OK"
|
||||
INFO calliope.llm:llm.py:360 LLM stream request to http://127.0.0.1:11434/v1/chat/completions with model llama3.2
|
||||
INFO httpx2:_client.py:1085 HTTP Request: POST http://testserver/api/projects/1/generate-script "HTTP/1.1 500 Internal Server Error"
|
||||
--------------------------- Captured stderr teardown ---------------------------
|
||||
2026-10-21 19:58:20,086 | INFO | calliope.worker | Queue worker stopped
|
||||
2026-10-21 19:58:20,086 | INFO | calliope | Calliope shutting down
|
||||
---------------------------- Captured log teardown -----------------------------
|
||||
INFO calliope.worker:worker.py:185 Queue worker stopped
|
||||
INFO calliope:main.py:118 Calliope shutting down
|
||||
=============================== warnings summary ===============================
|
||||
.venv/lib/python3.12/site-packages/starlette/testclient.py:53
|
||||
/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/calliope-backend/.venv/lib/python3.12/site-packages/starlette/testclient.py:53: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
|
||||
_PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]
|
||||
|
||||
tests/test_shell_tool.py::test_settings_roundtrip_for_new_keys
|
||||
/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-728-a07b128af8f7/workdir/aigc-home/calliope-backend/.venv/lib/python3.12/site-packages/_pytest/unraisableexception.py:67: PytestUnraisableExceptionWarning: Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x7ff7c055cb80>
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/base_subprocess.py", line 126, in __del__
|
||||
self.close()
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/base_subprocess.py", line 104, in close
|
||||
proto.pipe.close()
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/unix_events.py", line 568, in close
|
||||
self._close(None)
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/unix_events.py", line 592, in _close
|
||||
self._loop.call_soon(self._call_connection_lost, exc)
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/base_events.py", line 799, in call_soon
|
||||
self._check_closed()
|
||||
File "/home/xiaomo/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/asyncio/base_events.py", line 545, in _check_closed
|
||||
raise RuntimeError('Event loop is closed')
|
||||
RuntimeError: Event loop is closed
|
||||
|
||||
Enable tracemalloc to get traceback where the object was allocated.
|
||||
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
||||
warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
|
||||
|
||||
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
||||
=========================== short test summary info ============================
|
||||
FAILED tests/test_agent_comfy_mcp.py::test_comfy_server_info_scoping - sqlite...
|
||||
FAILED tests/test_continuity.py::test_h3_messages_bind_neighbor_shots_and_keep_file_slots
|
||||
FAILED tests/test_h3_profile.py::test_resolve_h3_references_prefers_form_files_over_story
|
||||
FAILED tests/test_scene_settings.py::test_preview_prompt_uses_form_references_not_story_cast
|
||||
FAILED tests/test_script_scene_count.py::test_script_regenerate_keeps_expanded_count
|
||||
5 failed, 834 passed, 6 skipped, 2 warnings in 368.55s (0:06:08)
|
||||
@@ -0,0 +1,201 @@
|
||||
feat/hel-665-refract @ 35fd07a (v5 formal interfaces; stage advice API; user database/config unchanged; demos retained; rollback /opt/aigc-home/releases/rollback-HEL665-v5-35fd07a-20261015.sh)
|
||||
total 64
|
||||
drwxr-xr-x 4 root root 4096 Oct 15 00:33 .
|
||||
drwxr-xr-x 10 root root 12288 Oct 15 00:33 ..
|
||||
drwxrwxr-x 6 mobai mobai 4096 Oct 15 00:33 build
|
||||
drwxrwxr-x 4 mobai mobai 4096 Oct 10 20:35 src
|
||||
-rw-rw-r-- 1 mobai mobai 40144 Oct 15 00:13 workbench.py
|
||||
6864465552ed31ae9179bf6cb8b45bc7df4e43b1b5d452abaa04007346cfa50c /opt/aigc-home/app/calliope-web/src/app.html
|
||||
9fcd4c28d99551f12eebc3e58d2d2e715a2d2fae91315078e25ad301a3fe0101 /opt/aigc-home/app/calliope-web/src/hooks.client.ts
|
||||
016119d7d2f2f77dee4441ce8c0e0c337461775be19589ab25eb8e6d93d9325b /opt/aigc-home/app/calliope-web/src/hooks.server.ts
|
||||
90ef4a1441f5ea1b9b1191dcd90bdedfad038a834393860071f4ac658217234a /opt/aigc-home/app/calliope-web/src/lib/actions/spotlight.ts
|
||||
b73c6e2c597d2ee06071c279ea7f51b8318702ec09617a29361d906fd72e3f12 /opt/aigc-home/app/calliope-web/src/lib/agentComposer.ts
|
||||
f5b7e10ecef0822206220c8c2827740c3e35254ca92ce130d52a786945dc3af8 /opt/aigc-home/app/calliope-web/src/lib/agentTasks.ts
|
||||
859129cc60fab17c6104f82c82eb0dc42322d9f81fb8b210ba4ff5aace234e4a /opt/aigc-home/app/calliope-web/src/lib/api.ts
|
||||
53fa1c405c185b2ec07cd379011dde429de28c965a8d7e21771e1a5b21e3e79c /opt/aigc-home/app/calliope-web/src/lib/assetPicker.ts
|
||||
b0adfec622f00ee5dbe1f786c9d487229ddb33eb2077e2166bd7b391c0d32d6c /opt/aigc-home/app/calliope-web/src/lib/canvas/ArtifactNode.svelte
|
||||
4d76e5fd32270d79be2814c2bd6b9ba19f1c3e5319133d915966052ecc92f6f3 /opt/aigc-home/app/calliope-web/src/lib/canvas/EntityNode.svelte
|
||||
8bc6d779cdfc98885b5203dabdca38999e12e9d503dfd6d7cd8452162b0bd78e /opt/aigc-home/app/calliope-web/src/lib/comfy/classifyInput.ts
|
||||
b0a8e133e68635ba08f700c23196a7ba9524d510ac5d28d8aa674cf18c21bd70 /opt/aigc-home/app/calliope-web/src/lib/comfy/imageFile.ts
|
||||
e8372ec223a04e4aef7af92cbe11656acc1339bfbc6029876efb4495efac60b1 /opt/aigc-home/app/calliope-web/src/lib/comfy/parser.ts
|
||||
233160c907bcf7a6b3a6d78d5500cecdf2e0a14dbd67b2f7a63555f721106c91 /opt/aigc-home/app/calliope-web/src/lib/comfy/promptInput.ts
|
||||
4cbfcb95e28e2d5061614977831b2a9fe1c82449ab9ed5b692d963e1d99f6505 /opt/aigc-home/app/calliope-web/src/lib/comfy/resolution.ts
|
||||
0edcc73d9a03a38804032b8799705f85d5a8560838ddbafd33651ea167a354c6 /opt/aigc-home/app/calliope-web/src/lib/comfy/types.ts
|
||||
aa91e6d36c34dd9a5246fff3c24e4b437dccb8f9c55141959a9b1df0639205b9 /opt/aigc-home/app/calliope-web/src/lib/comfy/useUpload.svelte.ts
|
||||
3722615c86e150d61fee60b287cc66fc1ff5f32c4a13e55f7f2e4ec6e3b7e95c /opt/aigc-home/app/calliope-web/src/lib/components/AppHeader.svelte
|
||||
b6844910420c977167b7beee5afa6ee3f649a74bd6e8128ced432e3a51079e57 /opt/aigc-home/app/calliope-web/src/lib/components/AttachToProject.svelte
|
||||
70b01844b1b8bb3c1c79e49aa61d3a37fe93ccf30c1f28a1e05867efa8f58582 /opt/aigc-home/app/calliope-web/src/lib/components/ComfyDynamicForm.svelte
|
||||
b67433cd628d0507665fdd594bbf38ba366cb71cf6e1bcf32c8be05cbc8bddc5 /opt/aigc-home/app/calliope-web/src/lib/components/GeneratingOverlay.svelte
|
||||
6675bd98205aa274938874dba40e4c95f0f871b9ea29433cb5edf207a8963a3d /opt/aigc-home/app/calliope-web/src/lib/components/ImageLightbox.svelte
|
||||
37fb771f258dd4dfe7b4c1738b84ea6aa74cd35508505c0c03bbb2121226c4ac /opt/aigc-home/app/calliope-web/src/lib/components/LanguageSwitcher.svelte
|
||||
4552e1fd1972a55b7267949fe6f6ce57e18b0c500698e2f919562a77b3ffa636 /opt/aigc-home/app/calliope-web/src/lib/components/OmniComposer.svelte
|
||||
d53835230e1d584e59c98f5b6aa965b605ab73011f33eac61a0a0e44158b6d0b /opt/aigc-home/app/calliope-web/src/lib/components/SafeMedia.svelte
|
||||
4becfa6663461e91602b74322f9807aedd403522ccd54603c66b80b872363953 /opt/aigc-home/app/calliope-web/src/lib/components/ToastHost.svelte
|
||||
d744fc2278a627ddb329a0ba9c86b80905d09e58a476297a35c4c77874c35b07 /opt/aigc-home/app/calliope-web/src/lib/components/WorkflowImportDrawer.svelte
|
||||
a75f0602d09cf72d6821a69be537cfda284ff589a9f5452e7ed8dd64337b7bd4 /opt/aigc-home/app/calliope-web/src/lib/components/WorkflowTestDialog.svelte
|
||||
52d9b005c65f6d83ef7ead5caa81dc61058a7049c29779b76d01979361c480b7 /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentArtifactCard.svelte
|
||||
075ab299124430e41ca9ab1e314d3e616dd0fbdc9e36cf92cd7b0479fdd493f4 /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentChat.svelte
|
||||
74545d012fa615b92d69ce6c5b660d4f61ba2501fe593a3cb92fd8df40136df6 /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentComposer.svelte
|
||||
abc7741fd784affd82a7a38b2d10d1714b77170da866cf2ea89ced3d43bfaa46 /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentPlanPanel.svelte
|
||||
3b87fdf4e8f2077cf0407bb2eadc418ca9e8aa4e781640b58ff9d88df73fc67f /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentSessionSidebar.svelte
|
||||
c1af4f03f60b8c677253c804316bfbc9629eb78d9846b5cff7d574befa1216e6 /opt/aigc-home/app/calliope-web/src/lib/components/agent/AgentToolCard.svelte
|
||||
932dcf780eec9d3f294bf90dbb04d25098b4a8c36a31113a7bb10162251c1e4e /opt/aigc-home/app/calliope-web/src/lib/components/agent/ReasoningPanel.svelte
|
||||
6dfc7d0b3a2372e3dd5213c48a7e5c6a7c2bb109c7fe102b9ddfab8f42217e77 /opt/aigc-home/app/calliope-web/src/lib/components/agent/WorkflowMentionMenu.svelte
|
||||
a84cf30f6cf6356c09b2623201e1f099f2843408553c724f76e362f5d844d2f7 /opt/aigc-home/app/calliope-web/src/lib/components/agent/agentPalette.ts
|
||||
770c0feb2009286ebdc455228a67117a80f94f58e4728475c17c57d968910f4c /opt/aigc-home/app/calliope-web/src/lib/components/desk/Artboard.svelte
|
||||
fe8483c2f5a4fdf9df112f0feae1d3170162b5c0fbf5bae73c1b6cc3126f2a31 /opt/aigc-home/app/calliope-web/src/lib/components/desk/DeskWorkflowRail.svelte
|
||||
f445d83de06804f132680eab34a6412444f1885a67a1aa832e62307f649ddaf3 /opt/aigc-home/app/calliope-web/src/lib/components/desk/InputRequirementBadge.svelte
|
||||
da087b4e93feeee3def4bafdf0ac931630fcd5b87b2293c4102e9b090eb3734f /opt/aigc-home/app/calliope-web/src/lib/components/desk/LibraryFilters.svelte
|
||||
cbdad9bfe085513184e2c30aefabaa92dbef38de4cbf2af763e2f74ad29e75e3 /opt/aigc-home/app/calliope-web/src/lib/components/desk/LibraryRow.svelte
|
||||
28583dfa4bcd6e605d3ba41ac889fdbd29d592949153a93bdd3670246a0a33cc /opt/aigc-home/app/calliope-web/src/lib/components/desk/ResultRail.svelte
|
||||
d78d68e3e3858d8cf0f22d06c9bb616187241264e3c67710f9f7561bb5ec4133 /opt/aigc-home/app/calliope-web/src/lib/components/desk/StudioDesk.svelte
|
||||
77518af58ceaaf4026eda2df5191ba244fff4b3ef21db54ae8692b759be86a6a /opt/aigc-home/app/calliope-web/src/lib/components/desk/TaskModeRail.svelte
|
||||
7bd0699f0d83702e04a06adc4cff8cdc4f62f5e6581b5c2deeb0e0b05d2077d7 /opt/aigc-home/app/calliope-web/src/lib/components/desk/WorkflowBay.svelte
|
||||
c093d1664194022d3edfb782d735df60e93a6fe838afb5ccbfb9b6079b2b1023 /opt/aigc-home/app/calliope-web/src/lib/components/desk/WorkflowPreview.svelte
|
||||
281bf5a5795b17d468b12dd4973004e5bdac458cd55e061feaaed69aa2c218c5 /opt/aigc-home/app/calliope-web/src/lib/components/generate/Composer.svelte
|
||||
ef72dc2367471507a4b5d15621854c761b99bba571876b94b07852369646260e /opt/aigc-home/app/calliope-web/src/lib/components/generate/ContextBar.svelte
|
||||
0e2943e5120efcf9ad620ba1d8a4e4c1658c88560c7c1d9b4032cd960f0a097a /opt/aigc-home/app/calliope-web/src/lib/components/generate/Inspector.svelte
|
||||
32f4c7c1a3a571a240741255fdf83173ef5d9d0f0a4626e02ea19d88fe613980 /opt/aigc-home/app/calliope-web/src/lib/components/generate/ParamChip.svelte
|
||||
1c7726496d94f822b1f6a72ccd7e0fd1a40b91e3adf64edc45f995d71df5da2b /opt/aigc-home/app/calliope-web/src/lib/components/generate/ParameterPopover.svelte
|
||||
18e20e2685e840f018b2eb9ba1928af5bd4fdf4cd8c2b2d65fd1f01da644aca8 /opt/aigc-home/app/calliope-web/src/lib/components/generate/ParamsPanel.svelte
|
||||
dd3d58c3bf9901d25790f44cc2eaa5835ea15335c3695202f565bb640efb2ed7 /opt/aigc-home/app/calliope-web/src/lib/components/generate/SlotTray.svelte
|
||||
f8205126227507fe1b50c9f57fec6412b830ad2234bf1ee61a5a458bb82ca3a2 /opt/aigc-home/app/calliope-web/src/lib/components/generate/TakeCard.svelte
|
||||
2307ee5f013d81f20315ec2118d801a3367837c8d018048d501f65770a173f26 /opt/aigc-home/app/calliope-web/src/lib/components/generate/TakeFeed.svelte
|
||||
beb37354c781810c670661be8ac35ccdf6b8fc9d23525a4fcc543cdb10b6ad0a /opt/aigc-home/app/calliope-web/src/lib/components/generate/context.ts
|
||||
da980feb2ea7e0eec93fac5cc0ee0c01a6be6f80d3c685e7eb22ecd00cc8741b /opt/aigc-home/app/calliope-web/src/lib/components/generate/schema.ts
|
||||
5cfda8936144415a0e001511128e39268cf4db39430b59882ff4ae80da9c93c6 /opt/aigc-home/app/calliope-web/src/lib/components/generate/takeDelete.svelte.ts
|
||||
ea14c626f5bedec1b8fb607af318e05454b36f913a63ad4808d9026380e0687d /opt/aigc-home/app/calliope-web/src/lib/components/generate/takes.ts
|
||||
eed1c80c2bb5ed54737c94adcc8f6461e57fb182218fca6ae0f87c61b0a1a0f8 /opt/aigc-home/app/calliope-web/src/lib/components/home/AProjectCard.svelte
|
||||
82de633bef1c92fecedd0618faaf4f3c6e869f365f8d22eda1631921f8cf56a5 /opt/aigc-home/app/calliope-web/src/lib/components/omni/AssetPickerModal.svelte
|
||||
0ba296a2ea05bb78ab3fdcd1ea526d894eb3eed0ed74f9149025abd68774413a /opt/aigc-home/app/calliope-web/src/lib/components/omni/MediaTile.svelte
|
||||
e587b7b07272f5f3c9935dce6092cb5fb4e678d0fa3653a02360f4dec7f478ae /opt/aigc-home/app/calliope-web/src/lib/components/omni/PillPopover.svelte
|
||||
47f04edf92ad2336893f77744762effef6e4acfeb53d657524ce1005505fb240 /opt/aigc-home/app/calliope-web/src/lib/components/omni/PillSelect.svelte
|
||||
5ef968def3ce3d7e134ef5ac10d07b098a9ec7a336593494ff7d967f7ff3158e /opt/aigc-home/app/calliope-web/src/lib/components/omni/PillStepper.svelte
|
||||
b895e524829484dd7306f1bb4cc2e9ce652a1968662c4f4d6a7d586cea6ba4f8 /opt/aigc-home/app/calliope-web/src/lib/components/refract/Hero.svelte
|
||||
e7399561fa10f35aaaffe4d085b1822e626a0396057883d4b5b5c24462f26a15 /opt/aigc-home/app/calliope-web/src/lib/components/settings/MemoryPanel.svelte
|
||||
24b303e3e0f2db36dafebef71353611f34fb75ac851730a1551621aaf1d0e219 /opt/aigc-home/app/calliope-web/src/lib/components/shell/AppShell.svelte
|
||||
25e74bb4200011048065b5c7de7566da902e2ed456316fdf786de1b1652d767a /opt/aigc-home/app/calliope-web/src/lib/components/shell/CommandPalette.svelte
|
||||
87a214fb486b27a8a7ed38caaef39b736a2fddb8be9b5a09c051762caf263442 /opt/aigc-home/app/calliope-web/src/lib/components/shell/ProjectScope.svelte
|
||||
9ebcf08567795b431537942481b461e400ab6a37a60e927e3fe559ddce6e65eb /opt/aigc-home/app/calliope-web/src/lib/components/shell/QueueTray.svelte
|
||||
fd205da624befed52999700d8a00ec48f167c376c51258b791ec4d8a2a345ac9 /opt/aigc-home/app/calliope-web/src/lib/components/shell/ShellPop.svelte
|
||||
f07a172763a2b0a7755ea20721ae20d7b2cb63aaeb5a6f3229c4ddedf99199e9 /opt/aigc-home/app/calliope-web/src/lib/components/shell/nav.ts
|
||||
16a3e74a27530b0a0065e425c128de12168243c5b35897f47bb5b7c9be2ae0c3 /opt/aigc-home/app/calliope-web/src/lib/components/studio/MediaSlot.svelte
|
||||
8b0e79f5d2563d2a73c61dad5dc721680d441787b26081dd2887097a9d9d1424 /opt/aigc-home/app/calliope-web/src/lib/components/studio/RefImageGrid.svelte
|
||||
b55a01704dad5ecdab05d3bddeb1d6e44923322fa7a9d4aa60558a702a231e07 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Button.svelte
|
||||
624cbcb67c9dc143a75b78359cd8c50c067dbff57cea528a7a309e0be29d8d96 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Card.svelte
|
||||
a72c982126332293887705350c8825f6232e2e1067abaf4a1bbfe1773aac473c /opt/aigc-home/app/calliope-web/src/lib/components/ui/ConfirmDialog.svelte
|
||||
bd56ad82b41fa23f64e908984c7a4c3ae6f24bdd5d1cfe2e66e21de25446d5ca /opt/aigc-home/app/calliope-web/src/lib/components/ui/Drawer.svelte
|
||||
7ab297b1f73b8bde8b7389f52721e2216fecdd4df91e5fefb21e424336194f30 /opt/aigc-home/app/calliope-web/src/lib/components/ui/EmptyState.svelte
|
||||
81798dc7007582e1025c246d4c3e9bb9ccfe7306f3199475b1581e58382005a5 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Icon.svelte
|
||||
db6130e0930b5a92d6af7fd613a898dcd117a9a7268823c1544d9c150cefe92d /opt/aigc-home/app/calliope-web/src/lib/components/ui/Modal.svelte
|
||||
0925761862b026b218cea0d6464cff4e67f1181bf4df4ff06f91e8ae472ea292 /opt/aigc-home/app/calliope-web/src/lib/components/ui/ProgressBar.svelte
|
||||
8f9304f189cb51702be7d426aad14edc05d6c68707baf8448cfe6de6a7951fed /opt/aigc-home/app/calliope-web/src/lib/components/ui/README.md
|
||||
08e0d4f85cc945a1fa3773edbbb8c725b7f9737bf5be5e7cd2a679bd9f9f90c1 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Skeleton.svelte
|
||||
1460161d521f5ffaf1853ccb85e33240bce1ce736fd4a2e0e081acdd7cd2c584 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Spinner.svelte
|
||||
c67bc6d80dc82801f9e9be21c201781dd2d0708dad857ee3425f42066ce5c6be /opt/aigc-home/app/calliope-web/src/lib/components/ui/StatusChip.svelte
|
||||
bbe0468da5495496bb76b75624eecd18438346b9c111319a77e3a2936f0a15f8 /opt/aigc-home/app/calliope-web/src/lib/components/ui/Switch.svelte
|
||||
c1c0c2f9edca20d964eddad0d02e53a1b332c53cef2dc8d5636cdf7af5bdef33 /opt/aigc-home/app/calliope-web/src/lib/components/ui/icons.ts
|
||||
0ab42d1c4781f6aa63aaabe90d40062d5f633a9941b10ed9c2dc7f5fc5a2472d /opt/aigc-home/app/calliope-web/src/lib/components/ui/modalLayers.ts
|
||||
61c450b53fc546a2f1b68551b691326abefd705fc6145287f25ea48b3c4b269f /opt/aigc-home/app/calliope-web/src/lib/components/video/ClipMonitor.svelte
|
||||
62649ec0b2e02c33b60651b31927bca0a589e3f68bc665d50438aa71bfe16161 /opt/aigc-home/app/calliope-web/src/lib/components/video/ClipSourceModal.svelte
|
||||
23225ace57828aa80cbd37fc00156b4170d31ddfbebb693c747059ad2032a280 /opt/aigc-home/app/calliope-web/src/lib/components/video/JobInputsDrawer.svelte
|
||||
38df3060885270e2e0d4e7a0eecad7d460fd88b5d65f3f65e6d3ba87ea9e3744 /opt/aigc-home/app/calliope-web/src/lib/components/video/PromptPreviewModal.svelte
|
||||
cde0d361ab0b5eb220da310d6297092c9c0cc8fb3b44a53eab84a1acc898ac1b /opt/aigc-home/app/calliope-web/src/lib/components/video/SceneFilmstrip.svelte
|
||||
116be76c6f77cd763279bbc632fefe9d5e1b8a220533ee92776e49a34e73e6cd /opt/aigc-home/app/calliope-web/src/lib/components/video/SceneScriptDrawer.svelte
|
||||
bcaa50dd928ae2b1ecf95697fad51852c2bf091ff391e94e749eb09035521322 /opt/aigc-home/app/calliope-web/src/lib/components/video/ShotBrief.svelte
|
||||
fe5823233fd94847258f02a8dbba7df1d1c84f0f45a9fde459dad297221f7e52 /opt/aigc-home/app/calliope-web/src/lib/components/video/VideoEditWorkspace.svelte
|
||||
f0d8365d82b65dcbb995cf93fe4769705bf9d9136b1bd60eb0e26387ccd488ec /opt/aigc-home/app/calliope-web/src/lib/components/workbench/AssetsStagePanel.svelte
|
||||
91c7eb1b74135fdb4780e86871d646dcaa23c6c7cd1d8d0cc69bc4ec044bfd99 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/JobChip.svelte
|
||||
a9b75b36f0c2f061caf61a3fe897ad4799a2cbeb3fbdf4cd90c907321a9e3869 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/PromptBlock.svelte
|
||||
6a01205bf0e4118f38a988f359650a0e9c3522567e7328e6783a32abb7a4ce03 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/ScriptStagePanel.svelte
|
||||
0cc25c48ed8bcc5d1312cae5da8ec8d43a719b88de1e9f1aecc34d216884ffbd /opt/aigc-home/app/calliope-web/src/lib/components/workbench/ShotStagePanel.svelte
|
||||
b64c479ec6e262c10607fd7bb9c5e3096e7ec9870369754e288f95293abb6fb2 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/StageStepper.svelte
|
||||
afd4ffe76429630d4ee6e30c06cc9e121a637e252bff78b0ff902990b1827c66 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/StoryboardStagePanel.svelte
|
||||
1b23da03f59c5d186e7e760c606e11e7fe22cb37ae8d90cfb813efc0dad9d597 /opt/aigc-home/app/calliope-web/src/lib/components/workbench/StyleStagePanel.svelte
|
||||
58407122bbb4c9cf4a4d3c280b7e27af7a8a51141ce2dd3eabe91644ea7843f7 /opt/aigc-home/app/calliope-web/src/lib/components/workflows/WorkflowBatchImportWizard.svelte
|
||||
77a2ac092a4c0bbb1f952e191b88704edd5815b783f439a022cd4f4baca5d16a /opt/aigc-home/app/calliope-web/src/lib/components/workflows/WorkflowLibrary.svelte
|
||||
d193924f8d50ac86de09cb8b1d44511c637811dbe5fb12bf8826633f5cac6d88 /opt/aigc-home/app/calliope-web/src/lib/components/workflows/WorkflowMetaDialog.svelte
|
||||
f7e318b7c2be62b8075568eaa1cfebbb002a5ac554cf26b7c6367ee6429de224 /opt/aigc-home/app/calliope-web/src/lib/dbtime.ts
|
||||
cdbcb72007dbc24c5fc13377aeeae8851644b306eb376e872155fda179c7acd3 /opt/aigc-home/app/calliope-web/src/lib/durationBudget.ts
|
||||
161c8c35241d55c6643f946e092d65748b8d55c6fdf5dad0fadf6e37e4fb3208 /opt/aigc-home/app/calliope-web/src/lib/endpointKind.ts
|
||||
d8cfc840dcccffadf3546d07ed1fe32c43e86b85599149e756ea80871ca3706a /opt/aigc-home/app/calliope-web/src/lib/events.ts
|
||||
9ae9634200ef0aaec1050a3638b32e2e1cf1dfdae089dca067a35cd2155fa7ec /opt/aigc-home/app/calliope-web/src/lib/formOptions.ts
|
||||
e22719d77911c34c6d49ce6fbffb655fbb9053bbe0a471cfd7bb36804e1adb89 /opt/aigc-home/app/calliope-web/src/lib/i18n.svelte.ts
|
||||
b48252457d2ce992db05b82dad361f3f971504a5b7c4e1f78f7e4f59eb062afc /opt/aigc-home/app/calliope-web/src/lib/i18n/de.ts
|
||||
8cc8df905076d916cbde2ba83ad3202ab3cfb87e38d4d2119023404dfaa6b7fc /opt/aigc-home/app/calliope-web/src/lib/i18n/en.ts
|
||||
837bf76c0ae34be1f6348bea071f47227ca0573d4c466574ad2ed99eb6db7df0 /opt/aigc-home/app/calliope-web/src/lib/i18n/es.ts
|
||||
332522881a6fc1ea9d227745f681ce484ae75367d56e61bcdad13a17487f3ce3 /opt/aigc-home/app/calliope-web/src/lib/i18n/fr.ts
|
||||
b2c9d3b530fe388781f6b85dbef4b9c71ff0652a42ad8faf6e7864e8ef5438c2 /opt/aigc-home/app/calliope-web/src/lib/i18n/ja.ts
|
||||
89862053863f268a6f3dff975be041b526ef6b5bb937c9660f97b4e80ce241e8 /opt/aigc-home/app/calliope-web/src/lib/i18n/ko.ts
|
||||
42b332e23e881092977434ee0bd446bb410834de262d96f13e0a7150e0da4bb4 /opt/aigc-home/app/calliope-web/src/lib/i18n/zh.ts
|
||||
60895e55f0860fba53ef9d80981b7ec13bc1d17c0ab5dd7d4aeb5ec930131b76 /opt/aigc-home/app/calliope-web/src/lib/ids.ts
|
||||
8354c545da56aa7d05edba6820614611db5c2846407f9ec69e4d2b0da4e29814 /opt/aigc-home/app/calliope-web/src/lib/jobLabels.ts
|
||||
b17722f478a633982c02191e02ef908297357d33b15d01944f59dce0c13c3ed9 /opt/aigc-home/app/calliope-web/src/lib/jobProgress.ts
|
||||
536733c170cc5266cd1f5d0a0eeda9a2a56c8f8c9613058c32a7a9d103063842 /opt/aigc-home/app/calliope-web/src/lib/jobStatus.ts
|
||||
d57e21fb3549b5c773073cb7d4c9b62bc79c16a9fa24d5d488450940be27ed9e /opt/aigc-home/app/calliope-web/src/lib/media/exportFrame.ts
|
||||
81762ea6ec15806d62298b838c48919744a6431df8a3300e28b6d214892b842e /opt/aigc-home/app/calliope-web/src/lib/media/lastFrame.ts
|
||||
345d9b8f82fb4893ecc2a0866581838e7b5d45e45259c40d40234d915545f929 /opt/aigc-home/app/calliope-web/src/lib/missingOutputs.svelte.ts
|
||||
3975f02ba220365dd32d4053d199800355c80c1a5d2a26942779df304fa042b8 /opt/aigc-home/app/calliope-web/src/lib/promptTemplates.ts
|
||||
57900f9c597c868a40ff6d142ef3d3b0e3ef364f4adddd967414688ecfbd7293 /opt/aigc-home/app/calliope-web/src/lib/reduceMotion.svelte.ts
|
||||
abd820a9a7a47f8eede494583eaa18b5f34b1abfe73260a6fb311f2e8ea01494 /opt/aigc-home/app/calliope-web/src/lib/referenceAgent.ts
|
||||
c037acebc7b878e00f680e65c5bfd6934b9eb8f7cc2e7d8c58afc4c87f93a927 /opt/aigc-home/app/calliope-web/src/lib/shot/api.ts
|
||||
7495bcb0d98e4dd91ad72c132b31724d97f226ae0420f862a5791d20888e2526 /opt/aigc-home/app/calliope-web/src/lib/shot/calibration/compositionPresets.ts
|
||||
e9301e261d4a12184f820ee0b0a547bf8c061bb65c58ee2a1967d89537b0c9b2 /opt/aigc-home/app/calliope-web/src/lib/shot/calibration/shotAxes.ts
|
||||
24ebe82dc55cc53cf3dfe0bc40275a9613353dc9116539acc6faf0b0aa597d80 /opt/aigc-home/app/calliope-web/src/lib/shot/calibration/shotSolver.ts
|
||||
5de1596d7827248cd5be5e576a54848d18b63225061beeccd2bd144ed678a2ea /opt/aigc-home/app/calliope-web/src/lib/shot/components/CaptureStrip.svelte
|
||||
d8450affdb98ce82325f9b0f860ca1f5493a0404c4f2dc52792758f25e7e145e /opt/aigc-home/app/calliope-web/src/lib/shot/components/ScenePanel.svelte
|
||||
abbc4622691782aa8ccddd55e43324642d715f2c5f78d32ef4f8d6ad1c86be6f /opt/aigc-home/app/calliope-web/src/lib/shot/components/ShotInspector.svelte
|
||||
810a24fb53b6458747ca981039fcde44a4b2f3b89242ec6f2be96e5f11e1d95d /opt/aigc-home/app/calliope-web/src/lib/shot/components/ShotSessionRail.svelte
|
||||
6c6b55ab12443cb7086a41448c2245c526784af60df5b8d3078f046de5cdc574 /opt/aigc-home/app/calliope-web/src/lib/shot/components/ShotViewport.svelte
|
||||
cc871911957ac769829dd487095488e0cf4cdbf44f99ace78df906fa351ae71c /opt/aigc-home/app/calliope-web/src/lib/shot/components/TimelineStrip.svelte
|
||||
6b18ef874ccd3c3508ac35788a8b9a1e924a79b4a7af9f7b9373e4f0b383e7e3 /opt/aigc-home/app/calliope-web/src/lib/shot/components/ViewportToolbar.svelte
|
||||
7de37792057307fd93a2df295308ccef609d9ec16ed17793eb8e2faf2295c626 /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/cameraUtils.ts
|
||||
2a07e4133ccc93420b64fcde15c43638219359cf42b1c8d9c849c44eb85cd2fe /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/jointConfig.ts
|
||||
a64e0938354f7363195285dfc564949b3dfac5f0be254177ce1378fdc00bea59 /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/mannequinFactory.ts
|
||||
0f94e29cb1d0b69d785dfaa326cee6a993c60472328f16664a5291d7e6caecf8 /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/mirror.ts
|
||||
d6569792a3a9e2dbff0f82b527e4d3b9d35874864c019f5dbc7aa8e4da947b25 /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/posture.ts
|
||||
18385f2f998666e864d5b67b6531b85e6d42c0d6de021a261f11199cb78b2fec /opt/aigc-home/app/calliope-web/src/lib/shot/helpers/primitiveFactory.ts
|
||||
480d36f1dabed4944b34471ed55d869e28f6e81875e6558c62a0b75d694cb783 /opt/aigc-home/app/calliope-web/src/lib/shot/motion/sampleTrack.ts
|
||||
7af90bd8c957299c282e12fca917f8fa56d2069b4ded99cc4798d1e730506f1c /opt/aigc-home/app/calliope-web/src/lib/shot/shotStore.svelte.ts
|
||||
f17a0e08c4c42336a8983f46f4970896daee72577e38fd4739f322d99c20e27d /opt/aigc-home/app/calliope-web/src/lib/shot/types/mannequin-js.d.ts
|
||||
d9c276a046c0ba7326d65293a56711913b8be107439470342220e98c6736af0b /opt/aigc-home/app/calliope-web/src/lib/skillFrontmatter.ts
|
||||
0a2075b0f882d9b354ed3d7a0a8913d9d9f2e0e380ad8ea4f655fc89f1986d97 /opt/aigc-home/app/calliope-web/src/lib/storage.ts
|
||||
07a9b47b8d793c23bc490b23d4bc7e4e5083e3780851525edc60c92118c43716 /opt/aigc-home/app/calliope-web/src/lib/toast.ts
|
||||
baa828f60b258b06032da3a2d289d353e1ba61b00bc3b06852d184936663d3ee /opt/aigc-home/app/calliope-web/src/lib/wideLayout.ts
|
||||
363320f14113146f617b12ead186db995fa99de71ad04be336ea1cb3e6f28453 /opt/aigc-home/app/calliope-web/src/routes/+layout.svelte
|
||||
c9a6362f526374fe88546908b976f897bccc8bb1b12a3797e176afc0d37a1172 /opt/aigc-home/app/calliope-web/src/routes/+layout.ts
|
||||
6c6481bf7b09e2e74400a112b66ad2430be6cdc843ebdc1c20d370bdacc174d8 /opt/aigc-home/app/calliope-web/src/routes/+page.svelte
|
||||
82665e45d52d9b8f182fe7395e4c8b2726beb62320de2f581b5b73d9c9d3987f /opt/aigc-home/app/calliope-web/src/routes/+page.ts
|
||||
bce9c599232e064eb946d9090391066ee8adcdc269797b8a874cca8effa4427d /opt/aigc-home/app/calliope-web/src/routes/agents/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/agents/+page.ts
|
||||
9949bca2d32eac10b2f9dfe91d0f6b539205259fa15b0a4c6443a6c1e600dc35 /opt/aigc-home/app/calliope-web/src/routes/app.css
|
||||
e7212b5a4b2eedcd6f107e5fcfb5ae8a2ded5bce3d12f7c279f6dfa4c0007660 /opt/aigc-home/app/calliope-web/src/routes/build-scene/+page.svelte
|
||||
f21b64d615dfbac548e7298fe8d130dfc7e0e148ffb00d6945ac470da791e002 /opt/aigc-home/app/calliope-web/src/routes/build-scene/+page.ts
|
||||
370b52d8e87153b57ef73eed1846a770eaf9b7c356b310a3fdcc8d3c295a403e /opt/aigc-home/app/calliope-web/src/routes/canvas/+page.svelte
|
||||
f21b64d615dfbac548e7298fe8d130dfc7e0e148ffb00d6945ac470da791e002 /opt/aigc-home/app/calliope-web/src/routes/canvas/+page.ts
|
||||
1e0197911d9752767374ca1fa1157ea534f24553fbea1e9db5fde0294af4f034 /opt/aigc-home/app/calliope-web/src/routes/canvas/[id]/+layout.svelte
|
||||
23de1dcb2b94ba7050764b7bfa04fd447aa36f50241f867783646ccb669a8658 /opt/aigc-home/app/calliope-web/src/routes/canvas/[id]/+page.svelte
|
||||
f21b64d615dfbac548e7298fe8d130dfc7e0e148ffb00d6945ac470da791e002 /opt/aigc-home/app/calliope-web/src/routes/canvas/[id]/+page.ts
|
||||
28c91d13beac10eba7964e562e90c8c4a3ec2652e69710970cd4733e9d42e1e5 /opt/aigc-home/app/calliope-web/src/routes/connections/+page.svelte
|
||||
bc76b47b593f0ae5e6946df26524d70e46b939889ccec090dc27a47cf71af140 /opt/aigc-home/app/calliope-web/src/routes/image/+page.svelte
|
||||
743d590d5e52e74a5b209448759c603c5b1ee5ae6540916354d496820c7acd7f /opt/aigc-home/app/calliope-web/src/routes/library/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/library/+page.ts
|
||||
5684b7f04e3eef40f349a5e98b22c6ebb05c9fa75bb4606a988b0f2ee65cf13a /opt/aigc-home/app/calliope-web/src/routes/models/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/models/+page.ts
|
||||
9f29a23ba5aed307d4f28c7091723269e6583d53357805f7e8893d468832fc53 /opt/aigc-home/app/calliope-web/src/routes/playground/+page.svelte
|
||||
f21b64d615dfbac548e7298fe8d130dfc7e0e148ffb00d6945ac470da791e002 /opt/aigc-home/app/calliope-web/src/routes/playground/+page.ts
|
||||
79812eaac33b12b43f539f0b957ebe4aeb64cf80eac03741ebfd4ba1cbf76335 /opt/aigc-home/app/calliope-web/src/routes/project/[id]/+page.ts
|
||||
f6ba8f210c2b8db20d401c57b6c84119ebda467b15ad9e41e8ba5ae89477354d /opt/aigc-home/app/calliope-web/src/routes/projects/+page.ts
|
||||
675613be31a3a5f95cb8675a42790425f4f864380d6b3c141ab028f5069fc9fa /opt/aigc-home/app/calliope-web/src/routes/settings/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/settings/+page.ts
|
||||
3c0f1d1b8d92c7b3e6372a83aaf5b3318442d135eb0de267cebfefb795d8ae49 /opt/aigc-home/app/calliope-web/src/routes/tasks/+page.svelte
|
||||
f2a395573851fe6916670ac392bedceaa5f93312c6560a33470b661e80132329 /opt/aigc-home/app/calliope-web/src/routes/video/+page.svelte
|
||||
32aa5a552f98d3a2ee487ed236de09daea24bd33ccf97f48bbe1f29fc639abbe /opt/aigc-home/app/calliope-web/src/routes/workbench/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/workbench/+page.ts
|
||||
31c0251a0f09a0540021a621410c084ff4d0b1fb9d409de0e461fde224f858db /opt/aigc-home/app/calliope-web/src/routes/workbench/[id]/+page.svelte
|
||||
58ca28942740b2ff08d6416473a2e8038f8a660017ce0b8b0d9ab3bb44453659 /opt/aigc-home/app/calliope-web/src/routes/workbench/[id]/+page.ts
|
||||
bc6dc994baaaf02c80ad390cb71965f2f15422704fa64c81f5b2c31f33b2ab13 /opt/aigc-home/app/calliope-web/src/routes/workflows/+page.svelte
|
||||
f21b64d615dfbac548e7298fe8d130dfc7e0e148ffb00d6945ac470da791e002 /opt/aigc-home/app/calliope-web/src/routes/workflows/+page.ts
|
||||
294450c3d45d4820d0bbf7f1c6e69aa0f3686efb6e3dbcdacf13e34e2d07b35e /opt/aigc-home/app/calliope-backend/src/calliope/routers/workbench.py
|
||||
acd3ba6e0ab29b92f5133358398f3544baa0ce2bea03560004a42e812b6abc8a /opt/aigc-home/app/calliope-backend/src/calliope/static/index.html
|
||||
acd3ba6e0ab29b92f5133358398f3544baa0ce2bea03560004a42e812b6abc8a /opt/aigc-home/releases/stage-HEL665-v5-35fd07a-20261015/build/index.html
|
||||
@@ -0,0 +1,79 @@
|
||||
660a6de4471ec76986e56f8d4467e4ed85a3ee5fdfc47f438410131c0f47f051 /opt/aigc-home/app/calliope-backend/src/calliope/__init__.py
|
||||
b00189efb92d1f8f77fdd9b912e7357bd6a7baaff998f364d55aa0029f7f9417 /opt/aigc-home/app/calliope-backend/src/calliope/agent/__init__.py
|
||||
7d0a16a798d89d7c8932c63698b8f4af91a61f7ec22b29f9e2efde75f06890b9 /opt/aigc-home/app/calliope-backend/src/calliope/agent/agents_registry.py
|
||||
f3ae5d869628d1cf2347e6b216d60dc7d4ea4fb82945fb348180bd04aca1b5d2 /opt/aigc-home/app/calliope-backend/src/calliope/agent/asset_agent.py
|
||||
45daa038f5dbfca19ec351e2e2c4480ed8abc3fa51adf62b46dff714221afe45 /opt/aigc-home/app/calliope-backend/src/calliope/agent/continuity.py
|
||||
300f043668e003bdf98f73cce40ba0251d94356092e5ad1aafe29ee1d4c97e22 /opt/aigc-home/app/calliope-backend/src/calliope/agent/coverage_agent.py
|
||||
2245f0e117e728382554155c8f3e93f5304913c595cf070d9ad29daafb9bd088 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/__init__.py
|
||||
077cebb46d3ecccc1336b9c92a5c82ad21cdd57e55644df9298a5495374bc09d /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/log.py
|
||||
c9429604ecde92dfc95f463fcfbbf2dd0153d91fd3155696238a1713a2cb8dd6 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/loop.py
|
||||
5233ad11b93f072d456861829d0f856436a9f330c2e4870aa2dad15e3bfc117a /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/orchestrator.py
|
||||
f9e2f2f5ab4084c53866621e9c17eb388fd6dd9b4cb06be6c067ee03490f4da5 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/__init__.py
|
||||
ab17c10c8e372ff94659047dd94b56bdeecf79aa88bce60821538ab4d5e4d875 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/canvas.py
|
||||
1e7d44d9c9d8031bca9d3537b2d96d05bf9087e64a3ff6a33eee76c09001157e /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/comfy_mcp.py
|
||||
03c9041e6cc8c443e56d2e0e09effa15107ad7b6bc4048e6b56fdfccd623a2d7 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/interaction.py
|
||||
7fe0366e33a1600766914a0b7bcc2bc0968bb39850370dec35697055ba8e8c1a /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/memory.py
|
||||
58cc3518674cd689eade1c2d401d3fb943c5f2429af66da537b6b55ed00d95df /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/render.py
|
||||
15d479331934ed05c23e19f24b131e566ef528550ab9720fd570d4b1bf3e977b /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/script.py
|
||||
e9f736490d5ef6951ee0ce2ace3516bc2f6902c6fa3b1ef6ea9b6e7123f5f8d1 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/shot_builder.py
|
||||
ca11d12eb274a6852af2d091dbe453df582543cfb2d03051528bc629c8f0d024 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/skills.py
|
||||
8c49aea52a52a59e31269c8e79c988f4a1b3d676c23040f6506fab94789e4a20 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/story.py
|
||||
5dc7f0e6db53eaebe523b1b22b0e77ef06683c9182a52be7ab54f3c8d9d66395 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/system.py
|
||||
2a2d4606539c42f2f3acb7b93c73f571b66f53d4ead934bb1d47547825226978 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/plugins/workspace.py
|
||||
7001d912ae819bd25a27db28cffb77b62c53ec28eae9bef320d46d967d195a81 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/policy.py
|
||||
09e935288ad6c5c3579c26e948beac6d14df74978334fe4ffa4b000e8a600edb /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/prompts.py
|
||||
25e0716d36a6598fe516d2d4838cfe54eedf00f390385ede5c252edc3a4a94c0 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/registry.py
|
||||
0495ee7f9ffefe13256688e47b23f68d6361bbef527b7ed4a5bc7f4a8998e1b8 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/runner.py
|
||||
90405bbb07c7cbe1283ead1ae901c8183756a93667e71f4ce585c0a543853198 /opt/aigc-home/app/calliope-backend/src/calliope/agent/harness/tools.py
|
||||
5d225d80e8886e04e9b02d18b0bae358b65f4e66beec1280c4f500e761b1d752 /opt/aigc-home/app/calliope-backend/src/calliope/agent/llm.py
|
||||
beadb0e82e8eb47356f81d81ff41271da97cc51c90707c89ee2908ed095d0380 /opt/aigc-home/app/calliope-backend/src/calliope/agent/prompts.py
|
||||
feffad04e8a668d4426fc6f9021213a9d1122221e685aa5ba30bcaa9611faf45 /opt/aigc-home/app/calliope-backend/src/calliope/agent/script_agent.py
|
||||
483c6658b7573382f3a83add57b9f7e27e83ff1388bf0b900837f81c2b47c56e /opt/aigc-home/app/calliope-backend/src/calliope/agent/skills_store.py
|
||||
2caa50c0e246b542f331c7a52778b5c13331cf3623a431c14bbdc4362674f138 /opt/aigc-home/app/calliope-backend/src/calliope/agent/video_agent.py
|
||||
1d3488bcc2eadcd8a8f2e84ab4f6e9bdf52096b8af637c4da399db041d5a0543 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/__init__.py
|
||||
e6faad052e3139d921936c7a73e2ee7fb55a3bb3c9fc256535dca5fa6f01ac14 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/client.py
|
||||
f8bf4d1b91d959044de1dbc4aeb11bf0bb521f51f1928d36a46c670381a08ed7 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/dry_run.py
|
||||
fc99a623850b581ae38843bbc3baf1b71ca9fd633e6103a34cb809a345e5a647 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/endpoints.py
|
||||
da82aad77fa561fea5fd6bdb553feaff61ce753a890eea2caa146a5813981952 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/lint.py
|
||||
12848b11ca346ee3c7703becb96469609b1b68612405a7be3cb7e8fca04291b5 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/metadata.py
|
||||
460d9463dabc8b055d1bdd81e5b908ad8bfd198da1560e3fe0f859c9cd1dfdf6 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/output_map.py
|
||||
d300c6f33f30bc9a1d9a4c5163b3a2f71795f9e349849205ec42f85f3a202824 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/parser.py
|
||||
8ac1417f0f78d952cdb219b10811a6ed7d4ce3bb0d561708858c4a8f5d15b45d /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/patcher.py
|
||||
6629961d33204cbe5b3fc3d8a5a0a4de0c86d235e73f542d191429cf7f4bd2ec /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/preflight.py
|
||||
4ca33343fc3f20e0fb82558cb428548f6415af04fb90213a694fb759515732f2 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/profiles.py
|
||||
21b024f44a3cba96db1b95a4c3a82591e6af921a31756378970da506ca0f9acf /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/registry.py
|
||||
355aca29ad4283f3cc600181fc0397cd06f8a63d3fe537b6fd10fc92bfcbe5a9 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/roles.py
|
||||
adc34e80cca7a2b38cc834a713c9e64001caac84413af288389e5554e304bab6 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/smart_fill.py
|
||||
ebb91f0d291b042d74a44019cfd69dcd553b0f0f96277b7795e52d4dbb7201d1 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/ui_convert.py
|
||||
db00a79a92d0add6ea3c2509d629c36cbe457c667e388fff50eeec7158d5b9d8 /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/ui_widget_orders.py
|
||||
c27fca69a604705b06809fdd692975ca0e7a08d05d558172962f8910a6a0491d /opt/aigc-home/app/calliope-backend/src/calliope/comfyui/validate.py
|
||||
94cda57274c512feac82ab3c97d9c680abf6706009727d6a6791cef690994001 /opt/aigc-home/app/calliope-backend/src/calliope/config.py
|
||||
9c404874ccbf1d3d49ab509b112f52ecd6a037488f3b0e05e5a08c5ad74123dd /opt/aigc-home/app/calliope-backend/src/calliope/db.py
|
||||
4b3f2620e25c17bf9587beda3b5e73284bf83c6b5fb6beaf1c6e73a73dc560f3 /opt/aigc-home/app/calliope-backend/src/calliope/events/__init__.py
|
||||
a9be4db2e810135a3482432316925b0bed8b2fab9e1395333831b7f5246f987b /opt/aigc-home/app/calliope-backend/src/calliope/events/bus.py
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /opt/aigc-home/app/calliope-backend/src/calliope/export/__init__.py
|
||||
cabc42a31999fa1e185b07c74f09b303f793a809127ce6039547c86657d9491b /opt/aigc-home/app/calliope-backend/src/calliope/export/runner.py
|
||||
ee776991e7fbeef9d0a370a734bb9428e015ef9f18b0cbf8f3a8e772614922d9 /opt/aigc-home/app/calliope-backend/src/calliope/main.py
|
||||
ff156ab234a8ea57a120e31c83baa591e613fa776d74cf29f2e75468bcff4e71 /opt/aigc-home/app/calliope-backend/src/calliope/models/__init__.py
|
||||
81bbb9b938d452f41369982b7434520d173ff68b0242278c602f5d489c00527a /opt/aigc-home/app/calliope-backend/src/calliope/models/schemas.py
|
||||
e4a4676265849f0dce021abccc1e7cc9ae6605a60eac8cc7e0a47246ff56bfa8 /opt/aigc-home/app/calliope-backend/src/calliope/poses.py
|
||||
dbe2691f035386e14a3be26725cfba67baf7f6f712fc0061740ea920a05d9f4c /opt/aigc-home/app/calliope-backend/src/calliope/queue/__init__.py
|
||||
22724a06ad9d6fced7572d52392cf2d22c793614097dbab42be9c1bc373b2ab0 /opt/aigc-home/app/calliope-backend/src/calliope/queue/manager.py
|
||||
ee3e91bf7e330ff1981aece7fc4bb475acfd71153ab59db99736ac765a57ce2d /opt/aigc-home/app/calliope-backend/src/calliope/queue/worker.py
|
||||
1805a0888c8dc007500cc1e24030a03555c6619e6fa56f937844831995cba5b8 /opt/aigc-home/app/calliope-backend/src/calliope/queue/workflow_test.py
|
||||
cbacc8761833b64aa017a3df2d933c3897f9f19997044efaea49f206ec1b205a /opt/aigc-home/app/calliope-backend/src/calliope/routers/__init__.py
|
||||
780483a9389c939d632a79e248e58053e0c468f65a27b0a90337412cc0fe1ec8 /opt/aigc-home/app/calliope-backend/src/calliope/routers/agent.py
|
||||
315b6318864370449c3570ae705046501f696ac86cb370de189b05be26d79a05 /opt/aigc-home/app/calliope-backend/src/calliope/routers/assets.py
|
||||
a05c24f6c26d8a8432e8c73deb8acfb1e71fa4f611c10e80ba19dd6c10985e9d /opt/aigc-home/app/calliope-backend/src/calliope/routers/canvas.py
|
||||
6195a37ef48e80a7f423fefcc2b2939c2270542ca4ce81ef58ca06da356b312d /opt/aigc-home/app/calliope-backend/src/calliope/routers/comfyui.py
|
||||
be7f140608380aa93d23893ba97b222fcf5b2a288ca81e5ccb53731875d2cdff /opt/aigc-home/app/calliope-backend/src/calliope/routers/events.py
|
||||
45c1952d866f76ab84cbc221541250ad6e9ae79d06d4e7c7cb4176d395f9d196 /opt/aigc-home/app/calliope-backend/src/calliope/routers/jobs.py
|
||||
3827af29c2645baee4a9ccbbc1d77155e830585bd033955b061bc320b6fb7de3 /opt/aigc-home/app/calliope-backend/src/calliope/routers/library.py
|
||||
ce4f8f21cff507cafdeece1f9427b02172c550da53327095167964cb97ca2145 /opt/aigc-home/app/calliope-backend/src/calliope/routers/playground.py
|
||||
c36d32df6571ecb1bf3bd17be48e47c0cc3864b79db51d764dcf95befbe78383 /opt/aigc-home/app/calliope-backend/src/calliope/routers/projects.py
|
||||
398cf96846e60c8e60907121b4a21f9086c3b03f86e0ad2ad4082acaa9fb4678 /opt/aigc-home/app/calliope-backend/src/calliope/routers/scenes.py
|
||||
a4fedd5c2285ffa0d28b4176e9014d46c27d83b4150a81b2de63ef9b921865cd /opt/aigc-home/app/calliope-backend/src/calliope/routers/settings.py
|
||||
bd235fde191c512e0592e269c8d1c8d8784ef8bce07de6d62a93626fac249744 /opt/aigc-home/app/calliope-backend/src/calliope/routers/shots.py
|
||||
64b3b8e96beaf6b5fa50114188f5f101c09794dcfc5b47ce79174f43445b4bbf /opt/aigc-home/app/calliope-backend/src/calliope/routers/story.py
|
||||
294450c3d45d4820d0bbf7f1c6e69aa0f3686efb6e3dbcdacf13e34e2d07b35e /opt/aigc-home/app/calliope-backend/src/calliope/routers/workbench.py
|
||||
455073355ada5eb2807f90496ff3a28b3e1f9f06bbc9e262a8da354d6aec15ae /opt/aigc-home/app/calliope-backend/src/calliope/routers/workflows.py
|
||||
@@ -0,0 +1,49 @@
|
||||
{"image_wf": 1, "video_wf": 2, "endpoint": "e9c0ef15-ab9a-4956-81d4-2d42425feea2"}
|
||||
{'dual': 3, 'h3': 4, 'project': 1}
|
||||
RUN e2e/hel728.cjs
|
||||
PASS 默认主题为夜片场
|
||||
PASS night 保留原编辑组件和正反向草稿
|
||||
PASS day 保留原编辑组件和正反向草稿
|
||||
PASS grade 保留原编辑组件和正反向草稿
|
||||
PASS bluehour 保留原编辑组件和正反向草稿
|
||||
PASS 刷新恢复主题和草稿
|
||||
PASS 方向键移动主题选项焦点
|
||||
PASS Esc 关闭并恢复入口焦点
|
||||
PASS 创作台兼容入口保留全部参数及片段
|
||||
PASS 隔离真实队列已收到任务
|
||||
PASS night 上传素材和运行中编辑状态保留
|
||||
PASS day 上传素材和运行中编辑状态保留
|
||||
PASS grade 上传素材和运行中编辑状态保留
|
||||
PASS bluehour 上传素材和运行中编辑状态保留
|
||||
PASS 切主题后原任务完成且产物归属不变
|
||||
PASS 切主题保留视频节点和暂停状态
|
||||
PASS 切主题保留智能体任务输入组件和草稿
|
||||
PASS 切主题保留未保存设置
|
||||
PASS 1440,900 night 导航入口和四主题完整可见
|
||||
PASS 1440,900 day 导航入口和四主题完整可见
|
||||
PASS 1440,900 grade 导航入口和四主题完整可见
|
||||
PASS 1440,900 bluehour 导航入口和四主题完整可见
|
||||
PASS 1366,768 night 导航入口和四主题完整可见
|
||||
PASS 1366,768 day 导航入口和四主题完整可见
|
||||
PASS 1366,768 grade 导航入口和四主题完整可见
|
||||
PASS 1366,768 bluehour 导航入口和四主题完整可见
|
||||
PASS 1280,720 night 导航入口和四主题完整可见
|
||||
PASS 1280,720 day 导航入口和四主题完整可见
|
||||
PASS 1280,720 grade 导航入口和四主题完整可见
|
||||
PASS 1280,720 bluehour 导航入口和四主题完整可见
|
||||
PASS 模型连接入口保留页签参数
|
||||
PASS 旧项目链接保留阶段参数
|
||||
PASS 全局搜索保留 视频创作
|
||||
PASS 全局搜索保留 大语言模型
|
||||
PASS 全局搜索保留 试验台
|
||||
PASS 全局搜索保留 三维搭景
|
||||
PASS night 首次绘制前恢复主题及底色
|
||||
PASS day 首次绘制前恢复主题及底色
|
||||
PASS grade 首次绘制前恢复主题及底色
|
||||
PASS bluehour 首次绘制前恢复主题及底色
|
||||
PASS 存储被禁用仍可切换且显示提示
|
||||
PASS 存储被禁用保留输入
|
||||
PASS 无效存储回退夜片场
|
||||
PASS 浏览器无运行错误
|
||||
TOTAL 44
|
||||
FAILED SCRIPTS []
|
||||
@@ -0,0 +1,47 @@
|
||||
# HEL-728 B0 自测与已知限制
|
||||
|
||||
## 通过
|
||||
|
||||
- `npm run check`:0 错误;1 个第五版已存在的视频字幕警告。干净第五版副本同为 0 错误、1 警告。
|
||||
- `npm test`:存储 SSR 安全、局域网随机 ID、技能正文、视频尾帧算法四组既有校验全部通过。
|
||||
- `npm run build`:静态构建成功;`git diff --check` 通过。
|
||||
- 本批全部修改的前端文件:Prettier 检查通过。
|
||||
- `e2e/hel728.cjs`:**44 项通过、0 个浏览器运行错误**。在一次性本地后端、假 ComfyUI、假 LLM 上检查;真实 HTTP 上传首尾帧和队列生成,四主题之间切换时原编辑 DOM 节点、正反向草稿、已上传文件、运行中的任务 ID/工作流归属不变,完成后仍可显示视频且默认暂停。另检查智能体输入、未保存设置、刷新恢复、方向键/Enter/Esc 与焦点返回、非法/禁用存储、旧项目链接及完整 URL 来源上下文。
|
||||
- 框架脚本被阻止时检查四个主题:head 脚本与阻塞样式表独立恢复主题与正确页面底色,没有依赖框架完成后才着色。
|
||||
- 人工查看 1440×900、1366×768、1280×720 截图:主题卡片完整可见、侧栏不溢出、浅色文字与面板正常。截图采用减少动效模式消除过渡帧;产品开关与系统减少动效沿用既有机制。
|
||||
|
||||
## 存量失败及原版对照
|
||||
|
||||
本批未修改 `calliope-backend`:`git diff --quiet 35fd07a -- calliope-backend` 退出 0。
|
||||
|
||||
后端全量 `pytest -q`:**834 通过、5 失败、6 跳过**。在 git archive 导出的干净 `35fd07a` 副本中,用相同解释器/依赖和 `PYTHONPATH=src` 单独复跑这五项,全部复现:
|
||||
|
||||
1. `test_agent_comfy_mcp.py::test_comfy_server_info_scoping`:`agent_events` 表不存在。
|
||||
2. `test_continuity.py::test_h3_messages_bind_neighbor_shots_and_keep_file_slots`:Linux 上 Windows 路径的名称提取与断言不符。
|
||||
3. `test_h3_profile.py::test_resolve_h3_references_prefers_form_files_over_story`:Linux 上 Windows 路径的名称提取与断言不符。
|
||||
4. `test_scene_settings.py::test_preview_prompt_uses_form_references_not_story_cast`:同类 Windows 路径名称问题。
|
||||
5. `test_script_scene_count.py::test_script_regenerate_keeps_expanded_count`:重新生成剧本返回 500,断言预期 200。
|
||||
|
||||
全仓 `npm run lint`:原版 68 个文件的 Prettier 失败,本批剩余 63 个,均为未修改文件;ESLint 本身缺少 v9 配置文件,原仓未提供。没有为本批新增独立 lint 规则或格式覆盖。完整输出附在本目录。
|
||||
|
||||
现有两份端到端脚本均在本批和干净第五版副本中失败,未删断言或改正式功能迎合旧测试:
|
||||
|
||||
- `e2e/reference/check.cjs`:前 8 项通过,随后等待第五版已移除的 `.result-item` 历史栏超时;当前 UI 用作品画布与独立生成历史弹层。
|
||||
- `e2e/reference/check-copy-fallback.cjs`:等待旧版「编辑内容并带回项目」按钮超时;当前第五版已重排成果编辑流程。
|
||||
|
||||
这些脚本没有被本批修改;原版和本批失败日志都保留。不能据此宣称现有端到端全绿。
|
||||
|
||||
## 运行方式
|
||||
|
||||
安装仓库锁定依赖后,从仓库根目录运行:
|
||||
|
||||
```sh
|
||||
# 指向环境已有的 Playwright 和 Chromium;按环境需要提供系统库路径。
|
||||
PLAYWRIGHT_MODULE_PATH=/path/to/playwright-core \
|
||||
CHROMIUM_EXECUTABLE_PATH=/path/to/chromium \
|
||||
HEL728_TESTS=e2e/hel728.cjs python3 e2e/run-hel728.py
|
||||
```
|
||||
|
||||
runner 检查端口空闲,保留上次一次性数据/证据到带时间戳的目录,再启动自己的本地服务;结束时停止自己创建的进程组。默认还会运行两份旧脚本并报告失败。用 `HEL728_WEB_DIR` 可将前端改为干净基线副本,完成同环境对照。
|
||||
|
||||
未验证真实 GPU/付费模型的生成质量;没有操作测试站用户资料或执行真实收费生成。B0 只验证主题与导航地基,B1–B5 的新页面布局、通用存入项目及最终全站动效不在本次完成范围。
|
||||
+397
@@ -0,0 +1,397 @@
|
||||
// B0 state preservation and navigation checks on the disposable reference stack.
|
||||
const { chromium } = require(
|
||||
process.env.PLAYWRIGHT_MODULE_PATH || "playwright",
|
||||
);
|
||||
const assert = require("node:assert/strict"),
|
||||
fs = require("node:fs"),
|
||||
path = require("node:path");
|
||||
const out = path.resolve("e2e/shots/hel728"),
|
||||
f = JSON.parse(fs.readFileSync("e2e/shots/reference/fixtures.json"));
|
||||
const WEB = "http://127.0.0.1:5173",
|
||||
API = "http://127.0.0.1:8247";
|
||||
const themes = ["night", "day", "grade", "bluehour"],
|
||||
names = ["夜片场", "日光棚", "调色间", "蓝调时刻"];
|
||||
const checks = [];
|
||||
function ok(name, value) {
|
||||
assert(value, name);
|
||||
checks.push(name);
|
||||
console.log("PASS", name);
|
||||
}
|
||||
async function change(p, id) {
|
||||
await p.getByRole("button", { name: "主题", exact: true }).click();
|
||||
await p
|
||||
.locator(".choice")
|
||||
.filter({ hasText: names[themes.indexOf(id)] })
|
||||
.click();
|
||||
await p.keyboard.press("Escape");
|
||||
await p.waitForFunction(
|
||||
(id) => document.documentElement.dataset.theme === id,
|
||||
id,
|
||||
);
|
||||
}
|
||||
async function waitJob(id) {
|
||||
for (let i = 0; i < 120; i++) {
|
||||
const j = (
|
||||
await fetch(API + "/api/playground/jobs").then((r) => r.json())
|
||||
).find((j) => j.id === id);
|
||||
assert(j, "submitted job remains in queue");
|
||||
if (j.status === "done") return j;
|
||||
assert(!["failed", "cancelled"].includes(j.status), JSON.stringify(j));
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
}
|
||||
throw Error("job timed out");
|
||||
}
|
||||
(async () => {
|
||||
const browser = await chromium.launch({
|
||||
executablePath: process.env.CHROMIUM_EXECUTABLE_PATH,
|
||||
headless: true,
|
||||
args: ["--no-sandbox"],
|
||||
});
|
||||
const errors = [];
|
||||
const modepath = "e2e/fake_mode.json",
|
||||
saved = fs.existsSync(modepath) ? fs.readFileSync(modepath) : null;
|
||||
try {
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
}),
|
||||
p = await context.newPage();
|
||||
p.on(
|
||||
"pageerror",
|
||||
(e) => (errors.push(e.message), console.error("PAGEERROR", e.stack)),
|
||||
);
|
||||
await p.goto(WEB + "/image?wf=" + f.dual);
|
||||
await p.locator("#desk-prompt").waitFor();
|
||||
ok(
|
||||
"默认主题为夜片场",
|
||||
await p.evaluate(
|
||||
() => document.documentElement.dataset.theme === "night",
|
||||
),
|
||||
);
|
||||
await p.locator("#desk-prompt").fill("切换主题时保留的半篇提示词");
|
||||
await p.locator("#desk-negative").fill("反向草稿");
|
||||
await p
|
||||
.locator("#desk-prompt")
|
||||
.evaluate((e) => (window.__promptElement = e));
|
||||
for (const id of themes) {
|
||||
await change(p, id);
|
||||
ok(
|
||||
id + " 保留原编辑组件和正反向草稿",
|
||||
(await p
|
||||
.locator("#desk-prompt")
|
||||
.evaluate(
|
||||
(e) =>
|
||||
e === window.__promptElement &&
|
||||
e.value === "切换主题时保留的半篇提示词",
|
||||
)) && (await p.locator("#desk-negative").inputValue()) === "反向草稿",
|
||||
);
|
||||
}
|
||||
await p.reload();
|
||||
await p.locator("#desk-prompt").waitFor();
|
||||
ok(
|
||||
"刷新恢复主题和草稿",
|
||||
(await p.evaluate(
|
||||
() => document.documentElement.dataset.theme === "bluehour",
|
||||
)) &&
|
||||
(await p.locator("#desk-prompt").inputValue()) ===
|
||||
"切换主题时保留的半篇提示词",
|
||||
);
|
||||
// Keyboard selection and focus return use the existing layered Modal.
|
||||
const trigger = p.getByRole("button", { name: "主题", exact: true });
|
||||
await trigger.click();
|
||||
await p.locator(".choice").first().focus();
|
||||
await p.keyboard.press("ArrowDown");
|
||||
ok(
|
||||
"方向键移动主题选项焦点",
|
||||
await p
|
||||
.locator(".choice")
|
||||
.nth(1)
|
||||
.evaluate((e) => document.activeElement === e),
|
||||
);
|
||||
await p.keyboard.press("Enter");
|
||||
await p.keyboard.press("Escape");
|
||||
ok(
|
||||
"Esc 关闭并恢复入口焦点",
|
||||
await trigger.evaluate((e) => document.activeElement === e),
|
||||
);
|
||||
// All source URL parameters survive the temporary gateway.
|
||||
const q = new URLSearchParams({
|
||||
kind: "video",
|
||||
wf: String(f.h3),
|
||||
from: "workbench",
|
||||
project: String(f.project),
|
||||
stage: "shot",
|
||||
source_kind: "shot",
|
||||
source_id: "s1",
|
||||
label: "镜头一",
|
||||
prompt: "上下文提示词",
|
||||
negative: "上下文反向",
|
||||
duration: "6",
|
||||
mode: "image2video",
|
||||
});
|
||||
await p.goto(WEB + "/create?" + q + "#source");
|
||||
await p.locator("#desk-prompt").waitFor();
|
||||
ok(
|
||||
"创作台兼容入口保留全部参数及片段",
|
||||
new URL(p.url()).pathname === "/video" &&
|
||||
[...q].every(([k, v]) => new URL(p.url()).searchParams.get(k) === v) &&
|
||||
new URL(p.url()).hash === "#source",
|
||||
);
|
||||
await p.goto(WEB + "/video?wf=" + f.h3);
|
||||
await p.getByRole("button", { name: "管理素材", exact: true }).click();
|
||||
const first = p
|
||||
.locator(".a-slot")
|
||||
.filter({ has: p.getByText("首帧", { exact: true }) }),
|
||||
last = p
|
||||
.locator(".a-slot")
|
||||
.filter({ has: p.getByText("尾帧", { exact: true }) });
|
||||
await first.waitFor();
|
||||
await first
|
||||
.locator("input[type=file]")
|
||||
.setInputFiles("calliope-web/static/refract/coast.jpg");
|
||||
await last
|
||||
.locator("input[type=file]")
|
||||
.setInputFiles("calliope-web/static/refract/arch.jpg");
|
||||
await first.locator("img").waitFor();
|
||||
await last.locator("img").waitFor();
|
||||
await p.locator("#desk-prompt").fill("上传和进行中任务保留");
|
||||
const sources = [
|
||||
await first.locator("img").getAttribute("src"),
|
||||
await last.locator("img").getAttribute("src"),
|
||||
];
|
||||
await p.getByRole("button", { name: "完成", exact: true }).click();
|
||||
await p.locator("#desk-prompt").evaluate((e) => (window.__videoPrompt = e));
|
||||
fs.writeFileSync(
|
||||
modepath,
|
||||
JSON.stringify({ mode: "ok", delay_sec: 12, videos: true }),
|
||||
);
|
||||
const response = p.waitForResponse(
|
||||
(r) =>
|
||||
r.url().endsWith("/api/playground/generate") &&
|
||||
r.request().method() === "POST",
|
||||
);
|
||||
await p.locator(".gen").click();
|
||||
const job = (await (await response).json()).job;
|
||||
ok("隔离真实队列已收到任务", !!job.id);
|
||||
for (const id of themes) {
|
||||
await change(p, id);
|
||||
ok(
|
||||
id + " 上传素材和运行中编辑状态保留",
|
||||
(await p.locator(".media-token img").nth(0).getAttribute("src")) ===
|
||||
sources[0] &&
|
||||
(await p.locator(".media-token img").nth(1).getAttribute("src")) ===
|
||||
sources[1] &&
|
||||
(await p
|
||||
.locator("#desk-prompt")
|
||||
.evaluate(
|
||||
(e) =>
|
||||
e === window.__videoPrompt &&
|
||||
e.value === "上传和进行中任务保留",
|
||||
)),
|
||||
);
|
||||
}
|
||||
const completed = await waitJob(job.id);
|
||||
ok(
|
||||
"切主题后原任务完成且产物归属不变",
|
||||
completed.workflow_id === f.h3 && completed.output_paths.length > 0,
|
||||
);
|
||||
await p.locator(".artboard video").waitFor();
|
||||
await change(p, "day");
|
||||
ok(
|
||||
"切主题保留视频节点和暂停状态",
|
||||
await p
|
||||
.locator(".artboard video")
|
||||
.evaluate((v) => v.paused && !v.autoplay),
|
||||
);
|
||||
await p.screenshot({ path: path.join(out, "uploaded-video-state.png") });
|
||||
await p.goto(WEB + "/agents");
|
||||
await p.locator(".agent-composer textarea").fill("智能体任务输入草稿");
|
||||
await p
|
||||
.locator(".agent-composer textarea")
|
||||
.evaluate((e) => (window.__agentElement = e));
|
||||
await change(p, "night");
|
||||
ok(
|
||||
"切主题保留智能体任务输入组件和草稿",
|
||||
await p
|
||||
.locator(".agent-composer textarea")
|
||||
.evaluate(
|
||||
(e) =>
|
||||
e === window.__agentElement && e.value === "智能体任务输入草稿",
|
||||
),
|
||||
);
|
||||
// Preserve dirty settings separately from the appearance section.
|
||||
await p.goto(WEB + "/settings");
|
||||
await p.locator("input[type=number]").first().fill("2");
|
||||
await change(p, "grade");
|
||||
ok(
|
||||
"切主题保留未保存设置",
|
||||
(await p.locator("input[type=number]").first().inputValue()) === "2",
|
||||
);
|
||||
await p.getByRole("button", { name: "放弃", exact: true }).click();
|
||||
await p.goto(WEB + "/settings?tab=appearance");
|
||||
await p.locator(".choices").waitFor();
|
||||
await p.emulateMedia({ reducedMotion: "reduce" });
|
||||
for (const size of [
|
||||
[1440, 900],
|
||||
[1366, 768],
|
||||
[1280, 720],
|
||||
]) {
|
||||
await p.setViewportSize({ width: size[0], height: size[1] });
|
||||
for (const id of themes) {
|
||||
await p
|
||||
.locator(".choice")
|
||||
.filter({ hasText: names[themes.indexOf(id)] })
|
||||
.click();
|
||||
ok(
|
||||
`${size} ${id} 导航入口和四主题完整可见`,
|
||||
(await p
|
||||
.locator(".sidebar")
|
||||
.evaluate((e) => e.scrollHeight <= e.clientHeight + 1)) &&
|
||||
(await p
|
||||
.locator(".choices")
|
||||
.evaluate((e) => e.getBoundingClientRect().right <= innerWidth)),
|
||||
);
|
||||
await p.screenshot({
|
||||
path: path.join(out, `${id}-${size[0]}x${size[1]}.png`),
|
||||
});
|
||||
}
|
||||
}
|
||||
await p.goto(WEB + "/model-connections?tab=llm&keep=hello#models");
|
||||
await p.locator(".sidebar").waitFor();
|
||||
ok(
|
||||
"模型连接入口保留页签参数",
|
||||
new URL(p.url()).pathname === "/models" &&
|
||||
new URL(p.url()).searchParams.get("keep") === "hello" &&
|
||||
new URL(p.url()).hash === "#models",
|
||||
);
|
||||
await p.goto(
|
||||
WEB + "/project/" + f.project + "?stage=assets&keep=source#draft",
|
||||
);
|
||||
await p.locator(".sidebar").waitFor();
|
||||
ok(
|
||||
"旧项目链接保留阶段参数",
|
||||
new URL(p.url()).pathname === "/workbench/" + f.project &&
|
||||
new URL(p.url()).searchParams.get("keep") === "source" &&
|
||||
new URL(p.url()).hash === "#draft",
|
||||
);
|
||||
// Explicit legacy tools remain searchable until B1/B2 relocate them.
|
||||
await p.keyboard.press("Control+k");
|
||||
for (const label of ["视频创作", "大语言模型", "试验台", "三维搭景"])
|
||||
ok(
|
||||
"全局搜索保留 " + label,
|
||||
(await p.getByRole("option").filter({ hasText: label }).count()) > 0,
|
||||
);
|
||||
await p.keyboard.press("Escape");
|
||||
// Block framework scripts to verify the remembered theme before hydration.
|
||||
const colours = [
|
||||
"rgb(7, 8, 12)",
|
||||
"rgb(233, 228, 218)",
|
||||
"rgb(27, 27, 28)",
|
||||
"rgb(10, 16, 41)",
|
||||
];
|
||||
for (let n = 0; n < themes.length; n++) {
|
||||
const cold = await browser.newContext();
|
||||
await cold.addInitScript(
|
||||
(id) => localStorage.setItem("aigc-theme", id),
|
||||
themes[n],
|
||||
);
|
||||
const coldPage = await cold.newPage();
|
||||
await coldPage.route("**/*", (route) =>
|
||||
route.request().resourceType() === "script"
|
||||
? route.abort()
|
||||
: route.continue(),
|
||||
);
|
||||
await coldPage.goto(WEB + "/", { waitUntil: "domcontentloaded" });
|
||||
ok(
|
||||
themes[n] + " 首次绘制前恢复主题及底色",
|
||||
await coldPage.evaluate(
|
||||
({ id, colour }) =>
|
||||
document.documentElement.dataset.theme === id &&
|
||||
getComputedStyle(document.documentElement).backgroundColor ===
|
||||
colour &&
|
||||
!document.querySelector(".refract-shell"),
|
||||
{ id: themes[n], colour: colours[n] },
|
||||
),
|
||||
);
|
||||
await cold.close();
|
||||
}
|
||||
const reference = await browser.newPage();
|
||||
await reference.goto(
|
||||
"file://" + path.resolve("design/nocturne/reference.html"),
|
||||
);
|
||||
await reference.evaluate(() => {
|
||||
document.documentElement.classList.add("capture", "reduce");
|
||||
go("settings");
|
||||
});
|
||||
for (const [width, height] of [
|
||||
[1440, 900],
|
||||
[1366, 768],
|
||||
[1280, 720],
|
||||
]) {
|
||||
await reference.setViewportSize({ width, height });
|
||||
await reference.screenshot({
|
||||
path: path.join(out, `reference-${width}x${height}.png`),
|
||||
});
|
||||
}
|
||||
await reference.close();
|
||||
const blocked = await browser.newContext();
|
||||
await blocked.addInitScript(() =>
|
||||
Object.defineProperty(window, "localStorage", {
|
||||
get() {
|
||||
throw new DOMException("blocked", "SecurityError");
|
||||
},
|
||||
}),
|
||||
);
|
||||
const b = await blocked.newPage();
|
||||
b.on(
|
||||
"pageerror",
|
||||
(e) => (errors.push(e.message), console.error("PAGEERROR", e.stack)),
|
||||
);
|
||||
await b.goto(WEB + "/image?wf=" + f.dual);
|
||||
await b.locator("#desk-prompt").fill("禁止存储仍可编辑");
|
||||
await change(b, "day");
|
||||
await b.getByRole("button", { name: "主题", exact: true }).click();
|
||||
ok(
|
||||
"存储被禁用仍可切换且显示提示",
|
||||
await b
|
||||
.getByText("浏览器禁止本地存储:本次有效,其他操作不受影响")
|
||||
.isVisible(),
|
||||
);
|
||||
await b.keyboard.press("Escape");
|
||||
ok(
|
||||
"存储被禁用保留输入",
|
||||
(await b.locator("#desk-prompt").inputValue()) === "禁止存储仍可编辑",
|
||||
);
|
||||
await b.screenshot({ path: path.join(out, "storage-blocked.png") });
|
||||
const invalid = await browser.newContext();
|
||||
await invalid.addInitScript(() =>
|
||||
localStorage.setItem("aigc-theme", "invalid"),
|
||||
);
|
||||
const i = await invalid.newPage();
|
||||
await i.goto(WEB + "/settings?tab=appearance");
|
||||
await i.locator(".choices").waitFor();
|
||||
ok(
|
||||
"无效存储回退夜片场",
|
||||
await i.evaluate(
|
||||
() => document.documentElement.dataset.theme === "night",
|
||||
),
|
||||
);
|
||||
if (errors.length) console.error("BROWSER ERRORS", errors);
|
||||
fs.writeFileSync(
|
||||
path.join(out, "results.json"),
|
||||
JSON.stringify({ checks, errors }, null, 2),
|
||||
);
|
||||
ok("浏览器无运行错误", errors.length === 0);
|
||||
fs.writeFileSync(
|
||||
path.join(out, "results.json"),
|
||||
JSON.stringify({ checks, errors }, null, 2),
|
||||
);
|
||||
console.log("TOTAL", checks.length);
|
||||
} finally {
|
||||
if (saved) fs.writeFileSync(modepath, saved);
|
||||
else if (fs.existsSync(modepath)) fs.unlinkSync(modepath);
|
||||
await browser.close();
|
||||
}
|
||||
})().catch((e) => {
|
||||
console.error(e);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Run the isolated regression stack in the foreground and always stop children."""
|
||||
import os, signal, socket, subprocess, time, urllib.request
|
||||
from pathlib import Path
|
||||
root=Path(__file__).resolve().parents[1]
|
||||
os.chdir(root)
|
||||
py=str(root/'calliope-backend/.venv/bin/python')
|
||||
logs=root/'e2e/shots/hel728'; logs.mkdir(parents=True,exist_ok=True)
|
||||
env=os.environ.copy()
|
||||
for port in [8247,5173,18188,18189]:
|
||||
with socket.socket() as probe:
|
||||
assert probe.connect_ex(('127.0.0.1',port)) != 0, f'Test port {port} is already in use'
|
||||
# Every run gets fresh disposable state; retain prior evidence instead of deleting it.
|
||||
reference=root/'e2e/shots/reference'
|
||||
if reference.exists():reference.rename(reference.with_name('reference.previous-'+str(time.time_ns())))
|
||||
processes=[]; handles=[]
|
||||
try:
|
||||
for name,cmd in [('api',[py,'e2e/reference/server.py']),('comfy',[py,'e2e/fake_comfy.py']),('llm',[py,'e2e/reference/fake_llm.py']),('web',['npm','--prefix',os.environ.get('HEL728_WEB_DIR','calliope-web'),'run','dev'])]:
|
||||
h=open(logs/(name+'.log'),'w');handles.append(h);processes.append(subprocess.Popen(cmd,stdout=h,stderr=subprocess.STDOUT,env=env,start_new_session=True))
|
||||
for url in ['http://127.0.0.1:8247/api/health','http://127.0.0.1:5173']:
|
||||
for i in range(100):
|
||||
try:
|
||||
urllib.request.urlopen(url,timeout=2); break
|
||||
except Exception:
|
||||
if any(p.poll() is not None for p in processes): raise RuntimeError('A test service failed')
|
||||
if i==99:raise
|
||||
time.sleep(.2)
|
||||
for cmd in [[py,'e2e/seed.py'],[py,'e2e/reference/seed.py']]:subprocess.run(cmd,env=env,check=True)
|
||||
failures=[]
|
||||
scripts=os.environ.get('HEL728_TESTS','e2e/reference/check.cjs,e2e/reference/check-copy-fallback.cjs,e2e/hel728.cjs').split(',')
|
||||
for script in scripts:
|
||||
print('RUN',script,flush=True)
|
||||
result=subprocess.run(['node',script],env=env)
|
||||
if result.returncode:failures.append(script)
|
||||
print('FAILED SCRIPTS',failures,flush=True)
|
||||
if failures:raise SystemExit(1)
|
||||
|
||||
finally:
|
||||
for p in processes:
|
||||
if p.poll() is None:os.killpg(p.pid,signal.SIGTERM)
|
||||
for p in processes:
|
||||
try:p.wait(timeout=10)
|
||||
except subprocess.TimeoutExpired:os.killpg(p.pid,signal.SIGKILL);p.wait()
|
||||
for h in handles:h.close()
|
||||
Reference in New Issue
Block a user