xusijie
Clean branch for HF push
06ba7ea
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="color-scheme" content="light dark" />
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0b0b0c" media="(prefers-color-scheme: dark)" />
<title>OpenStoryline</title>
<link rel="icon" type="image/png" href="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/logo.png">
<link rel="stylesheet" href="/static/style.css" />
<script defer src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
</head>
<body class="sidebar-collapsed devbar-collapsed">
<!-- 左侧可收起侧边栏 -->
<aside id="sidebar" class="sidebar collapsed"
aria-label="侧边栏"
data-i18n-aria-label="aria.sidebar">
<div class="sidebar-inner">
<!-- 顶部固定区:永远不被挤压 -->
<div class="sidebar-top">
<button id="sidebarToggle" class="sidebar-icon-btn"
title="收起/展开侧边栏"
aria-label="收起/展开侧边栏"
data-i18n-title="sidebar.toggle"
data-i18n-aria-label="sidebar.toggle">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 7h16"></path>
<path d="M4 12h16"></path>
<path d="M4 17h16"></path>
</svg>
</button>
<button id="createDialogBtn" class="sidebar-action primary"
title="创建新对话"
aria-label="创建新对话"
data-i18n-title="sidebar.new_chat"
data-i18n-aria-label="sidebar.new_chat">
<span class="sidebar-action-icon"></span>
<span class="sidebar-action-text" data-i18n="sidebar.new_chat">创建新对话</span>
</button>
</div>
<!-- 中间滚动区:长内容放这里 -->
<div class="sidebar-scroll" id="sidebarScroll"
aria-label="侧边栏滚动区"
data-i18n-aria-label="aria.sidebar_scroll">
<!-- LLM 配置:卡片包住 下拉框 + 自定义字段 -->
<div id="llmBox" class="sidebar-panel" aria-label="LLM 配置">
<div class="sidebar-panel-title">
<span class="sidebar-panel-title-text" data-i18n="sidebar.llm_label">LLM 模型</span>
<a class="sidebar-help"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
target="_blank" rel="noopener noreferrer"
data-help-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/zh/api-key.md"
data-help-en="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
data-i18n-aria-label="sidebar.help_aria">
<span class="sidebar-help-icon" aria-hidden="true">?</span>
<span class="sidebar-help-tooltip" role="tooltip">
<span class="sidebar-help-tooltip-body" data-i18n="sidebar.help.llm"></span>
<span class="sidebar-help-tooltip-cta" data-i18n="sidebar.help.cta">点击查看配置教程</span>
</span>
</a>
</div>
<select id="llmModelSelect" class="sidebar-model-select"
aria-label="选择 LLM 模型"
data-i18n-aria-label="sidebar.llm_select_aria"
data-os-persist="sidebar.llm_model"></select>
<!-- 仅当 LLM 选择“使用自定义模型”时显示 -->
<div id="customLlmSection" class="sidebar-fields hidden">
<div class="sidebar-divider"></div>
<input id="customLlmModel" class="sidebar-input"
data-os-persist="sidebar.custom.llm.model"
placeholder="模型名称,例如 deepseek-chat / gpt-4o-mini"
data-i18n-placeholder="sidebar.custom_llm_model_ph" />
<input id="customLlmBaseUrl" class="sidebar-input"
data-os-persist="sidebar.custom.llm.base_url"
placeholder="Base URL,例如 https://api.xxx.com/v1"
data-i18n-placeholder="sidebar.custom_llm_baseurl_ph" />
<input id="customLlmApiKey" class="sidebar-input" type="password"
data-os-persist="sidebar.custom.llm.api_key"
placeholder="API Key"
data-i18n-placeholder="sidebar.custom_llm_apikey_ph" autocomplete="off" />
<div class="sidebar-hint" data-i18n="sidebar.custom_hint">
提示:API Key 仅用于本会话的服务端调用;页面与 Tool trace 会自动脱敏,不会显示明文。
</div>
</div>
</div>
<!-- VLM 配置:卡片包住 下拉框 + 自定义字段 -->
<div id="vlmBox" class="sidebar-panel" aria-label="VLM 配置">
<div class="sidebar-panel-title">
<span class="sidebar-panel-title-text" data-i18n="sidebar.vlm_label">VLM 模型</span>
<a class="sidebar-help"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
target="_blank" rel="noopener noreferrer"
data-help-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/zh/api-key.md"
data-help-en="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
data-i18n-aria-label="sidebar.help_aria">
<span class="sidebar-help-icon" aria-hidden="true">?</span>
<span class="sidebar-help-tooltip" role="tooltip">
<span class="sidebar-help-tooltip-body" data-i18n="sidebar.help.vlm"></span>
<span class="sidebar-help-tooltip-cta" data-i18n="sidebar.help.cta">点击查看配置教程</span>
</span>
</a>
</div>
<select id="vlmModelSelect" class="sidebar-model-select"
aria-label="选择 VLM 模型"
data-i18n-aria-label="sidebar.vlm_select_aria"
data-os-persist="sidebar.vlm_model"></select>
<!-- 仅当 VLM 选择“使用自定义模型”时显示 -->
<div id="customVlmSection" class="sidebar-fields hidden">
<div class="sidebar-divider"></div>
<input id="customVlmModel" class="sidebar-input"
data-os-persist="sidebar.custom.vlm.model"
placeholder="模型名称,例如 qwen-vl-plus / gpt-4o"
data-i18n-placeholder="sidebar.custom_vlm_model_ph" />
<input id="customVlmBaseUrl" class="sidebar-input"
data-os-persist="sidebar.custom.vlm.base_url"
placeholder="Base URL,例如 https://api.xxx.com/v1"
data-i18n-placeholder="sidebar.custom_vlm_baseurl_ph" />
<input id="customVlmApiKey" class="sidebar-input" type="password"
data-os-persist="sidebar.custom.vlm.api_key"
placeholder="API Key"
data-i18n-placeholder="sidebar.custom_vlm_apikey_ph" autocomplete="off" />
<div class="sidebar-hint" data-i18n="sidebar.custom_hint">
提示:API Key 仅用于本会话的服务端调用;页面与 Tool trace 会自动脱敏,不会显示明文。
</div>
</div>
</div>
<!-- Pexels 配置 -->
<div id="pexelsBox" class="sidebar-panel"
aria-label="Pexels API Key 配置"
data-i18n-aria-label="sidebar.pexels_box_aria">
<div class="sidebar-panel-title">
<span class="sidebar-panel-title-text" data-i18n="sidebar.pexels_title">Pexels 配置</span>
<a class="sidebar-help"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
target="_blank" rel="noopener noreferrer"
data-help-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/zh/api-key.md"
data-help-en="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
data-i18n-aria-label="sidebar.help_aria">
<span class="sidebar-help-icon" aria-hidden="true">?</span>
<span class="sidebar-help-tooltip" role="tooltip">
<span class="sidebar-help-tooltip-body" data-i18n="sidebar.help.pexels"></span>
<span
class="sidebar-help-tooltip-link"
role="link"
tabindex="0"
data-pexels-home-zh="https://www.pexels.com/zh-cn/"
data-pexels-home-en="https://www.pexels.com/"
data-i18n="sidebar.help.pexels_home_link"
>点击进入 Pexels 官方网站</span>
<span
class="sidebar-help-tooltip-link"
role="link"
tabindex="0"
data-terms-zh="https://www.pexels.com/terms-of-service"
data-terms-en="https://www.pexels.com/terms-of-service"
data-i18n="sidebar.help.pexels_terms_link"
>查看 Pexels 用户协议</span>
<span class="sidebar-help-tooltip-cta" data-i18n="sidebar.help.cta">点击查看配置教程</span>
</span>
</a>
</div>
<select id="pexelsKeyModeSelect"
class="sidebar-model-select"
aria-label="Pexels Key 模式"
data-i18n-aria-label="sidebar.pexels_mode_select_aria"
data-os-persist="sidebar.pexels.mode">
<option value="default" data-i18n="sidebar.pexels_default">使用默认配置</option>
<option value="custom" data-i18n="sidebar.pexels_custom">使用自定义 key</option>
</select>
<div id="pexelsCustomKeyBox" class="hidden">
<input id="pexelsApiKeyInput"
class="sidebar-input"
type="password"
autocomplete="off"
data-os-persist="sidebar.pexels.api_key"
placeholder="Pexels API Key"
data-i18n-placeholder="sidebar.pexels_apikey_ph" />
</div>
<div class="sidebar-hint" data-i18n="sidebar.pexels_hint">
提示:默认配置会优先使用 config.toml 的 search_media.pexels_api_key;为空时工具内部会从环境变量读取。
</div>
</div>
<!-- TTS 配置 -->
<div id="ttsBox" class="sidebar-panel"
aria-label="TTS 服务配置"
data-i18n-aria-label="sidebar.tts_box_aria">
<div class="sidebar-panel-title">
<span class="sidebar-panel-title-text" data-i18n="sidebar.tts_title">TTS 配置</span>
<a class="sidebar-help"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
target="_blank" rel="noopener noreferrer"
data-help-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/zh/api-key.md"
data-help-en="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/api-key.md"
data-i18n-aria-label="sidebar.help_aria">
<span class="sidebar-help-icon" aria-hidden="true">?</span>
<span class="sidebar-help-tooltip" role="tooltip">
<span class="sidebar-help-tooltip-body" data-i18n="sidebar.help.tts"></span>
<span class="sidebar-help-tooltip-cta" data-i18n="sidebar.help.cta">点击查看配置教程</span>
</span>
</a>
</div>
<select id="ttsProviderSelect"
class="sidebar-model-select"
aria-label="选择 TTS 服务厂家"
data-i18n-aria-label="sidebar.tts_provider_select_aria"
data-os-persist="sidebar.tts.provider">
<option value="" data-i18n="sidebar.tts_default">使用默认配置</option>
</select>
<div class="sidebar-hint" data-i18n="sidebar.tts_hint">
提示:字段留空将使用 config.toml 中的配置。
</div>
<div id="ttsProviderFields"></div>
</div>
</div>
</div>
</aside>
<!-- 主内容区(用于给 sidebar 留出空间) -->
<div class="main">
<!-- 保留原有 topbar 结构(不破坏 JS),但 CSS 默认隐藏 -->
<header class="topbar">
<div class="brand">
<picture>
<source srcset="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/brand_black.png" media="(prefers-color-scheme: dark)">
<img class="brand-img" src="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/brand_white.png" alt="OpenStoryline" width="168" height="26" decoding="async">
</picture>
<span class="ver">v1.0.0</span>
</div>
<div class="actions">
<div class="topbar-links" aria-label="快捷链接">
<a
class="topbar-pill topbar-link"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline"
data-link-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline"
data-link-en="https://github.com/FireRedTeam/FireRed-OpenStoryline"
target="_blank" rel="noopener noreferrer"
data-i18n-title="topbar.link1"
data-i18n-aria-label="topbar.link1"
>
<img class="os-icon" src="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/github.png" alt="" />
<span class="topbar-pill-text">Github</span>
</a>
<a
class="topbar-pill topbar-link"
href="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/guide.md"
data-link-zh="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/zh/guide.md"
data-link-en="https://github.com/FireRedTeam/FireRed-OpenStoryline/blob/main/docs/source/en/guide.md"
target="_blank" rel="noopener noreferrer"
data-i18n-title="topbar.link2"
data-i18n-aria-label="topbar.link2"
>
<img class="os-icon" src="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/user_guide.png" alt="" />
<span class="topbar-pill-text">Docs</span>
</a>
<a
class="topbar-pill topbar-link"
href="/node-map"
data-link-suffix="/node-map"
target="_blank" rel="noopener noreferrer"
data-i18n-title="topbar.node_map"
data-i18n-aria-label="topbar.node_map"
>
<img class="os-icon" src="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/node_map.png" alt="" />
<span class="topbar-pill-text">Node Map</span>
</a>
</div>
<div class="lang-switch" data-i18n-aria-label="topbar.lang_aria">
<span class="lang-chip lang-zh" data-i18n="topbar.lang_zh"></span>
<label class="lang-toggle" data-i18n-title="topbar.lang_title">
<input id="langToggle" type="checkbox" data-i18n-aria-label="topbar.lang_aria" />
<span class="lang-slider"></span>
</label>
<span class="lang-chip lang-en" data-i18n="topbar.lang_en">EN</span>
</div>
</div>
</header>
<!-- 对话区 -->
<main id="chat" class="chat" aria-live="polite"></main>
<!-- 空白页标题(ChatGPT 风格):仅在 #chat 为空时显示(纯 CSS 控制) -->
<section id="hero" class="hero" aria-hidden="true">
<h1 id="greeting" class="hero-title" data-i18n="main.greeting">你好,创作者</h1>
</section>
<!-- Toast -->
<div id="toast" class="toast hidden" role="status" aria-live="polite"></div>
<!-- Scroll to bottom -->
<button id="scrollToBottomBtn" class="scroll-bottom hidden" aria-label="滚动到底部" title="滚动到底部">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 5v14"></path>
<path d="M7 14l5 5 5-5"></path>
</svg>
</button>
<!-- 输入区 -->
<footer class="composer" role="region" aria-label="消息输入区">
<input id="fileInput" class="file-input" type="file" multiple />
<div id="pendingBar" class="pending hidden" aria-label="待发送素材">
<div class="media-bar-title">待发送素材</div>
<div id="pendingRow" class="media-row"></div>
</div>
<div class="composer-top">
<textarea
id="promptInput"
class="prompt"
data-i18n-placeholder="composer.placeholder"
placeholder="prompt here"
></textarea>
</div>
<div class="composer-actions">
<button id="uploadBtn" class="icon-btn" title="上传素材" aria-label="上传素材">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>
</svg>
</button>
<div class="composer-actions-spacer"></div>
<button
id="quickPromptBtn"
class="ghost-icon-btn"
type="button"
data-i18n-title="composer.quick_prompt"
data-i18n-aria-label="composer.quick_prompt"
>
<img class="os-icon" src="https://image-url-2-feature-1251524319.cos.ap-shanghai.myqcloud.com/openstoryline/web/static/dice.png" alt="" decoding="async" />
</button>
<button id="sendBtn" class="send-btn" aria-label="发送">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 19V6"></path>
<path d="M7 11l5-5 5 5"></path>
</svg>
</button>
</div>
</footer>
<!-- 预览 Modal -->
<div id="modal" class="modal hidden" aria-hidden="true">
<div class="modal-backdrop" id="modalBackdrop"></div>
<div class="modal-body" role="dialog" aria-modal="true">
<button class="modal-close" id="modalClose" aria-label="关闭">×</button>
<div class="modal-content" id="modalContent"></div>
</div>
</div>
<!-- Tool UI 配置:必须在 app.js 之前 -->
<script>
window.OPENSTORYLINE_TOOL_UI = {
labels: {
"load_media": {"zh": "读取素材", "en": "load media"},
"search_media": {"zh": "搜索素材", "en": "search media"},
"split_shots": {"zh": "镜头切分", "en": "split shots"},
"filter_clips": {"zh": "筛选片段", "en": "filter clips"},
"understand_clips": {"zh": "理解素材", "en": "understand clips"},
"group_clips": {"zh": "片段分组", "en": "group clips"},
"script_template_rec":{"zh": "仿写模版推荐", "en": "recommend script template"},
"create_profile_style_skill": {"zh": "[SKILL] 总结新SKILL", "en": "[SKILL] generate a new SKILL"},
"subtitle_imitation_skill": {"zh": "[SKILL] 文风仿写", "en": "[SKILL] mimic script style"},
"generate_script": {"zh": "生成文案", "en": "generate script"},
"generate_voiceover": {"zh": "生成配音", "en": "generate voiceover"},
"select_bgm": {"zh": "推荐背景音乐", "en": "recommend music"},
"elementrec_transition": {"zh": "推荐转场", "en": "recommend transition"},
"elementrec_text":{"zh": "推荐花字", "en": "recommend stylized subtitle fonts"},
"plan_timeline": {"zh": "组织时间线", "en": "plan timeline"},
"plan_timeline_pro": {"zh": "组织时间线 (pro)", "en": "plan timeline (pro)"},
"render_video": {"zh": "渲染视频", "en": "render"},
"write_skills": {"zh": "创建新SKILL", "en": "Create a new SKILL"},
"split_shots_pro": {"zh": "镜头切分 (pro)", "en": "split shots (pro)"},
"filter_clips_pro": {"zh": "筛选片段 (pro)", "en": "filter clips (pro)"},
"understand_clips_pro": {"zh": "理解素材 (pro)", "en": "understand clips (pro)"},
"group_clips_pro": {"zh": "片段分组 (pro)", "en": "group clips (pro)"},
"generate_script_pro": {"zh": "生成文案 (pro)", "en": "generate script (pro)"},
"elementrec_texts_pro": {"zh": "推荐花字 (pro)", "en": "recommend stylized subtitle fonts (pro)"},
"elementrec_title_pro": {"zh": "推荐标题 (pro)", "en": "recommand title"},
"elementrec_global_effects_pro": {"zh": "推荐全局特效 (pro)", "en": "recommand global effects (pro)"},
"elementrec_local_effects_pro": {"zh": "推荐局部特效 (pro)", "en": "recommand loacl effects (pro)"},
"elementrec_close_effects_pro": {"zh": "推荐闭幕特效 (pro)", "en": "recommand close effects (pro)"},
"elementrec_filter_pro": {"zh": "推荐滤镜 (pro)", "en": "recommand filter (pro)"},
"elementrec_transition_pro": {"zh": "推荐转场 (pro)", "en": "recommand transition (pro)"},
"elementrec_text_animation_pro": {"zh": "推荐花字动画 (pro)", "en": "recommended stylized subtitle animations (pro)"},
"elementrec_title_clip_pro": {"zh": "推荐片头 (pro)", "en": "recommend title clip (pro)"},
"elementrec_tts_pro": {"zh": "推荐配音音色 (pro)", "en": "recommended voice timbre for voiceover (pro)"},
"generate_voiceover_pro": {"zh": "生成配音 (pro)", "en": "generate voiceover (pro)"},
"music_rec_service_pro": {"zh": "推荐背景音乐 (pro)", "en": "recommand music (pro)"},
"timeline_pro": {"zh": "组织时间线 (pro)", "en": "plan timeline (pro)"},
"render_template_pro": {"zh": "渲染视频 (pro)", "en": "render (pro)"},
"read_node_history": {"zh": "读取详细结果", "en": "read history"},
},
estimates_ms: {
"storyline.load_media": 1000
},
default_estimate_ms: 5000,
tick_ms: 120,
cap_running_progress: 0.99,
hide_raw_tool_name: true,
show_raw_tool_name_in_dev: true
};
</script>
<script type="module" src="/static/app.js"></script>
</div>
<!-- 右侧开发者侧边栏(仅 developer_mode=true 时由 JS 显示) -->
<aside id="devbar" class="devbar hidden collapsed" aria-label="开发者侧边栏">
<div class="devbar-inner">
<button id="devbarToggle" class="devbar-icon-btn" title="收起/展开开发者侧边栏" aria-label="收起/展开开发者侧边栏">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M15 6l-6 6 6 6"></path>
</svg>
</button>
<div class="devbar-title">Tool summary trace</div>
<div class="devbar-sid" id="sidebarSid"></div>
<div id="devLog" class="devbar-log" aria-label="工具 summary 输出">
<!-- JS 追加 summary -->
</div>
</div>
</aside>
</body>
</html>