Skill: ildar981105-create/product-doc-hub (version 1.0.0)

--- name: product-doc-hub description: "面向 AI 产品团队的一站式文档解决方案，一套工具覆盖从产品定义到 API 上线的全链路文档：PRD（功能规格说明书）、Product Brief（投资人/团队轻量介绍）、Experience Framework（体验验证方法论，含四维模型+埋点指标+SUS/EV/NPS/SAM量表设计）、API Console（配置化在线调试台）。PRD/Brief/体验框架为内容模板（保留结构换内容），API Console 为零代码配置（改 JS 对象即可定义端点）。适用于：产品立项、团队交接、投资人演示、API 调试。创新点：四类文档统一风格、统一入口，API Console 支持在线发送真实请求并查看响应。" --- # Product Doc Hub Skill — 产品知识库聚合器 v2（API Console 可配置版） ## 🎯 5 分钟上手 ### 最简配置（API Console，复制即用） ```html <script src="api-console-config.js"></script> <script> window.API_CONSOLE_CONFIG = { productName: '我的产品', baseUrl: 'https://api.my-product.com', groups: [ { name: '用户', apis: [ { method: 'POST', path: '/users', desc: '创建用户', params: [ { name:'name', type:'text', required:true, placeholder:'姓名' }, { name:'email', type:'text', required:true, placeholder:'邮箱' } ] }, { method: 'GET', path: '/users/:id', desc: '查询用户', params: [ { name:'id', type:'text', required:true, placeholder:'用户ID' } ] } ] } ] }; </script> <script src="api.html"></script> ``` ### 其他页面 | 页面 | 定制方式 | |------|---------| | **PRD** | 复制 `prd.html`，替换章节内容 | | **产品简介** | 复制 `product-brief.html`，替换内容 | | **体验框架** | 复制 `experience-framework.html`，替换四维模型内容 | | **Hub 导航** | 复制 `hub.html`，修改四个入口链接 | --- ## 概述 本 Skill 提供一套**可配置的产品文档黄页**，包含 PRD/Brief/体验框架/API调试台四类页面。 | 页面 | 文件 | 用途 | 定制方式 | |------|------|------|---------| | **PRD** | `prd.html` | 功能规格说明书 | 内容替换 | | **产品简介** | `product-brief.html` | 面向投资人轻量介绍 | 内容替换 | | **体验框架** | `experience-framework.html` | AI产品体验验证方法论 | 章节模板 | | **API 控制台** | `api.html` | 在线 API 调试 | **配置化** ⭐ | | **Hub 导航** | `hub.html` | 四页面导航入口 | 内容替换 | --- ## ⭐ API Console 配置化（重点） ### 快速使用 ```html <!-- Step 1: 引入配置 --> <script src="api-console-config.js"></script> <!-- Step 2: 修改配置 --> <script> window.API_CONSOLE_CONFIG.productName = '我的产品'; window.API_CONSOLE_CONFIG.baseUrl = 'https://api.my-product.com'; // 修改端点列表 window.API_CONSOLE_CONFIG.groups = [ { name: '用户模块', icon: '<svg ...>', // 可选 SVG apis: [ { method: 'POST', path: '/users', desc: '创建用户', params: [ { name: 'name', type: 'text', required: true, desc: '用户名' }, { name: 'email', type: 'text', required: true, desc: '邮箱' }, { name: 'role', type: 'select', required: false, default: 'user', options: ['user','admin','vip'], desc: '用户角色' } ] }, { method: 'GET', path: '/users/:id', desc: '查询用户详情', params: [ { name: 'id', type: 'text', required: true, desc: '用户 ID' } ] } ] } ]; </script> <!-- Step 3: 引入页面 --> <script src="api.html"></script> ``` 页面会自动读取 `API_CONSOLE_CONFIG` 并渲染端点列表、发送请求。 ### API_CONSOLE_CONFIG 完整字段 | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `productName` | string | `'本产品'` | 页面标题 | | `baseUrl` | string | — | API 基础地址 | | `timeout` | number | `30000` | 请求超时（ms） | | `showStats` | boolean | `true` | 是否显示统计卡片 | | `initialStats` | object | 见下方 | 初始统计数据 | | `groups` | array | 内置默认 | 端点分组列表 | | `theme` | string | `'dark'` | `'dark'` / `'light'` | **initialStats 默认值**： ```javascript { totalCalls: 0, // 总调用次数 successRate: 100, // 成功率% avgLatency: 0, // 平均延迟ms activeTasks: 0 // 活跃任务数 } ``` ### 端点参数格式 ```javascript { method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: '/endpoint/:param', // :param 会被识别为路径参数 desc: '端点描述', params: [ // 请求参数（用于构造器） { name: 'paramName', // 参数名 type: 'text' | 'file' | 'select', required: true | false, default: '默认值', // 可选 options: ['a','b','c'], // type=select 时必填 desc: '参数说明' // 可选 } ] } ``` --- ## 文件结构 ``` product-doc-hub/ ├── SKILL.md # 本文档 └── assets/ ├── prd.html # 产品需求文档（可直接修改内容） ├── product-brief.html # 产品简介（可直接修改内容） ├── experience-framework.html # 体验框架（保留结构换内容） ├── api.html # API 调试台（配置化） ├── api-console-config.js # API Console 配置模板 ⭐ ├── hub.html # Hub 导航页 └── (其他产品文档资源) ``` --- ## PRD / Brief 定制指南 ### PRD 定制（最快） 1. 复制 `prd.html` 作为 `my-product-prd.html` 2. 全局替换产品名称为"我的产品" 3. 修改各章节的功能规格描述 4. 保留 Callout / Flow / 目录等组件结构 ### Brief 定制 1. 复制 `product-brief.html` 作为 `my-product-brief.html` 2. 全局替换产品名称为"我的产品" 3. 修改产品定位、目标用户、核心流程 4. 调整功能状态表（已完成 → 进行中 → 待开发） ### 体验框架 定制 1. 复制 `experience-framework.html` 作为 `my-ef.html` 2. 保留"四维体验验证模型"的结构框架 3. 替换每个维度的具体内容为新产品的设计策略 4. 更新 SUS/EV/SAM/NPS 的具体题目文本 5. 调整埋点指标映射 --- ## 设计系统（四个页面共享） ### 暗色主题变量 ```css background: #08080c surface: rgba(255,255,255,0.02~0.08) text-primary: #e2e8f0 text-secondary: #94a3b8 accent-blue: #818cf8 accent-green: #10b981 accent-amber: #f59e0b accent-purple: #a855f7 border: rgba(255,255,255,0.05~0.10) ``` ### 通用组件类 | 组件 | CSS 类 | 说明 | |------|--------|------| | Callout | `.callout .callout-blue/green/yellow/purple` | 左色条信息卡片 | | Flow 步骤 | `.flow-step` + `.flow-arrow` | 流程图 | | 表格 | 标准 `<table>` + th/td | 数据表格 | | 代码 | `<code>` 半透明底 | 内联代码 | | 等宽框 | `.diagram` | ASCII 架构图 | --- ## 如何为新产品构建 Product Hub ### 推荐顺序 1. **Brief 先行**（半天）— 写清楚"为什么做"，给所有人看 2. **PRD 跟进**（1-2天）— 写清楚"做什么怎么做"，给实现团队 3. **EF 并行**（1-2天）— 同时设计体验验证方案 4. **API Console 最后**（1小时配置）— 有接口了再配置端点 ### 定制检查清单 - [ ] 全局替换产品名称为新产品名 - [ ] 更新 Brief 的产品定义和目标用户 - [ ] 重写 PRD 的功能规格（保留章节结构） - [ ] 调整 EF 的四维模型内容（保留验证方法论） - [ ] 更新 API Console 的 `groups` 端点列表 - [ ] 调整配色（如果品牌色不同） - [ ] 更新版本号和日期 --- ## 发布到 GitHub ```bash cd ~/.codebuddy/skills/product-doc-hub git init git add . git commit -m "feat: product-doc-hub v2" git remote add origin https://github.com/YOUR_USERNAME/product-doc-hub.git git push -u origin main ```

path: assets/api-console-config.js
content: /**
 * api-console-config.js — API Console 全局配置
 *
 * ============================================================
 * 🎯 最简配置（只需 3 步，5 分钟完成）
 * ============================================================
 *
 * 1. 引入本文件
 * 2. 设置 baseUrl + groups（见下方最小示例）
 * 3. 引入 api.html
 *
 * 最小配置示例（复制下面的代码即可）：
 *
 * <script src="api-console-config.js"></script>
 * <script>
 *   window.API_CONSOLE_CONFIG = {
 *     productName: '我的产品',
 *     baseUrl:     'https://api.my-product.com',
 *     groups: [
 *       {
 *         name: '用户',
 *         apis: [
 *           { method: 'POST', path: '/users', desc: '创建用户',
 *             params: [
 *               { name:'name',  type:'text',   required:true,  placeholder:'姓名' },
 *               { name:'email', type:'text',   required:true,  placeholder:'邮箱' }
 *             ]
 *           },
 *           { method: 'GET',  path: '/users/:id', desc: '查询用户',
 *             params: [
 *               { name:'id', type:'text', required:true, placeholder:'用户ID' }
 *             ]
 *           }
 *         ]
 *       }
 *     ]
 *   };
 * </script>
 * <script src="api.html"></script>
 *
 * ============================================================
 * 📋 配置速查表
 * ============================================================
 *
 * 字段      | 类型    | 必填 | 说明
 * ----------|---------|------|------
 * productName | string | 否   | 页面标题（默认"Tideo"）
 * baseUrl    | string | 是   | API 基础地址
 * groups     | array  | 是   | 端点分组列表
 * timeout    | number | 否   | 请求超时 ms（默认 30000）
 * showStats  | bool   | 否   | 是否显示统计卡片（默认 true）
 * theme      | string | 否   | 'dark'|'light'（默认 'dark'）
 *
 * group 对象格式：
 *   { name:'分组名', icon:'<svg>...</svg>(可选)', apis:[...] }
 *
 * api 对象格式：
 *   { method:'GET'|'POST'|'PUT'|'DELETE', path:'/path', desc:'描述',
 *     params:[{ name, type:'text'|'file'|'select', required, options?, default?, placeholder?, desc? }] }
 *
 * ============================================================
 */

window.API_CONSOLE_CONFIG = window.API_CONSOLE_CONFIG || {};

/**
 * 产品名称（显示在页面标题）
 */
window.API_CONSOLE_CONFIG.productName = window.API_CONSOLE_CONFIG.productName || 'Tideo';

/**
 * 基础 URL — 所有 API 请求的 base 地址
 * 实际请求时：baseUrl + endpoint.path
 */
window.API_CONSOLE_CONFIG.baseUrl = window.API_CONSOLE_CONFIG.baseUrl || 'https://your-api-server.com';

/**
 * 请求默认超时时间（ms）
 */
window.API_CONSOLE_CONFIG.timeout = window.API_CONSOLE_CONFIG.timeout || 30000;

/**
 * 是否显示统计卡片（默认显示）
 */
window.API_CONSOLE_CONFIG.showStats = window.API_CONSOLE_CONFIG.showStats !== undefined
    ? window.API_CONSOLE_CONFIG.showStats : true;

/**
 * 统计卡片初始数据（首次加载时显示）
 * 在真实使用中这些数据会被页面内的请求记录覆盖
 */
window.API_CONSOLE_CONFIG.initialStats = window.API_CONSOLE_CONFIG.initialStats || {
  totalCalls: 0,
  successRate: 100,
  avgLatency: 0,
  activeTasks: 0
};

/**
 * 端点分组列表
 *
 * 每个分组：
 *   name   — 分组名称（如 'MPS 视频处理'）
 *   icon   — 分组图标（可选，SVG 路径字符串）
 *   apis   — 端点数组
 *
 * 每个端点：
 *   method   — HTTP 方法：GET / POST / PUT / DELETE
 *   path     — 路径（如 '/translate'），完整 URL = baseUrl + path
 *   desc     — 端点描述
 *   params   — 参数列表（用于请求构造器）
 *     name   — 参数名
 *     type   — 'text' | 'file' | 'select'
 *     required — 是否必填
 *     default — 默认值（可选）
 *     options — type=select 时的选项数组（可选）
 *     desc   — 参数说明（可选）
 */
window.API_CONSOLE_CONFIG.groups = window.API_CONSOLE_CONFIG.groups || [

  {
    name: 'MPS 视频处理',
    icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>',
    apis: [
      {
        method: 'POST',
        path: '/translate',
        desc: '提交视频译制任务',
        params: [
          { name: 'videoUrl',    type: 'text',     required: true,  desc: 'COS 视频文件地址' },
          { name: 'lang_src',    type: 'select',   required: true,  default: 'zh',  options: ['zh','en','ja','ko','fr','es','de','it','pt','ru','ar'], desc: '源语言' },
          { name: 'lang_tgt',    type: 'select',   required: true,  default: 'en',  options: ['zh','en','ja','ko','fr','es','de','it','pt','ru','ar'], desc: '目标语言' },
          { name: 'mode',        type: 'select',   required: false, default: 'full', options: ['full','erase','subtitle','voice'], desc: '处理模式' }
        ]
      },
      {
        method: 'POST',
        path: '/erase',
        desc: '提交字幕擦除任务',
        params: [
          { name: 'videoUrl',    type: 'text',     required: true,  desc: 'COS 视频文件地址' },
          { name: 'regions',     type: 'text',     required: true,  desc: '擦除区域 JSON，格式 [{x,y,w,h,startSec,endSec}]' }
        ]
      },
      {
        method: 'POST',
        path: '/clip',
        desc: '提交视频剪辑任务',
        params: [
          { name: 'videoUrl',    type: 'text',     required: true,  desc: 'COS 视频文件地址' },
          { name: 'startSec',    type: 'text',     required: true,  desc: '剪辑起点（秒）' },
          { name: 'endSec',      type: 'text',     required: true,  desc: '剪辑终点（秒）' }
        ]
      },
      {
        method: 'GET',
        path: '/task/:taskId',
        desc: '查询任务状态',
        params: [
          { name: 'taskId',      type: 'text',     required: true,  desc: '任务 ID' }
        ]
      }
    ]
  },

  {
    name: 'COS 文件操作',
    icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>',
    apis: [
      {
        method: 'POST',
        path: '/sts',
        desc: '获取 COS 临时访问凭证',
        params: [
          { name: 'filename',    type: 'text',     required: false, desc: '文件名（可选，用于生成带签名的 URL）' }
        ]
      },
      {
        method: 'POST',
        path: '/list-files',
        desc: '列出 COS Bucket 中的文件',
        params: [
          { name: 'prefix',      type: 'text',     required: false, desc: '文件名前缀筛选' },
          { name: 'maxKeys',     type: 'text',     required: false, default: '100', desc: '最大返回条数' }
        ]
      }
    ]
  },

  {
    name: 'VOD AIGC',
    icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>',
    apis: [
      {
        method: 'POST',
        path: '/aigc-video',
        desc: 'AI 视频生成（多模型支持）',
        params: [
          { name: 'model',       type: 'select',   required: true,  default: 'kling', options: ['kling','vidu','hailuo','minimax','pixverse'], desc: '生成模型' },
          { name: 'prompt',      type: 'text',     required: true,  desc: '视频描述提示词' },
          { name: 'duration',    type: 'select',   required: false, default: '5', options: ['3','5','10'], desc: '视频时长（秒）' },
          { name: 'aspect_ratio',type: 'select',  required: false, default: '16:9', options: ['16:9','9:16','1:1'], desc: '画面比例' }
        ]
      },
      {
        method: 'POST',
        path: '/aigc-image',
        desc: 'AI 图片生成（多模型支持）',
        params: [
          { name: 'model',       type: 'select',   required: true,  default: 'gem', options: ['gem','hunyuan','midjourney'], desc: '生成模型' },
          { name: 'prompt',      type: 'text',     required: true,  desc: '图片描述提示词' },
          { name: 'size',        type: 'select',   required: false, default: '1024x1024', options: ['512x512','768x768','1024x1024','1024x1792'], desc: '图片尺寸' }
        ]
      }
    ]
  },

  {
    name: '其他',
    icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',
    apis: [
      {
        method: 'POST',
        path: '/track',
        desc: '埋点数据上报',
        params: [
          { name: 'events',     type: 'text',     required: true,  desc: '事件数组 JSON' }
        ]
      },
      {
        method: 'GET',
        path: '/track-data',
        desc: '查询埋点数据',
        params: [
          { name: 'uid',         type: 'text',     required: false, desc: '用户 ID 筛选' },
          { name: 'limit',       type: 'text',     required: false, default: '50', desc: '返回条数' }
        ]
      }
    ]
  }

];

/**
 * 配色主题（与 api.html 的 CSS 变量对应）
 */
window.API_CONSOLE_CONFIG.theme = window.API_CONSOLE_CONFIG.theme || 'dark'; // 'dark' | 'light'


path: assets/api.html
content: <!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>API 管理 — <span id="apiPageTitle">本产品</span></title>
    <script>
    (function(){
      var pn=(window.API_CONSOLE_CONFIG||{}).productName||'本产品';
      var el=document.getElementById('apiPageTitle');
      if(el) el.textContent=pn;
      var logoEl=document.getElementById('apiLogoText');
      if(logoEl) logoEl.textContent=pn;
      var linkEl=document.getElementById('apiLogoLink');
      if(linkEl) linkEl.title=pn;
      var t=localStorage.getItem('ptheme');
        if (t === 'dark') {
            document.documentElement.removeAttribute('data-theme');
        } else if (t === 'light' || (!t && window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches)) {
            document.documentElement.setAttribute('data-theme', 'light');
        } else {
            document.documentElement.removeAttribute('data-theme');
        }
    })();
    </script>
    <link rel="stylesheet" href="style.css">
    <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=DM+Sans:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
    <style>
    /* ===== API 管理页专属样式 ===== */

    /* 统计卡片行 */
    .api-stats-row {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        gap: 16px;
        margin: 28px 0 32px;
    }
    .api-stat-card {
        padding: 22px;
        background: rgba(255,255,255,0.025);
        border: 1px solid rgba(255,255,255,0.06);
        border-radius: 18px;
        transition: all 0.35s cubic-bezier(.4,0,.2,1);
        cursor: default;
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        position: relative;
        overflow: hidden;
    }
    .api-stat-card::before {
        content: '';
        position: absolute;
        top: -1px;
        left: 15%;
        right: 15%;
        height: 1px;
        background: linear-gradient(90deg, transparent, rgba(99,102,241,0.2), transparent);
        pointer-events: none;
    }
    .api-stat-card:hover {
        border-color: rgba(99,102,241,0.2);
        background: rgba(99,102,241,0.03);
        transform: translateY(-2px);
        box-shadow: 0 8px 32px rgba(99,102,241,0.06);
    }
    .api-stat-top {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 12px;
    }
    .api-stat-icon {
        width: 42px; height: 42px;
        border-radius: 13px;
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
    }
    .api-stat-icon::after {
        content: '';
        position: absolute;
        inset: -5px;
        border-radius: 18px;
        pointer-events: none;
    }
    .api-stat-icon--purple { background: rgba(99,102,241,0.12); color: #a855f7; }
    .api-stat-icon--purple::after { background: radial-gradient(circle, rgba(168,85,247,0.07) 0%, transparent 70%); }
    .api-stat-icon--blue { background: rgba(59,130,246,0.12); color: #3b82f6; }
    .api-stat-icon--blue::after { background: radial-gradient(circle, rgba(59,130,246,0.07) 0%, transparent 70%); }
    .api-stat-icon--green { background: rgba(16,185,129,0.12); color: #10b981; }
    .api-stat-icon--green::after { background: radial-gradient(circle, rgba(16,185,129,0.07) 0%, transparent 70%); }
    .api-stat-icon--amber { background: rgba(245,158,11,0.12); color: #f59e0b; }
    .api-stat-icon--amber::after { background: radial-gradient(circle, rgba(245,158,11,0.07) 0%, transparent 70%); }
    .api-stat-trend {
        display: flex;
        align-items: center;
        gap: 4px;
        font-size: 0.72rem;
        font-weight: 600;
        padding: 3px 8px;
        border-radius: 6px;
    }
    .api-stat-trend--up { color: #10b981; background: rgba(16,185,129,0.1); }
    .api-stat-trend--down { color: #ef4444; background: rgba(239,68,68,0.1); }
    .api-stat-value {
        font-size: 1.8rem;
        font-weight: 800;
        margin-bottom: 2px;
        font-family: 'JetBrains Mono', monospace;
    }
    .api-stat-label {
        font-size: 0.78rem;
        color: var(--text-muted);
    }

    /* 区块标题 */
    .api-section-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 16px;
    }
    .api-section-title {
        font-size: 1rem;
        font-weight: 700;
        color: var(--text-primary);
        display: flex;
        align-items: center;
        gap: 8px;
    }
    .api-section-title svg { color: var(--text-muted); }
    .api-section-badge {
        font-size: 0.65rem;
        font-weight: 700;
        padding: 2px 8px;
        border-radius: 100px;
        background: rgba(99,102,241,0.12);
        color: #a78bfa;
    }

    /* 创建 API Key 按钮 */
    .api-create-btn {
        display: flex;
        align-items: center;
        gap: 6px;
        padding: 8px 18px;
        font-size: 0.82rem;
        font-weight: 600;
        border-radius: 10px;
        border: none;
        color: #fff;
        background: linear-gradient(135deg, #a855f7, #6366f1);
        cursor: pointer;
        font-family: inherit;
        box-shadow: 0 0 16px rgba(99,102,241,0.2);
        transition: all 0.3s;
    }
    .api-create-btn:hover {
        transform: translateY(-1px);
        box-shadow: 0 4px 20px rgba(99,102,241,0.3);
    }

    /* API Key 列表 */
    .api-keys-list {
        display: flex;
        flex-direction: column;
        gap: 12px;
        margin-bottom: 40px;
    }
    .api-key-card {
        padding: 18px 22px;
        background: rgba(255,255,255,0.025);
        border: 1px solid rgba(255,255,255,0.06);
        border-radius: 14px;
        transition: all 0.3s cubic-bezier(.4,0,.2,1);
        display: flex;
        align-items: center;
        gap: 16px;
    }
    .api-key-card:hover {
        border-color: rgba(99,102,241,0.15);
        background: rgba(99,102,241,0.02);
    }
    .api-key-icon {
        width: 40px; height: 40px;
        border-radius: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        background: rgba(99,102,241,0.08);
        color: #a78bfa;
    }
    .api-key-info {
        flex: 1;
        min-width: 0;
    }
    .api-key-name {
        font-size: 0.88rem;
        font-weight: 600;
        color: var(--text-primary);
        margin-bottom: 4px;
        display: flex;
        align-items: center;
        gap: 8px;
    }
    .api-key-name .key-status {
        font-size: 0.65rem;
        font-weight: 600;
        padding: 2px 8px;
        border-radius: 100px;
    }
    .key-status--active { background: rgba(16,185,129,0.12); color: #10b981; }
    .key-status--expired { background: rgba(239,68,68,0.12); color: #ef4444; }
    .api-key-value {
        font-family: 'JetBrains Mono', monospace;
        font-size: 0.78rem;
        color: var(--text-muted);
        letter-spacing: 0.02em;
    }
    .api-key-meta {
        display: flex;
        align-items: center;
        gap: 16px;
        flex-shrink: 0;
    }
    .api-key-meta-item {
        text-align: right;
    }
    .api-key-meta-value {
        font-size: 0.82rem;
        font-weight: 600;
        color: var(--text-primary);
        font-family: 'JetBrains Mono', monospace;
    }
    .api-key-meta-label {
        font-size: 0.68rem;
        color: var(--text-faint);
    }
    .api-key-actions {
        display: flex;
        align-items: center;
        gap: 6px;
        flex-shrink: 0;
    }
    .api-key-action-btn {
        width: 34px; height: 34px;
        display: flex;
        align-items: center;
        justify-content: center;
        border: 1px solid rgba(255,255,255,0.06);
        background: rgba(255,255,255,0.03);
        border-radius: 8px;
        color: var(--text-muted);
        cursor: pointer;
        transition: all 0.2s;
    }
    .api-key-action-btn:hover {
        color: var(--text-primary);
        border-color: rgba(99,102,241,0.3);
        background: rgba(99,102,241,0.06);
    }
    .api-key-action-btn--danger:hover {
        color: #ef4444;
        border-color: rgba(239,68,68,0.3);
        background: rgba(239,68,68,0.06);
    }

    /* 调用日志 */
    .api-log-table {
        width: 100%;
        border-collapse: collapse;
        margin-bottom: 40px;
    }
    .api-log-table thead {
        position: sticky;
        top: 0;
    }
    .api-log-table th {
        padding: 10px 16px;
        font-size: 0.72rem;
        font-weight: 600;
        color: var(--text-faint);
        text-align: left;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        border-bottom: 1px solid rgba(255,255,255,0.06);
        background: var(--bg-base);
    }
    .api-log-table td {
        padding: 14px 16px;
        font-size: 0.82rem;
        color: var(--text-secondary);
        border-bottom: 1px solid rgba(255,255,255,0.03);
        transition: background 0.15s;
    }
    .api-log-table tbody tr:hover td {
        background: rgba(99,102,241,0.02);
    }
    .api-log-method {
        font-family: 'JetBrains Mono', monospace;
        font-size: 0.7rem;
        font-weight: 700;
        padding: 3px 8px;
        border-radius: 4px;
        letter-spacing: 0.02em;
    }
    .method--post { background: rgba(99,102,241,0.12); color: #818cf8; }
    .method--get { background: rgba(16,185,129,0.12); color: #34d399; }
    .method--put { background: rgba(245,158,11,0.12); color: #fbbf24; }
    .method--delete { background: rgba(239,68,68,0.12); color: #f87171; }
    .api-log-endpoint {
        font-family: 'JetBrains Mono', monospace;
        font-size: 0.78rem;
        color: var(--text-primary);
    }
    .api-log-status {
        font-family: 'JetBrains Mono', monospace;
        font-weight: 600;
        font-size: 0.78rem;
    }
    .status--200 { color: #10b981; }
    .status--201 { color: #10b981; }
    .status--400 { color: #f59e0b; }
    .status--401 { color: #ef4444; }
    .status--500 { color: #ef4444; }
    .api-log-time {
        font-family: 'JetBrains Mono', monospace;
        font-size: 0.75rem;
        color: var(--text-muted);
    }
    .api-log-latency {
        font-family: 'JetBrains Mono', monospace;
        font-size: 0.75rem;
        color: var(--text-muted);
    }

    /* 快捷入口卡片 */
    .api-quick-grid {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 16px;
        margin-bottom: 40px;
    }
    .api-quick-card {
        padding: 24px;
        background: rgba(255,255,255,0.025);
        border: 1px solid rgba(255,255,255,0.06);
        border-radius: 16px;
        cursor: pointer;
        transition: all 0.35s cubic-bezier(.4,0,.2,1);
        position: relative;
        overflow: hidden;
    }
    .api-quick-card::before {
        content: '';
        position: absolute;
        top: -1px;
        left: 15%;
        right: 15%;
        height: 1px;
        background: linear-gradient(90deg, transparent, rgba(99,102,241,0.15), transparent);
        pointer-events: none;
    }
    .api-quick-card:hover {
        border-color: rgba(99,102,241,0.2);
        background: rgba(99,102,241,0.03);
        transform: translateY(-2px);
        box-shadow: 0 8px 32px rgba(99,102,241,0.06);
    }
    .api-quick-icon {
        width: 44px; height: 44px;
        border-radius: 13px;
        display: flex;
        align-items: center;
        justify-content: center;
        margin-bottom: 16px;
    }
    .api-quick-icon--purple { background: rgba(168,85,247,0.12); color: #a855f7; }
    .api-quick-icon--blue { background: rgba(59,130,246,0.12); color: #3b82f6; }
    .api-quick-icon--cyan { background: rgba(6,182,212,0.12); color: #06b6d4; }
    .api-quick-title {
        font-size: 0.92rem;
        font-weight: 700;
        color: var(--text-primary);
        margin-bottom: 6px;
    }
    .api-quick-desc {
        font-size: 0.78rem;
        color: var(--text-muted);
        line-height: 1.5;
    }
    .api-quick-arrow {
        position: absolute;
        top: 24px;
        right: 20px;
        color: var(--text-faint);
        transition: all 0.3s;
    }
    .api-quick-card:hover .api-quick-arrow {
        color: var(--text-primary);
        transform: translateX(3px);
    }

    /* 空状态 */
    .api-empty {
        text-align: center;
        padding: 48px 24px;
        color: var(--text-muted);
    }
    .api-empty svg {
        margin-bottom: 16px;
        opacity: 0.4;
    }
    .api-empty-text {
        font-size: 0.88rem;
        margin-bottom: 8px;
    }
    .api-empty-hint {
        font-size: 0.78rem;
        color: var(--text-faint);
    }

    /* Toast 复制提示 */
    .api-toast {
        position: fixed;
        bottom: 24px;
        left: 50%;
        transform: translateX(-50%) translateY(80px);
        padding: 10px 24px;
        background: rgba(16,185,129,0.15);
        border: 1px solid rgba(16,185,129,0.3);
        border-radius: 10px;
        color: #34d399;
        font-size: 0.82rem;
        font-weight: 600;
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        pointer-events: none;
        opacity: 0;
        transition: all 0.4s cubic-bezier(.4,0,.2,1);
        z-index: 999;
    }
    .api-toast.show {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
    }

    /* 创建密钥弹窗 */
    .api-modal-overlay {
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,0.6);
        backdrop-filter: blur(8px);
        -webkit-backdrop-filter: blur(8px);
        z-index: 1000;
        display: none;
        align-items: center;
        justify-content: center;
        opacity: 0;
        transition: opacity 0.3s;
    }
    .api-modal-overlay.show {
        display: flex;
        opacity: 1;
    }
    .api-modal {
        background: var(--bg-elevated, #0f0f1a);
        border: 1px solid rgba(255,255,255,0.08);
        border-radius: 20px;
        padding: 32px;
        width: 440px;
        max-width: 90vw;
        box-shadow: 0 24px 80px rgba(0,0,0,0.5);
        transform: scale(0.95);
        transition: transform 0.3s;
    }
    .api-modal-overlay.show .api-modal {
        transform: scale(1);
    }
    .api-modal-title {
        font-size: 1.1rem;
        font-weight: 700;
        margin-bottom: 6px;
        color: var(--text-primary);
    }
    .api-modal-desc {
        font-size: 0.82rem;
        color: var(--text-muted);
        margin-bottom: 24px;
    }
    .api-modal-field {
        margin-bottom: 20px;
    }
    .api-modal-label {
        display: block;
        font-size: 0.78rem;
        font-weight: 600;
        color: var(--text-secondary);
        margin-bottom: 8px;
    }
    .api-modal-input {
        width: 100%;
        padding: 10px 14px;
        font-size: 0.85rem;
        background: rgba(255,255,255,0.04);
        border: 1px solid rgba(255,255,255,0.08);
        border-radius: 10px;
        color: var(--text-primary);
        outline: none;
        transition: border-color 0.3s;
    }
    .api-modal-input:focus {
        border-color: rgba(99,102,241,0.5);
    }
    .api-modal-input::placeholder { color: var(--text-faint); }
    .api-modal-select {
        width: 100%;
        padding: 10px 14px;
        font-size: 0.85rem;
        background: rgba(255,255,255,0.04);
        border: 1px solid rgba(255,255,255,0.08);
        border-radius: 10px;
        color: var(--text-primary);
        outline: none;
        cursor: pointer;
        appearance: none;
        -webkit-appearance: none;
        background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2364748b' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: right 12px center;
    }
    .api-modal-select:focus {
        border-color: rgba(99,102,241,0.5);
    }
    .api-modal-actions {
        display: flex;
        gap: 10px;
        justify-content: flex-end;
        margin-top: 28px;
    }
    .api-modal-btn {
        padding: 9px 22px;
        font-size: 0.82rem;
        font-weight: 600;
        border-radius: 10px;
        border: none;
        cursor: pointer;
        transition: all 0.2s;
        font-family: inherit;
    }
    .api-modal-btn--cancel {
        background: rgba(255,255,255,0.04);
        border: 1px solid rgba(255,255,255,0.08);
        color: var(--text-secondary);
    }
    .api-modal-btn--cancel:hover {
        background: rgba(255,255,255,0.06);
        border-color: rgba(255,255,255,0.12);
    }
    .api-modal-btn--primary {
        color: #fff;
        background: linear-gradient(135deg, #a855f7, #6366f1);
        box-shadow: 0 0 12px rgba(99,102,241,0.2);
    }
    .api-modal-btn--primary:hover {
        box-shadow: 0 4px 20px rgba(99,102,241,0.3);
        transform: translateY(-1px);
    }

    /* 响应式 */
    @media (max-width: 1100px) {
        .api-stats-row { grid-template-columns: repeat(2, 1fr); }
        .api-quick-grid { grid-template-columns: repeat(2, 1fr); }
    }
    @media (max-width: 700px) {
        .api-stats-row { grid-template-columns: 1fr; }
        .api-quick-grid { grid-template-columns: 1fr; }
        .api-key-meta { display: none; }
    }

    /* ===== 用户下拉菜单 ===== */
    .icon-nav-avatar { position: relative; }
    .user-dropdown {
        position: absolute;
        bottom: 0;
        left: calc(100% + 12px);
        width: 220px;
        background: var(--bg-elevated, #0f0f1a);
        border: 1px solid rgba(255,255,255,0.08);
        border-radius: 16px;
        padding: 12px;
        opacity: 0;
        pointer-events: none;
        transform: translateX(-8px) scale(0.97);
        transition: all 0.25s cubic-bezier(.4,0,.2,1);
        z-index: 999;
        box-shadow: 0 12px 40px rgba(0,0,0,0.4);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
    }
    .user-dropdown.show {
        opacity: 1;
        pointer-events: auto;
        transform: translateX(0) scale(1);
    }
    .user-dropdown-header {
        display: flex; align-items: center; gap: 10px; padding: 6px 4px 10px;
    }
    .user-dropdown-avatar {
        width: 34px; height: 34px;
        border-radius: 10px;
        background: linear-gradient(135deg, #a855f7, #6366f1);
        display: flex; align-items: center; justify-content: center;
        font-size: 0.82rem; font-weight: 700; color: #fff;
        flex-shrink: 0;
    }
    .user-dropdown-info { flex: 1; min-width: 0; }
    .user-dropdown-name { font-size: 0.82rem; font-weight: 600; color: var(--text-primary); }
    .user-dropdown-hint { font-size: 0.68rem; color: var(--text-faint); }
    .user-dropdown-divider { height: 1px; background: rgba(255,255,255,0.06); margin: 6px 0; }
    .user-dropdown-item {
        display: flex; align-items: center; gap: 8px;
        padding: 8px 10px; border-radius: 8px;
        font-size: 0.78rem; color: var(--text-secondary);
        transition: all 0.15s; cursor: pointer; text-decoration: none;
    }
    .user-dropdown-item:hover { background: rgba(255,255,255,0.04); color: var(--text-primary); }
    .user-dropdown-logout { color: #ef4444 !important; }
    .user-dropdown-logout:hover { background: rgba(239,68,68,0.06) !important; }

    /* ===== 亮色模式覆盖 ===== */

    /* 全局 */
    [data-theme="light"] body,
    [data-theme="light"] .creator-layout {
        background: linear-gradient(180deg, transparent 35%, #F5F8FC 55%), linear-gradient(90deg, #ECF4FF 0%, #EBEBFF 45%, #FFF8FA 80%, #F5F8FC 100%), #F5F8FC !important;
        color: #1e293b !important;
    }

    /* 侧边栏 */
    [data-theme="light"] .icon-sidebar {
        background: transparent !important;
        border-right: none !important;
        backdrop-filter: none !important;
    }
    [data-theme="light"] .icon-nav-item { color: #475569 !important; }
    [data-theme="light"] .icon-nav-item:hover { color: #1e293b !important; background: rgba(0,0,0,0.04) !important; }
    [data-theme="light"] .icon-nav-item.active { color: #1e293b !important; background: rgba(255,255,255,0.85) !important; border-radius: 14px !important; box-shadow: 0 2px 10px rgba(0,0,0,0.06) !important; }
    .nav-icon { display: block; }
    .icon-nav-item .nav-icon--on { display: none; }
    .icon-nav-item .nav-icon--off { display: block; }
    .icon-nav-item.active .nav-icon--on { display: block; }
    .icon-nav-item.active .nav-icon--off { display: none; }

    /* 顶栏 */
    [data-theme="light"] .topbar { border-color: rgba(0,0,0,0.06) !important; }

    /* 统计卡片 */
    [data-theme="light"] .api-stat-card {
        background: rgba(255,255,255,0.75) !important;
        border-color: rgba(0,0,0,0.07) !important;
        box-shadow: 0 1px 4px rgba(0,0,0,0.04) !important;
    }
    [data-theme="light"] .api-stat-card:hover {
        background: #fff !important;
        border-color: rgba(0,0,0,0.12) !important;
        box-shadow: 0 4px 16px rgba(0,0,0,0.06) !important;
    }
    [data-theme="light"] .api-stat-value { color: #1e293b !important; }

    /* Key 卡片 */
    [data-theme="light"] .api-key-card {
        background: rgba(255,255,255,0.75) !important;
        border-color: rgba(0,0,0,0.07) !important;
    }
    [data-theme="light"] .api-key-card:hover {
        background: #fff !important;
        border-color: rgba(0,0,0,0.12) !important;
    }
    [data-theme="light"] .api-key-name { color: #1e293b !important; }
    [data-theme="light"] .api-key-value { color: #64748b !important; }
    [data-theme="light"] .api-key-action-btn {
        background: rgba(0,0,0,0.02) !important;
        border-color: rgba(0,0,0,0.08) !important;
        color: #64748b !important;
    }
    [data-theme="light"] .api-key-action-btn:hover {
        background: rgba(99,102,241,0.06) !important;
        border-color: rgba(99,102,241,0.2) !important;
        color: #1e293b !important;
    }

    /* 表格 */
    [data-theme="light"] .api-log-table th {
        color: #64748b !important;
        border-color: rgba(0,0,0,0.06) !important;
        background: #f8f9fc !important;
    }
    [data-theme="light"] .api-log-table td {
        color: #475569 !important;
        border-color: rgba(0,0,0,0.04) !important;
    }
    [data-theme="light"] .api-log-table tbody tr:hover td {
        background: rgba(99,102,241,0.03) !important;
    }
    [data-theme="light"] .api-log-endpoint { color: #1e293b !important; }

    /* 快捷卡片 */
    [data-theme="light"] .api-quick-card {
        background: rgba(255,255,255,0.75) !important;
        border-color: rgba(0,0,0,0.07) !important;
    }
    [data-theme="light"] .api-quick-card:hover {
        background: #fff !important;
        border-color: rgba(0,0,0,0.12) !important;
        box-shadow: 0 4px 16px rgba(0,0,0,0.06) !important;
    }
    [data-theme="light"] .api-quick-title { color: #1e293b !important; }
    [data-theme="light"] .api-quick-desc { color: #64748b !important; }

    /* 弹窗 */
    [data-theme="light"] .api-modal {
        background: #fff !important;
        border-color: rgba(0,0,0,0.08) !important;
        box-shadow: 0 24px 80px rgba(0,0,0,0.12) !important;
    }
    [data-theme="light"] .api-modal-title { color: #1e293b !important; }
    [data-theme="light"] .api-modal-input,
    [data-theme="light"] .api-modal-select {
        background: rgba(0,0,0,0.02) !important;
        border-color: rgba(0,0,0,0.1) !important;
        color: #1e293b !important;
    }
    [data-theme="light"] .api-modal-btn--cancel {
        background: rgba(0,0,0,0.03) !important;
        border-color: rgba(0,0,0,0.1) !important;
        color: #475569 !important;
    }

    /* 下拉菜单 */
    [data-theme="light"] .user-dropdown {
        background: #fff !important;
        border-color: rgba(0,0,0,0.08) !important;
        box-shadow: 0 12px 40px rgba(0,0,0,0.1) !important;
    }
    [data-theme="light"] .user-dropdown-name { color: #1e293b !important; }
    [data-theme="light"] .user-dropdown-item { color: #475569 !important; }
    [data-theme="light"] .user-dropdown-item:hover { background: rgba(0,0,0,0.03) !important; }
    [data-theme="light"] .user-dropdown-divider { background: rgba(0,0,0,0.06) !important; }

    /* 额度 */
    [data-theme="light"] .credits-badge {
        background: rgba(0,0,0,0.04) !important;
        border-color: rgba(0,0,0,0.08) !important;
        color: #475569 !important;
    }

    /* Section 标题 */
    [data-theme="light"] .api-section-title { color: #1e293b !important; }
    [data-theme="light"] .api-section-title svg { color: #94a3b8 !important; }

    /* ===== 暗/亮主题切换图标 ===== */
    .theme-toggle-btn svg.icon-moon { display: none; }
    .theme-toggle-btn svg.icon-sun { display: none; }
    [data-theme="light"] .theme-toggle-btn svg.icon-moon { display: block; }
    html:not([data-theme="light"]) .theme-toggle-btn svg.icon-sun { display: block; }
    </style>
</head>
<body class="creator-layout">
    <!-- 侧边栏 -->
    <aside class="icon-sidebar">
        <a href="create.html" class="icon-sidebar-logo" id="apiLogoLink"><span class="logo-wordmark" id="apiLogoText">本产品</span></a>
        <nav class="icon-nav">
            <a href="create.html" class="icon-nav-item"><img class="nav-icon nav-icon--off" src="assets/icons/nav-create.svg" width="22" height="22" alt=""><img class="nav-icon nav-icon--on" src="assets/icons/nav-create-active.svg" width="22" height="22" alt="">生成</a>
            <a href="media.html" class="icon-nav-item"><img class="nav-icon nav-icon--off" src="assets/icons/nav-media.svg" width="22" height="22" alt=""><img class="nav-icon nav-icon--on" src="assets/icons/nav-media-active.svg" width="22" height="22" alt="">素材</a>
            <a href="result.html" class="icon-nav-item"><img class="nav-icon nav-icon--off" src="assets/icons/nav-result.svg" width="22" height="22" alt=""><img class="nav-icon nav-icon--on" src="assets/icons/nav-result-active.svg" width="22" height="22" alt="">作品</a>
        </nav>
        <div class="icon-nav-bottom">
            <a href="api.html" class="icon-nav-item active" title="API 管理"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M13 10V3L4 14H11V21L20 10H13Z" fill="currentColor" opacity="0.15"/><path d="M13 10V3L4 14H11V21L20 10H13Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg></a>
            <a href="#" class="icon-nav-item theme-toggle-btn" id="themeToggleBtn" title="切换明暗模式">
                <svg class="icon-sun" width="20" height="20" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="5" stroke="currentColor" stroke-width="1.5"></circle><path d="M12 1V3M12 21V23M4.22 4.22L5.64 5.64M18.36 18.36L19.78 19.78M1 12H3M21 12H23M4.22 19.78L5.64 18.36M18.36 5.64L19.78 4.22" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg>
                <svg class="icon-moon" width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
            </a>
            <div class="icon-nav-avatar" id="userAvatar" title="用户"><span id="userAvatarLetter">U</span></div>
            <div class="user-dropdown" id="userDropdown">
                <div class="user-dropdown-header">
                    <div class="user-dropdown-avatar" id="dropdownAvatar">U</div>
                    <div class="user-dropdown-info">
                        <div class="user-dropdown-name" id="dropdownName">未登录</div>
                        <div class="user-dropdown-hint" id="dropdownHint">点击登录</div>
                    </div>
                </div>
                <div class="user-dropdown-divider"></div>
                <a href="#" class="user-dropdown-item" id="userLoginBtn">
                    <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 2H4C2.89543 2 2 2.89543 2 4V12C2 13.1046 2.89543 14 4 14H6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M10 11L14 8L10 5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 8H6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
                    登录
                </a>
                <a href="#" class="user-dropdown-item user-dropdown-logout" id="userLogoutBtn" style="display:none;">
                    <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 2H4C2.89543 2 2 2.89543 2 4V12C2 13.1046 2.89543 14 4 14H6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M10 11L14 8L10 5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 8H6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
                    退出登录
                </a>
            </div>
        </div>
    </aside>

    <main class="main-content">
        <!-- 顶部栏 -->
        <header class="topbar">
            <div class="topbar-left"><h1 class="page-title">API 管理</h1></div>
            <div class="topbar-right">
                <div class="credits-badge">
                    <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 5V8L10 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                    <span>剩余 47 次</span>
                </div>
            </div>
        </header>

        <!-- 统计卡片 -->
        <div class="api-stats-row">
            <div class="api-stat-card">
                <div class="api-stat-top">
                    <div class="api-stat-icon api-stat-icon--purple">
                        <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M10 2V18M6 6L10 2L14 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 10H17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                    </div>
                    <span class="api-stat-trend api-stat-trend--up">
                        <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M2 7L5 3L8 7" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                        +24%
                    </span>
                </div>
                <div class="api-stat-value">12,847</div>
                <div class="api-stat-label">本月调用次数</div>
            </div>
            <div class="api-stat-card">
                <div class="api-stat-top">
                    <div class="api-stat-icon api-stat-icon--green">
                        <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="7" stroke="currentColor" stroke-width="1.5"/><path d="M7 10L9 12L13 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
                    </div>
                </div>
                <div class="api-stat-value">99.2%</div>
                <div class="api-stat-label">请求成功率</div>
            </div>
            <div class="api-stat-card">
                <div class="api-stat-top">
                    <div class="api-stat-icon api-stat-icon--blue">
                        <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="7" stroke="currentColor" stroke-width="1.5"/><path d="M10 6V10L13 11.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                    </div>
                </div>
                <div class="api-stat-value">238ms</div>
                <div class="api-stat-label">平均响应时间</div>
            </div>
            <div class="api-stat-card">
                <div class="api-stat-top">
                    <div class="api-stat-icon api-stat-icon--amber">
                        <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><rect x="3" y="8" width="3" height="9" rx="1" stroke="currentColor" stroke-width="1.3"/><rect x="8.5" y="5" width="3" height="12" rx="1" stroke="currentColor" stroke-width="1.3"/><rect x="14" y="3" width="3" height="14" rx="1" stroke="currentColor" stroke-width="1.3"/></svg>
                    </div>
                    <span class="api-stat-trend api-stat-trend--down">
                        <svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M2 3L5 7L8 3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                        -3%
                    </span>
                </div>
                <div class="api-stat-value">¥186</div>
                <div class="api-stat-label">本月消费</div>
            </div>
        </div>

        <!-- API 密钥管理 -->
        <div class="api-section-header">
            <div class="api-section-title">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10.5 2.5C11.6046 2.5 12.5 3.39543 12.5 4.5C12.5 5.60457 11.6046 6.5 10.5 6.5C9.39543 6.5 8.5 5.60457 8.5 4.5C8.5 3.39543 9.39543 2.5 10.5 2.5Z" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 4.5H2V7H4.5V4.5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
                API 密钥
                <span class="api-section-badge">3 个活跃</span>
            </div>
            <button class="api-create-btn" id="createKeyBtn">
                <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2V12M2 7H12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
                创建密钥
            </button>
        </div>

        <div class="api-keys-list" id="apiKeysList">
            <!-- Key 1 -->
            <div class="api-key-card">
                <div class="api-key-icon">
                    <svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M12 6.5C12 4.567 10.433 3 8.5 3C6.567 3 5 4.567 5 6.5C5 8.433 6.567 10 8.5 10" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 10H14.5V12.5H12.5V10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
                </div>
                <div class="api-key-info">
                    <div class="api-key-name">
                        生产环境主密钥
                        <span class="key-status key-status--active">活跃</span>
                    </div>
                    <div class="api-key-value">sk-api-prod-****-****-****-a3f7b2c1</div>
                </div>
                <div class="api-key-meta">
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">8,432</div>
                        <div class="api-key-meta-label">本月调用</div>
                    </div>
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">03-20</div>
                        <div class="api-key-meta-label">创建日期</div>
                    </div>
                </div>
                <div class="api-key-actions">
                    <button class="api-key-action-btn" title="复制密钥" data-copy="[REDACTED_SECRET]">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="5" y="5" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M9 5V3.5C9 2.67157 8.32843 2 7.5 2H3.5C2.67157 2 2 2.67157 2 3.5V7.5C2 8.32843 2.67157 9 3.5 9H5" stroke="currentColor" stroke-width="1.2"/></svg>
                    </button>
                    <button class="api-key-action-btn api-key-action-btn--danger" title="删除">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 4.5H11M5.5 4.5V3C5.5 2.44772 5.94772 2 6.5 2H7.5C8.05228 2 8.5 2.44772 8.5 3V4.5M4 4.5L4.5 11.5C4.5 12.0523 4.94772 12.5 5.5 12.5H8.5C9.05228 12.5 9.5 12.0523 9.5 11.5L10 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
                    </button>
                </div>
            </div>

            <!-- Key 2 -->
            <div class="api-key-card">
                <div class="api-key-icon">
                    <svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M12 6.5C12 4.567 10.433 3 8.5 3C6.567 3 5 4.567 5 6.5C5 8.433 6.567 10 8.5 10" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 10H14.5V12.5H12.5V10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
                </div>
                <div class="api-key-info">
                    <div class="api-key-name">
                        开发测试密钥
                        <span class="key-status key-status--active">活跃</span>
                    </div>
                    <div class="api-key-value">sk-api-dev-****-****-****-e9d1f8a4</div>
                </div>
                <div class="api-key-meta">
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">3,215</div>
                        <div class="api-key-meta-label">本月调用</div>
                    </div>
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">03-15</div>
                        <div class="api-key-meta-label">创建日期</div>
                    </div>
                </div>
                <div class="api-key-actions">
                    <button class="api-key-action-btn" title="复制密钥" data-copy="[REDACTED_SECRET]">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="5" y="5" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M9 5V3.5C9 2.67157 8.32843 2 7.5 2H3.5C2.67157 2 2 2.67157 2 3.5V7.5C2 8.32843 2.67157 9 3.5 9H5" stroke="currentColor" stroke-width="1.2"/></svg>
                    </button>
                    <button class="api-key-action-btn api-key-action-btn--danger" title="删除">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 4.5H11M5.5 4.5V3C5.5 2.44772 5.94772 2 6.5 2H7.5C8.05228 2 8.5 2.44772 8.5 3V4.5M4 4.5L4.5 11.5C4.5 12.0523 4.94772 12.5 5.5 12.5H8.5C9.05228 12.5 9.5 12.0523 9.5 11.5L10 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
                    </button>
                </div>
            </div>

            <!-- Key 3 -->
            <div class="api-key-card">
                <div class="api-key-icon" style="background:rgba(239,68,68,0.08);color:#f87171;">
                    <svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M12 6.5C12 4.567 10.433 3 8.5 3C6.567 3 5 4.567 5 6.5C5 8.433 6.567 10 8.5 10" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 10H14.5V12.5H12.5V10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
                </div>
                <div class="api-key-info">
                    <div class="api-key-name">
                        旧版兼容密钥
                        <span class="key-status key-status--expired">已过期</span>
                    </div>
                    <div class="api-key-value">sk-api-legacy-****-****-****-7b2e4f09</div>
                </div>
                <div class="api-key-meta">
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">1,200</div>
                        <div class="api-key-meta-label">累计调用</div>
                    </div>
                    <div class="api-key-meta-item">
                        <div class="api-key-meta-value">02-28</div>
                        <div class="api-key-meta-label">过期日期</div>
                    </div>
                </div>
                <div class="api-key-actions">
                    <button class="api-key-action-btn" title="复制密钥" data-copy="[REDACTED_SECRET]">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="5" y="5" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M9 5V3.5C9 2.67157 8.32843 2 7.5 2H3.5C2.67157 2 2 2.67157 2 3.5V7.5C2 8.32843 2.67157 9 3.5 9H5" stroke="currentColor" stroke-width="1.2"/></svg>
                    </button>
                    <button class="api-key-action-btn api-key-action-btn--danger" title="删除">
                        <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 4.5H11M5.5 4.5V3C5.5 2.44772 5.94772 2 6.5 2H7.5C8.05228 2 8.5 2.44772 8.5 3V4.5M4 4.5L4.5 11.5C4.5 12.0523 4.94772 12.5 5.5 12.5H8.5C9.05228 12.5 9.5 12.0523 9.5 11.5L10 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
                    </button>
                </div>
            </div>
        </div>

        <!-- 最近调用日志 -->
        <div class="api-section-header">
            <div class="api-section-title">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 3H14M2 6.5H14M2 10H10M2 13.5H8" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
                最近调用
            </div>
        </div>

        <table class="api-log-table">
            <thead>
                <tr>
                    <th>方法</th>
                    <th>接口</th>
                    <th>状态</th>
                    <th>延迟</th>
                    <th>时间</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><span class="api-log-method method--post">POST</span></td>
                    <td class="api-log-endpoint">/v1/video/translate</td>
                    <td><span class="api-log-status status--200">200</span></td>
                    <td class="api-log-latency">342ms</td>
                    <td class="api-log-time">2 分钟前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--post">POST</span></td>
                    <td class="api-log-endpoint">/v1/subtitle/erase</td>
                    <td><span class="api-log-status status--200">200</span></td>
                    <td class="api-log-latency">189ms</td>
                    <td class="api-log-time">8 分钟前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--get">GET</span></td>
                    <td class="api-log-endpoint">/v1/task/status/t-7b2e4f09</td>
                    <td><span class="api-log-status status--200">200</span></td>
                    <td class="api-log-latency">45ms</td>
                    <td class="api-log-time">12 分钟前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--post">POST</span></td>
                    <td class="api-log-endpoint">/v1/voice/synthesize</td>
                    <td><span class="api-log-status status--201">201</span></td>
                    <td class="api-log-latency">1,247ms</td>
                    <td class="api-log-time">25 分钟前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--post">POST</span></td>
                    <td class="api-log-endpoint">/v1/video/translate</td>
                    <td><span class="api-log-status status--400">400</span></td>
                    <td class="api-log-latency">28ms</td>
                    <td class="api-log-time">1 小时前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--get">GET</span></td>
                    <td class="api-log-endpoint">/v1/media/list</td>
                    <td><span class="api-log-status status--200">200</span></td>
                    <td class="api-log-latency">112ms</td>
                    <td class="api-log-time">1 小时前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--delete">DELETE</span></td>
                    <td class="api-log-endpoint">/v1/task/t-9a3c1d7e</td>
                    <td><span class="api-log-status status--200">200</span></td>
                    <td class="api-log-latency">67ms</td>
                    <td class="api-log-time">2 小时前</td>
                </tr>
                <tr>
                    <td><span class="api-log-method method--post">POST</span></td>
                    <td class="api-log-endpoint">/v1/subtitle/translate</td>
                    <td><span class="api-log-status status--500">500</span></td>
                    <td class="api-log-latency">5,012ms</td>
                    <td class="api-log-time">3 小时前</td>
                </tr>
            </tbody>
        </table>

        <!-- 快捷入口 -->
        <div class="api-section-header">
            <div class="api-section-title">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 2H7V7H2V2Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M9 2H14V7H9V2Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M2 9H7V14H2V9Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><circle cx="11.5" cy="11.5" r="2.5" stroke="currentColor" stroke-width="1.3"/></svg>
                开发者资源
            </div>
        </div>

        <div class="api-quick-grid">
            <div class="api-quick-card" onclick="window.open('#docs','_blank')">
                <div class="api-quick-icon api-quick-icon--purple">
                    <svg width="22" height="22" viewBox="0 0 22 22" fill="none"><path d="M4 3H14L18 7V19H4V3Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M14 3V7H18" stroke="currentColor" stroke-width="1.5"/><path d="M7 11H15M7 14H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                </div>
                <div class="api-quick-title">API 文档</div>
                <div class="api-quick-desc">完整的 RESTful API 参考文档，包含请求示例和响应格式</div>
                <svg class="api-quick-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </div>
            <div class="api-quick-card" onclick="window.open('#sdk','_blank')">
                <div class="api-quick-icon api-quick-icon--blue">
                    <svg width="22" height="22" viewBox="0 0 22 22" fill="none"><path d="M7 7L3 11L7 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M15 7L19 11L15 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M13 4L9 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                </div>
                <div class="api-quick-title">SDK & 代码示例</div>
                <div class="api-quick-desc">Python / Node.js / Java SDK，快速集成 API 能力到你的应用到你的应用</div>
                <svg class="api-quick-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </div>
            <div class="api-quick-card" onclick="window.open('#webhook','_blank')">
                <div class="api-quick-icon api-quick-icon--cyan">
                    <svg width="22" height="22" viewBox="0 0 22 22" fill="none"><circle cx="11" cy="5" r="3" stroke="currentColor" stroke-width="1.5"/><circle cx="5" cy="16" r="3" stroke="currentColor" stroke-width="1.5"/><circle cx="17" cy="16" r="3" stroke="currentColor" stroke-width="1.5"/><path d="M11 8V11L5 16M11 11L17 16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
                </div>
                <div class="api-quick-title">Webhook 配置</div>
                <div class="api-quick-desc">任务完成回调通知，实时获取译制/擦除/配音处理结果</div>
                <svg class="api-quick-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </div>
        </div>
    </main>

    <!-- 创建密钥弹窗 -->
    <div class="api-modal-overlay" id="createKeyModal">
        <div class="api-modal">
            <div class="api-modal-title">创建 API 密钥</div>
            <div class="api-modal-desc">为你的应用或服务创建一个新的 API 访问密钥</div>
            <div class="api-modal-field">
                <label class="api-modal-label">密钥名称</label>
                <input class="api-modal-input" id="keyNameInput" type="text" placeholder="例如：生产环境主密钥">
            </div>
            <div class="api-modal-field">
                <label class="api-modal-label">有效期</label>
                <select class="api-modal-select" id="keyExpiry">
                    <option value="30">30 天</option>
                    <option value="90" selected>90 天</option>
                    <option value="180">180 天</option>
                    <option value="365">1 年</option>
                    <option value="0">永不过期</option>
                </select>
            </div>
            <div class="api-modal-field">
                <label class="api-modal-label">权限范围</label>
                <select class="api-modal-select" id="keyScope">
                    <option value="full" selected>完整权限（读写）</option>
                    <option value="read">只读权限</option>
                    <option value="translate">仅译制 API</option>
                    <option value="media">仅媒体管理 API</option>
                </select>
            </div>
            <div class="api-modal-actions">
                <button class="api-modal-btn api-modal-btn--cancel" id="cancelCreateKey">取消</button>
                <button class="api-modal-btn api-modal-btn--primary" id="confirmCreateKey">创建</button>
            </div>
        </div>
    </div>

    <!-- 复制 Toast -->
    <div class="api-toast" id="apiToast">✓ 已复制到剪贴板</div>

    <script src="app.js"></script>

    <!-- 主题切换逻辑 -->
    <script>
    (function() {
        var STORAGE_KEY = 'ptheme';
        var html = document.documentElement;

        var saved = localStorage.getItem(STORAGE_KEY);
        if (saved === 'dark') {
            html.removeAttribute('data-theme');
        } else if (saved === 'light') {
            html.setAttribute('data-theme', 'light');
        }
        if (!saved && window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
            html.setAttribute('data-theme', 'light');
        }

        var btn = document.getElementById('themeToggleBtn');
        if (btn) {
            btn.addEventListener('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
                var current = html.getAttribute('data-theme');
                if (current === 'light') {
                    html.removeAttribute('data-theme');
                    localStorage.setItem(STORAGE_KEY, 'dark');
                } else {
                    html.setAttribute('data-theme', 'light');
                    localStorage.setItem(STORAGE_KEY, 'light');
                }
            });
        }
    })();
    </script>

    <!-- 用户菜单逻辑 -->
    <script>
    (function() {
        var avatar = document.getElementById('userAvatar');
        var avatarLetter = document.getElementById('userAvatarLetter');
        var dropdown = document.getElementById('userDropdown');
        var dropdownAvatar = document.getElementById('dropdownAvatar');
        var dropdownName = document.getElementById('dropdownName');
        var dropdownHint = document.getElementById('dropdownHint');
        var loginBtn = document.getElementById('userLoginBtn');
        var logoutBtn = document.getElementById('userLogoutBtn');

        function updateUserUI() {
            var raw = localStorage.getItem('puser');
            if (raw) {
                try {
                    var user = JSON.parse(raw);
                    var initial = user.avatar || user.name.charAt(0).toUpperCase();
                    avatarLetter.textContent = initial;
                    dropdownAvatar.textContent = initial;
                    dropdownName.textContent = user.name;
                    dropdownHint.textContent = '已登录';
                    loginBtn.style.display = 'none';
                    logoutBtn.style.display = 'flex';
                    avatar.title = user.name;
                } catch(e) {}
            } else {
                avatarLetter.textContent = 'U';
                dropdownAvatar.textContent = 'U';
                dropdownName.textContent = '未登录';
                dropdownHint.textContent = '点击登录';
                loginBtn.style.display = 'flex';
                logoutBtn.style.display = 'none';
                avatar.title = '用户';
            }
        }

        avatar.addEventListener('click', function(e) {
            e.stopPropagation();
            dropdown.classList.toggle('show');
        });
        document.addEventListener('click', function(e) {
            if (!dropdown.contains(e.target) && e.target !== avatar) {
                dropdown.classList.remove('show');
            }
        });
        loginBtn.addEventListener('click', function(e) {
            e.preventDefault();
            window.location.href = 'login.html';
        });
        logoutBtn.addEventListener('click', function(e) {
            e.preventDefault();
            localStorage.removeItem('puser');
            updateUserUI();
            dropdown.classList.remove('show');
        });
        updateUserUI();
        window.addEventListener('storage', function(e) {
            if (e.key === 'puser') updateUserUI();
        });
    })();
    </script>

    <!-- API 页面交互逻辑 -->
    <script>
    (function() {
        // 复制密钥
        document.querySelectorAll('.api-key-action-btn[data-copy]').forEach(function(btn) {
            btn.addEventListener('click', function() {
                var text = btn.getAttribute('data-copy');
                navigator.clipboard.writeText(text).then(function() {
                    showToast('✓ 已复制到剪贴板');
                }).catch(function() {
                    // 降级方案
                    var ta = document.createElement('textarea');
                    ta.value = text;
                    document.body.appendChild(ta);
                    ta.select();
                    document.execCommand('copy');
                    document.body.removeChild(ta);
                    showToast('✓ 已复制到剪贴板');
                });
            });
        });

        // Toast
        var toastTimer = null;
        function showToast(msg) {
            var toast = document.getElementById('apiToast');
            toast.textContent = msg;
            toast.classList.add('show');
            clearTimeout(toastTimer);
            toastTimer = setTimeout(function() {
                toast.classList.remove('show');
            }, 2000);
        }

        // 删除密钥
        document.querySelectorAll('.api-key-action-btn--danger').forEach(function(btn) {
            btn.addEventListener('click', function() {
                var card = btn.closest('.api-key-card');
                var name = card.querySelector('.api-key-name').textContent.trim().split('\n')[0].trim();
                if (confirm('确定要删除密钥「' + name + '」吗？此操作不可撤销。')) {
                    card.style.opacity = '0';
                    card.style.transform = 'translateX(-20px)';
                    card.style.transition = 'all 0.3s';
                    setTimeout(function() { card.remove(); }, 300);
                    showToast('🗑️ 密钥已删除');
                }
            });
        });

        // 创建密钥弹窗
        var modal = document.getElementById('createKeyModal');
        document.getElementById('createKeyBtn').addEventListener('click', function() {
            modal.classList.add('show');
            setTimeout(function() {
                document.getElementById('keyNameInput').focus();
            }, 100);
        });
        document.getElementById('cancelCreateKey').addEventListener('click', function() {
            modal.classList.remove('show');
        });
        modal.addEventListener('click', function(e) {
            if (e.target === modal) modal.classList.remove('show');
        });
        document.getElementById('confirmCreateKey').addEventListener('click', function() {
            var name = document.getElementById('keyNameInput').value.trim();
            if (!name) {
                document.getElementById('keyNameInput').style.borderColor = 'rgba(239,68,68,0.5)';
                document.getElementById('keyNameInput').focus();
                return;
            }
            // 模拟创建
            var newKey = 'sk-api-' + Math.random().toString(36).substr(2, 8);
            var list = document.getElementById('apiKeysList');
            var card = document.createElement('div');
            card.className = 'api-key-card';
            card.style.opacity = '0';
            card.style.transform = 'translateY(-10px)';
            card.innerHTML =
                '<div class="api-key-icon"><svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M12 6.5C12 4.567 10.433 3 8.5 3C6.567 3 5 4.567 5 6.5C5 8.433 6.567 10 8.5 10" stroke="currentColor" stroke-width="1.3"/><path d="M8.5 10H14.5V12.5H12.5V10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg></div>' +
                '<div class="api-key-info"><div class="api-key-name">' + name + ' <span class="key-status key-status--active">活跃</span></div><div class="api-key-value">' + newKey + '</div></div>' +
                '<div class="api-key-meta"><div class="api-key-meta-item"><div class="api-key-meta-value">0</div><div class="api-key-meta-label">本月调用</div></div><div class="api-key-meta-item"><div class="api-key-meta-value">今天</div><div class="api-key-meta-label">创建日期</div></div></div>' +
                '<div class="api-key-actions"><button class="api-key-action-btn" title="复制密钥" data-copy="' + newKey + '"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="5" y="5" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M9 5V3.5C9 2.67157 8.32843 2 7.5 2H3.5C2.67157 2 2 2.67157 2 3.5V7.5C2 8.32843 2.67157 9 3.5 9H5" stroke="currentColor" stroke-width="1.2"/></svg></button><button class="api-key-action-btn api-key-action-btn--danger" title="删除"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 4.5H11M5.5 4.5V3C5.5 2.44772 5.94772 2 6.5 2H7.5C8.05228 2 8.5 2.44772 8.5 3V4.5M4 4.5L4.5 11.5C4.5 12.0523 4.94772 12.5 5.5 12.5H8.5C9.05228 12.5 9.5 12.0523 9.5 11.5L10 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg></button></div>';
            list.insertBefore(card, list.firstChild);
            requestAnimationFrame(function() {
                card.style.transition = 'all 0.4s cubic-bezier(.4,0,.2,1)';
                card.style.opacity = '1';
                card.style.transform = 'translateY(0)';
            });

            // 绑定新卡片的复制和删除
            card.querySelector('[data-copy]').addEventListener('click', function() {
                navigator.clipboard.writeText(newKey).then(function() { showToast('✓ 已复制到剪贴板'); });
            });
            card.querySelector('.api-key-action-btn--danger').addEventListener('click', function() {
                if (confirm('确定要删除密钥「' + name + '」吗？')) {
                    card.style.opacity = '0';
                    card.style.transform = 'translateX(-20px)';
                    setTimeout(function() { card.remove(); }, 300);
                    showToast('🗑️ 密钥已删除');
                }
            });

            modal.classList.remove('show');
            document.getElementById('keyNameInput').value = '';
            showToast('🔑 新密钥已创建');
        });
    })();
    </script>
</body>
</html>


path: assets/prd.html
content: <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tideo · 产品需求文档（PRD）</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Text',sans-serif;background:#08080c;color:#e2e8f0;line-height:1.7}
.page{max-width:780px;margin:0 auto;padding:40px 24px 100px}
.back{display:inline-flex;align-items:center;gap:4px;font-size:.78rem;color:#64748b;text-decoration:none;margin-bottom:20px}
.back:hover{color:#94a3b8}
.cover{text-align:center;padding:40px 0 48px;border-bottom:1px solid rgba(255,255,255,0.05);margin-bottom:32px}
.cover h1{font-size:2rem;font-weight:800;margin-bottom:4px}
.cover .sub{font-size:1rem;color:#94a3b8;margin-bottom:16px}
.cover .meta{font-size:.75rem;color:#475569;line-height:1.8}
.cover a{color:#818cf8;text-decoration:none}
.copy-hint{position:fixed;top:16px;right:16px;padding:6px 14px;border-radius:8px;background:rgba(16,185,129,0.15);border:1px solid rgba(16,185,129,0.3);color:#10b981;font-size:.72rem;font-weight:500;opacity:0;transition:opacity .3s;pointer-events:none;z-index:100}
.copy-hint.show{opacity:1}
h2{font-size:1.1rem;font-weight:700;margin:32px 0 12px;padding-top:20px;border-top:1px solid rgba(255,255,255,0.05)}
h3{font-size:.92rem;font-weight:600;margin:18px 0 8px;color:#cbd5e1}
h4{font-size:.82rem;font-weight:600;margin:12px 0 6px;color:#94a3b8}
p{font-size:.85rem;color:#94a3b8;margin-bottom:10px}
ul,ol{font-size:.85rem;color:#94a3b8;margin:0 0 12px 20px}
li{margin-bottom:4px}
li::marker{color:#475569}
strong{color:#e2e8f0}
code{background:rgba(255,255,255,0.08);padding:1px 6px;border-radius:4px;font-size:.78rem;color:#e2e8f0}
.callout{padding:14px 16px;border-radius:10px;margin:12px 0;font-size:.82rem}
.callout-blue{background:rgba(129,140,248,0.08);border-left:3px solid #818cf8;color:#cbd5e1}
.callout-green{background:rgba(16,185,129,0.08);border-left:3px solid #10b981;color:#cbd5e1}
.callout-yellow{background:rgba(245,158,11,0.08);border-left:3px solid #f59e0b;color:#cbd5e1}
.callout-purple{background:rgba(168,85,247,0.08);border-left:3px solid #a855f7;color:#cbd5e1}
table{width:100%;border-collapse:collapse;font-size:.8rem;margin:10px 0 16px}
th{text-align:left;padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.1);color:#64748b;font-weight:500}
td{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.03);color:#94a3b8}
.flow{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:10px 0 16px}
.flow-step{padding:6px 14px;border-radius:8px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.08);font-size:.78rem;color:#cbd5e1}
.flow-step.active{background:rgba(129,140,248,0.1);border-color:rgba(129,140,248,0.25);color:#818cf8}
.flow-arrow{color:#334155;font-size:.75rem}
.toc{margin:20px 0 32px;padding:20px;border-radius:12px;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.06)}
.toc h3{margin:0 0 12px;font-size:.85rem;color:#94a3b8}
.toc a{display:block;padding:4px 0;font-size:.8rem;color:#64748b;text-decoration:none;transition:color .2s}
.toc a:hover{color:#e2e8f0}
.toc a.l2{padding-left:16px;font-size:.75rem}
.diagram{padding:16px;border-radius:10px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);font-family:monospace;font-size:.72rem;color:#94a3b8;line-height:1.8;white-space:pre;overflow-x:auto;margin:10px 0 16px}
.copy-all{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border-radius:8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);color:#94a3b8;font-size:.78rem;cursor:pointer;transition:all .2s;margin-bottom:20px;font-family:inherit}
.copy-all:hover{background:rgba(255,255,255,0.1);color:#e2e8f0}
</style>
</head>
<body>
<div class="page">

<a class="back" href="hub.html"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> 返回产品中心</a>

<button class="copy-all" id="copyBtn"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><rect x="5" y="5" width="8" height="8" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M11 5V3.5C11 2.67 10.33 2 9.5 2H3.5C2.67 2 2 2.67 2 3.5V9.5C2 10.33 2.67 11 3.5 11H5" stroke="currentColor" stroke-width="1.2"/></svg> 复制全文</button>

<div class="cover">
    <h1>Tideo PRD</h1>
    <div class="sub">产品需求文档</div>
    <div class="meta">
        腾讯云音视频能力轻量化统一平台<br>
        版本：visual1 · 2026-04-15<br>
        <a href="https://ildar981105-create.github.io/visual1/app/create.html" target="_blank">在线体验</a>
    </div>
</div>

<div class="toc">
    <h3>目录</h3>
    <a href="#s1">1. 产品定义与目标用户</a>
    <a href="#s2">2. 产品入口</a>
    <a href="#s3">3. 页面结构总览</a>
    <a href="#s4">4. 创作页 — 统一入口</a>
    <a href="#s5">5. 影视译制</a>
    <a href="#s5-1" class="l2">5.1 工作坊对话体验</a>
    <a href="#s5-2" class="l2">5.2 精调面板</a>
    <a href="#s6">6. 视频制作（AI 生成）</a>
    <a href="#s6-1" class="l2">6.1 分镜工作坊</a>
    <a href="#s6-2" class="l2">6.2 分镜精调</a>
    <a href="#s7">7. 直播剪辑</a>
    <a href="#s8">8. 精调统一视觉规范</a>
    <a href="#s9">9. 产品特色</a>
    <a href="#s10">10. 当前状态与规划</a>
</div>

<div id="prdContent">

<!-- ===== 1 ===== -->
<h2 id="s1">1. 产品定义与目标用户</h2>

<div class="callout callout-blue">
    <strong>Tideo</strong> 是腾讯云音视频能力的轻量化统一平台 — 整合云点播（VOD）、云直播、MPS 的公用功能，提供开箱即用的可视化操作界面。<br>
    首期聚焦三大核心功能：<strong>影视译制 · 视频制作 · 直播剪辑</strong>。
</div>

<h3>目标用户</h3>
<ul>
    <li><strong>中小企业</strong> — 无技术团队，需要开箱即用的音视频工具</li>
    <li><strong>短剧出海团队</strong> — 中文短剧翻译成英/日/韩发行海外</li>
    <li><strong>内容创作者</strong> — 视频多语言化扩大受众</li>
    <li><strong>企业市场部</strong> — 宣传片、培训视频多语言本地化</li>
    <li><strong>直播运营团队</strong> — 从直播中快速剪辑精彩片段</li>
</ul>

<!-- ===== 2 ===== -->
<h2 id="s2">2. 产品入口</h2>

<h3>入口一：MPS / VOD 任务列表 — 二次编辑</h3>
<p>在腾讯云 MPS 和 VOD 的任务列表中，凡是与视频译制、视频生成相关的已完成任务，任务行上提供<strong>"二次编辑"</strong>按钮。</p>
<ul>
    <li>点击后直接跳转到 Tideo 对应的<strong>精调页面</strong>，跳过创作页和对话流程</li>
    <li>用户可调整擦除区域、字幕翻译、配音参数或分镜内容，然后重新提交</li>
</ul>

<div class="diagram">MPS / VOD 控制台 → 任务列表
  ├── 译制任务  [已完成]  [二次编辑 →]  → Tideo 擦除/字幕/配音精调
  └── 生成任务  [已完成]  [二次编辑 →]  → Tideo 分镜精调</div>

<h3>入口二：控制台菜单 — SaaS 工具</h3>
<p>在 VOD、云直播、MPS 控制台的侧边栏菜单中，统一增加<strong>"SaaS 工具"</strong>入口，点击跳转到 Tideo 创作页，从零开始创建新任务。</p>

<h3>入口三：独立访问</h3>
<p>Tideo 同时作为独立站点直接访问，适用于无腾讯云账号的外部用户和分享链接场景。</p>

<h3>账号打通</h3>
<table>
    <tr><th>入口</th><th>登录方式</th></tr>
    <tr><td>腾讯云控制台</td><td>SSO 单点登录，继承腾讯云账号</td></tr>
    <tr><td>独立站点</td><td>手机号 / 邮箱 / 微信，关联腾讯云子账号</td></tr>
    <tr><td>分享链接</td><td>游客模式（受限功能）</td></tr>
</table>

<!-- ===== 3 ===== -->
<h2 id="s3">3. 页面结构总览</h2>

<table>
    <tr><th>页面</th><th>说明</th></tr>
    <tr><td><strong>创作页</strong>（主入口）</td><td>首页视图 + 智能输入框 + 技能卡片 + 配置项</td></tr>
    <tr><td><strong>影视译制</strong></td><td>四角色对话工作坊 + 擦除/字幕/配音精调</td></tr>
    <tr><td><strong>视频制作</strong></td><td>四角色分镜工作坊 + 分镜精调</td></tr>
    <tr><td><strong>直播剪辑</strong></td><td>直播流监控 + 精彩片段提取</td></tr>
    <tr><td>素材管理</td><td>已上传素材的浏览和管理</td></tr>
    <tr><td>任务记录</td><td>历史任务列表 + 结果查看 + 下载</td></tr>
    <tr><td>登录</td><td>手机号 / 邮箱 / 微信扫码</td></tr>
</table>
<p>侧边栏三个入口：<strong>创作 → 素材 → 作品</strong></p>

<!-- ===== 4 ===== -->
<h2 id="s4">4. 创作页 — 统一入口</h2>

<h3>4.1 智能输入框</h3>
<p>页面底部的统一输入框，三种触发方式：</p>
<ul>
    <li><strong>点击技能卡片</strong>（影视译制 / 视频制作 / 直播剪辑）→ 展示对应配置项和默认提示词</li>
    <li><strong>自然语言输入</strong>（如"帮我翻译成英语"）→ 自动识别意图并匹配技能</li>
    <li><strong>直接上传视频</strong> → 自动识别为影视译制</li>
</ul>

<h3>4.2 视频来源三路径</h3>
<p>影视译制支持三种视频来源：</p>
<ul>
    <li><strong>上传视频</strong>：本地文件 → 进入对话工作坊流程</li>
    <li><strong>导入任务</strong>：输入 VOD/MPS 任务 ID → 直接进入精调</li>
    <li><strong>项目文件</strong>：原视频 + 可选配置文件 → 直接进入精调</li>
</ul>

<h3>4.3 右侧角色群像</h3>
<p>创作页右侧展示 Tideo 团队 6 名角色群像。选中不同技能时切换为对应团队配图。Hover 角色可查看姓名、职责、技能标签和台词。</p>
<table>
    <tr><th>角色</th><th>职责</th><th>出现在</th></tr>
    <tr><td>林雨晨</td><td>导演</td><td>译制 + 生成</td></tr>
    <tr><td>陈默</td><td>后期</td><td>译制（擦除）+ 生成（剪辑）</td></tr>
    <tr><td>李明远</td><td>翻译 / 编剧</td><td>译制（翻译）+ 生成（分镜）</td></tr>
    <tr><td>苏雅</td><td>配音 / 艺术指导</td><td>译制（配音）+ 生成（画面）</td></tr>
    <tr><td>赵思琪</td><td>美术指导</td><td>创作页展示</td></tr>
    <tr><td>王大力</td><td>摄影师</td><td>创作页展示</td></tr>
</table>

<!-- ===== 5 ===== -->
<h2 id="s5">5. 影视译制</h2>

<h3>功能概述</h3>
<p>上传视频后，系统自动完成<strong>字幕擦除 → 字幕翻译 → AI 配音</strong>，输出多语言成片。</p>

<h4>处理模式</h4>
<table>
    <tr><th>模式</th><th>包含能力</th></tr>
    <tr><td><strong>完整模式</strong></td><td>字幕擦除 + 字幕翻译 + AI 配音</td></tr>
    <tr><td>字幕擦除</td><td>仅擦除画面中的字幕和水印</td></tr>
    <tr><td>字幕翻译</td><td>识别语音 + 翻译 + 字幕压制</td></tr>
    <tr><td>配音</td><td>语音识别 + 翻译 + AI 克隆配音</td></tr>
</table>

<h4>配置项</h4>
<ul>
    <li><strong>语言</strong>：源语言（中/英/日/韩/自动）→ 目标语言（英/日/韩/西/法/德/中）</li>
    <li><strong>字幕</strong>：压制风格（标准/电影/花字/极简）或文件导出（SRT/ASS）</li>
    <li><strong>配音</strong>：克隆音色 / 女声 / 男声 / 自动 / 关闭</li>
</ul>

<h3 id="s5-1">5.1 工作坊对话体验</h3>
<div class="callout callout-purple">
    <strong>核心特色</strong>：把原本枯燥的视频处理等待过程，变成一个有角色、有对话、有进度的<strong>沉浸式工作坊体验</strong>。用户能看到"工作室里正在发生什么"，降低感知等待时间。
</div>
<p>四个 AI 角色在右侧聊天面板中实时汇报进度：</p>
<ul>
    <li><strong>导演（林雨晨）</strong>：开场分工、统筹调度、最终验收</li>
    <li><strong>后期（陈默）</strong>：字幕/水印擦除进度</li>
    <li><strong>翻译（李明远）</strong>：语音识别、翻译进度</li>
    <li><strong>配音（苏雅）</strong>：配音合成进度</li>
</ul>
<p>每个角色下方有<strong>子任务卡片</strong>，逐条从"排队中"→"处理中"→"完成"，与真实处理进度完全同步。</p>
<p>左侧视频区域显示工作室背景视频，处理完成后自动切换到成片预览（关灯聚光效果）。</p>

<h3 id="s5-2">5.2 精调面板</h3>
<p>处理完成后（或从任务导入/二次编辑进入），可以对三个维度进行手动调整：</p>

<h4>擦除精调（Tab: 擦除）</h4>
<ul>
    <li>擦除区域列表（E1, E2...），每条显示时间范围 + 编辑/删除</li>
    <li>编辑态：单位选择（PX/百分比）、位置 XY、尺寸 WH、时间范围 → 取消/保存</li>
    <li>视频上方实时显示擦除区域框，支持 8 方向拖拽调整</li>
</ul>

<h4>字幕精调（Tab: 字幕）</h4>
<ul>
    <li>字幕设置区：源语言、目标语言、字幕样式下拉选择</li>
    <li>字幕列表（T1, T2...），每条显示时间范围 + 编辑/删除 → 原文 + 译文</li>
    <li>编辑态：时间范围、原文、译文输入框 → 取消/保存</li>
</ul>

<h4>配音精调（Tab: 配音）</h4>
<ul>
    <li>配音设置区：配音音色下拉选择</li>
    <li>配音列表（V1, V2...），每条显示时间范围 + 播放/编辑/删除 → 译文文本</li>
    <li>编辑态：时间范围、语速选择、译文输入、试听/重新生成 → 取消/保存</li>
</ul>

<!-- ===== 6 ===== -->
<h2 id="s6">6. 视频制作（AI 生成）</h2>

<h3>功能概述</h3>
<p>输入文字描述，系统自动拆分为多个分镜，调用 AIGC 模型逐段生成画面，合成完整视频。</p>

<h4>配置项</h4>
<ul>
    <li><strong>AI 模型</strong>：可灵 3.0-Omni / Vidu Q3-Pro / 海螺 2.3 / PixVerse V6 / 即梦 3.0 Pro / GV 3.1</li>
    <li><strong>清晰度</strong>：1080p / 720p / 2K / 4K</li>
    <li><strong>画面比例</strong>：16:9 / 9:16 / 1:1</li>
</ul>

<h3 id="s6-1">6.1 分镜工作坊</h3>
<p>同样是四角色协作的对话工作坊，但角色分工不同：</p>
<div class="flow">
    <span class="flow-step active">导演（林雨晨）开场</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">编剧（李明远）拆分镜</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">艺术指导（苏雅）生成画面</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">后期（陈默）剪辑合成</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step">精调</span>
</div>
<p>全流程以角色对话 + 子任务卡片展示在聊天面板中，与译制工作坊相同的交互范式。</p>

<h3 id="s6-2">6.2 分镜精调</h3>
<p>成片生成后进入精调：</p>
<ul>
    <li><strong>左上</strong>：当前分镜视频预览（canvas 播放器 + 进度条）</li>
    <li><strong>左下</strong>：时间轴（播放头 + 标尺 + 分镜色块首尾相接，点击切换）</li>
    <li><strong>右侧</strong>：分镜卡片列表</li>
</ul>

<h4>分镜卡片结构</h4>
<ul>
    <li>头行：F编号 | 片段名称 + 编辑/删除按钮</li>
    <li>内容区：分镜缩略图 + 画面描述文字</li>
    <li>编辑态：画面描述（textarea）+ 时长（数字选择器）→ 取消/重新生成</li>
</ul>
<p>顶部有"添加分镜"按钮，底部有"完成分镜精调"按钮。</p>

<!-- ===== 7 ===== -->
<h2 id="s7">7. 直播剪辑</h2>
<p>粘贴直播链接，系统实时监控直播流，自动识别高光时刻并生成精彩片段。</p>
<ul>
    <li><strong>类型选择</strong>：赛事 / 带货 / 游戏 / 知识 / 综艺</li>
    <li><strong>状态</strong>：待对接</li>
</ul>

<!-- ===== 8 ===== -->
<h2 id="s8">8. 精调统一视觉规范</h2>
<p>所有精调面板（擦除/字幕/配音/分镜）共享同一套视觉语言：</p>

<h3>布局</h3>
<ul>
    <li>三栏 Grid：左上视频预览 + 左下时间线 + 右侧编辑面板</li>
    <li>深色背景 + 点阵网格（24px 间距白色圆点）+ 鼠标跟随亮光</li>
    <li>三张黑色毛玻璃卡片（半透明深色 + 模糊 + 微弱白色边框 + 圆角）</li>
</ul>

<h3>卡片统一结构</h3>
<table>
    <tr><th>元素</th><th>规则</th></tr>
    <tr><td>头行</td><td>编号（E1/T1/V1/F1）+ 竖线 + 时间或名称 + 编辑/删除 icon</td></tr>
    <tr><td>内容区</td><td>分割线下方：擦除无内容、字幕显示双语、配音显示文本、分镜显示缩略图+描述</td></tr>
    <tr><td>编辑态</td><td>点击编辑展开，各模块不同字段 → 底部：取消（暗色胶囊）+ 保存（白色胶囊）</td></tr>
    <tr><td>时间线</td><td>控制栏 + 标尺 + 轨道色块 + 播放头</td></tr>
    <tr><td>完成按钮</td><td>右侧底部吸底，白底黑字圆角："完成 XX 精调"</td></tr>
</table>

<!-- ===== 9 ===== -->
<h2 id="s9">9. 产品特色</h2>

<div class="callout callout-green">
    Tideo 的核心差异不在于功能本身（擦除、翻译、配音都是 MPS 现有能力），而在于<strong>体验层</strong>的设计。
</div>

<h3>9.1 沉浸式工作坊 — 把等待变成体验</h3>
<p>传统媒体处理产品：提交任务 → 进度条/空白页 → 完成通知。用户在等待期间无事可做。</p>
<p>Tideo 的做法：把处理过程具象化为<strong>四人虚拟工作坊</strong>，用户看到角色在工作、对话、汇报进度。等待本身变成产品体验的一部分。</p>

<h3>9.2 统一的精调范式</h3>
<p>无论是擦除区域、字幕内容、配音参数还是分镜画面，都使用<strong>完全统一的视觉语言和交互模式</strong>（三栏布局 + 卡片列表 + 编辑态展开）。用户学会一种精调，就会用所有精调。</p>

<h3>9.3 对话式创作入口</h3>
<p>创作页不是传统的表单填写，而是<strong>对话式+卡片式</strong>的智能输入框。用户可以用自然语言描述需求，也可以点击技能卡片直接配置。降低上手门槛。</p>

<h3>9.4 多触点嵌入</h3>
<p>Tideo 不是孤立产品，而是嵌入在腾讯云控制台（MPS/VOD/云直播）的多个触点中。任务列表二次编辑、SaaS 工具菜单入口，用户在既有工作流中自然触达。</p>

<h3>9.5 一键复用角色 IP</h3>
<p>6 名角色各有姓名、性格、职责和台词体系。这套角色 IP 可以在译制、生成、剪辑等不同功能中复用，构建统一的产品人格。</p>

<!-- ===== 10 ===== -->
<h2 id="s10">10. 当前状态与规划</h2>

<h3>已完成</h3>
<ul>
    <li>影视译制全流程（上传 → 处理 → 精调 → 下载）</li>
    <li>视频制作 AI 生成流程（分镜编排 → 画面生成 → 合成 → 精调）</li>
    <li>四角色沉浸式工作坊（对话+子任务+实时进度）</li>
    <li>擦除/字幕/配音/分镜四套精调面板（统一视觉规范）</li>
    <li>创作页智能输入框（意图识别+技能配置+视频来源三路径）</li>
    <li>多任务状态持久化</li>
    <li>用户测试埋点 + 测试数据看板</li>
</ul>

<h3>待做</h3>
<ul>
    <li>直播剪辑功能对接</li>
    <li>AI 视频生成对接真实 AIGC 模型</li>
    <li>精调数据回写（重新提交处理）</li>
    <li>MPS/VOD 控制台二次编辑入口 + SaaS 工具菜单</li>
    <li>账号体系（SSO + 轻量登录）</li>
    <li>多语言支持扩展</li>
</ul>

<h3>产品规划</h3>
<table>
    <tr><th>阶段</th><th>内容</th><th>时间</th></tr>
    <tr><td><strong>首期 MVP</strong></td><td>视频译制跑通 + 体验设计 + 用户测试</td><td>2026.04</td></tr>
    <tr><td>首期完整版</td><td>三大功能全部对接</td><td>2026.05</td></tr>
    <tr><td>控制台嵌入</td><td>MPS/VOD 二次编辑 + SaaS 工具菜单</td><td>2026.05</td></tr>
    <tr><td>账号体系</td><td>轻量登录，SSO 对接腾讯云</td><td>2026.06</td></tr>
    <tr><td>能力扩充</td><td>持续引入更多音视频功能</td><td>持续</td></tr>
</table>

</div><!-- /prdContent -->

</div>

<div class="copy-hint" id="copyHint">已复制到剪贴板</div>

<script>
document.getElementById('copyBtn').addEventListener('click', function() {
    var content = document.getElementById('prdContent');
    var range = document.createRange();
    range.selectNodeContents(content);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    try {
        document.execCommand('copy');
        var hint = document.getElementById('copyHint');
        hint.classList.add('show');
        setTimeout(function() { hint.classList.remove('show'); }, 2000);
    } catch(e) {}
    sel.removeAllRanges();
});
</script>
</body>
</html>


path: assets/product-brief.html
content: <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tideo · 产品逻辑文档</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Text',sans-serif;background:#08080c;color:#e2e8f0;line-height:1.7}
.page{max-width:780px;margin:0 auto;padding:40px 24px 80px}
.back{display:inline-flex;align-items:center;gap:4px;font-size:.78rem;color:#64748b;text-decoration:none;margin-bottom:20px}
.back:hover{color:#94a3b8}
h1{font-size:1.5rem;font-weight:800;margin-bottom:4px}
.meta{font-size:.75rem;color:#475569;margin-bottom:32px}
h2{font-size:1.1rem;font-weight:700;margin:32px 0 12px;padding-top:20px;border-top:1px solid rgba(255,255,255,0.05)}
h3{font-size:.92rem;font-weight:600;margin:18px 0 8px;color:#cbd5e1}
p{font-size:.85rem;color:#94a3b8;margin-bottom:10px}
ul,ol{font-size:.85rem;color:#94a3b8;margin:0 0 12px 20px}
li{margin-bottom:4px}
strong{color:#e2e8f0}
code{background:rgba(255,255,255,0.08);padding:1px 6px;border-radius:4px;font-size:.78rem;color:#e2e8f0}
.callout{padding:14px 16px;border-radius:10px;margin:12px 0;font-size:.82rem}
.callout-blue{background:rgba(129,140,248,0.08);border-left:3px solid #818cf8;color:#cbd5e1}
.callout-green{background:rgba(16,185,129,0.08);border-left:3px solid #10b981;color:#cbd5e1}
.callout-yellow{background:rgba(245,158,11,0.08);border-left:3px solid #f59e0b;color:#cbd5e1}
table{width:100%;border-collapse:collapse;font-size:.8rem;margin:10px 0 16px}
th{text-align:left;padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.1);color:#64748b;font-weight:500}
td{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.03);color:#94a3b8}
.flow{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:10px 0 16px}
.flow-step{padding:6px 14px;border-radius:8px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.08);font-size:.78rem;color:#cbd5e1}
.flow-step.active{background:rgba(129,140,248,0.1);border-color:rgba(129,140,248,0.25);color:#818cf8}
.flow-arrow{color:#334155;font-size:.75rem}
</style>
</head>
<body>
<div class="page">

<a class="back" href="hub.html">← 返回产品中心</a>

<h1>Tideo 产品逻辑文档</h1>
<p class="meta">最后更新：2026-04-15 · 版本：visual1（视觉稿还原版）</p>

<!-- ===== 背景 ===== -->
<h2>为什么做这个产品</h2>
<div class="callout callout-blue">
    腾讯云旗下有<strong>云点播、云直播、媒体处理（MPS）</strong>等多个音视频产品，它们之间存在大量公用功能（字幕擦除、翻译、配音、剪辑等）。如果分别嵌入各个产品内部，开发成本高、功能冗杂。<br><br>
    因此决定做一个<strong>统一平台</strong>，把这些跨产品的能力集合在一起使用。
</div>

<p>立项有三个核心原因：</p>

<h3>1. 能力整合</h3>
<p>云点播、云直播、MPS 各自有视频处理能力，但分散在不同产品线。用户要用"视频译制"需要同时调 MPS 的擦除、翻译、配音三个接口，操作分散。Tideo 把它们整合成一键流程。</p>

<h3>2. 开箱即用</h3>
<p>中小企业和内容团队有直接使用这些能力的需求，但未必具备 API 对接的开发能力。Tideo 提供<strong>零代码、可视化</strong>的操作界面，上传视频就能用，不需要写一行代码。</p>

<h3>3. 简化账号管理</h3>
<p>腾讯云的账号体系需要多处授权（CAM 策略、服务角色、跨产品权限），流程繁琐。Tideo 用一套<strong>轻量账号体系</strong>统一管理，降低使用门槛。</p>

<h2>产品是什么</h2>
<div class="callout callout-blue">
    <strong>Tideo</strong> 是腾讯云音视频能力的轻量化统一平台 — 整合云点播、云直播、MPS 的公用功能，提供开箱即用的可视化操作界面。<br>
    首期聚焦三大核心功能：<strong>视频译制 · 视频生成 · 直播剪辑</strong>，后续持续扩充。
</div>

<h2>首期核心功能</h2>
<table>
    <tr><th>功能</th><th>能力来源</th><th>用户价值</th><th>状态</th></tr>
    <tr><td><strong>视频译制</strong></td><td>MPS 字幕擦除 + 翻译 + AI 配音</td><td>上传视频，自动输出多语言版本</td><td>✅ 已跑通</td></tr>
    <tr><td><strong>视频生成</strong></td><td>云点播 AI 生成能力</td><td>文字/图片生成视频内容</td><td>⏳ 待对接</td></tr>
    <tr><td><strong>直播剪辑</strong></td><td>云直播 + MPS EditMedia</td><td>直播流实时剪辑、精彩片段提取</td><td>⏳ 待对接</td></tr>
</table>

<h2>用户是谁</h2>
<ul>
    <li><strong>中小企业</strong> — 没有技术团队，无法自己对接 API，需要开箱即用的音视频处理工具</li>
    <li><strong>短剧出海团队</strong> — 中文短剧翻译成英语/日语/韩语发行海外，需要高效批量处理</li>
    <li><strong>内容创作者</strong> — 把视频翻译成多语言版本，扩大海外受众</li>
    <li><strong>企业市场部</strong> — 产品宣传片、培训视频的多语言本地化</li>
    <li><strong>直播运营团队</strong> — 需要快速从直播流中剪辑精彩片段分发</li>
</ul>

<h2>视频译制 — 核心流程</h2>
<p>首期已跑通的完整流程：</p>

<div class="flow">
    <span class="flow-step active">打开产品</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">上传视频</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">选择模式</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">等待处理</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">查看成片</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step">精调（可选）</span>
    <span class="flow-arrow">→</span>
    <span class="flow-step active">下载</span>
</div>

<h3>处理模式</h3>
<table>
    <tr><th>模式</th><th>包含能力</th><th>适用场景</th></tr>
    <tr><td><strong>完整模式</strong>（full）</td><td>字幕擦除 + 字幕翻译 + AI 配音</td><td>完整的视频本地化</td></tr>
    <tr><td>字幕擦除（erase）</td><td>仅擦除画面中的字幕和水印</td><td>清理画面</td></tr>
    <tr><td>字幕翻译（subtitle）</td><td>识别语音 + 翻译 + 字幕压制</td><td>只要字幕，不改配音</td></tr>
    <tr><td>配音（voice）</td><td>语音识别 + 翻译 + AI 克隆配音</td><td>只要换配音</td></tr>
</table>

<h3>详细步骤</h3>
<table>
    <tr><th>步骤</th><th>页面</th><th>用户做什么</th><th>系统做什么</th></tr>
    <tr><td>1. 进入</td><td>create.html</td><td>打开产品首页</td><td>展示功能卡片和智能输入框</td></tr>
    <tr><td>2. 选择功能</td><td>create.html</td><td>点「视频译制」或描述需求</td><td>识别意图，展示上传引导</td></tr>
    <tr><td>3. 上传视频</td><td>create.html</td><td>选择本地视频文件</td><td>上传到腾讯云 COS（显示进度）</td></tr>
    <tr><td>4. 提交任务</td><td>→ translate-v8</td><td>点发送，自动跳转</td><td>调用 MPS ProcessMedia API</td></tr>
    <tr><td>5. 等待处理</td><td>translate-v8</td><td>观看四角色对话进度</td><td>每5秒轮询 MPS 状态，驱动进度</td></tr>
    <tr><td>6. 查看成片</td><td>translate-v8</td><td>播放器自动切到成片</td><td>输出成片 URL + 下载按钮</td></tr>
    <tr><td>7. 下载</td><td>translate-v8</td><td>点下载按钮</td><td>直接下载 COS 成片文件</td></tr>
</table>

<h2>体验设计 — 产品核心差异</h2>

<div class="callout callout-blue">
    <strong>传统媒体处理产品的等待体验：</strong>提交任务 → 进度条/空白页 → 完成通知。用户在等待期间无事可做，只能离开页面。<br><br>
    <strong>Tideo 的做法：</strong>把原本无聊、不可视的媒体处理过程，变成一个<strong>可交互的游戏沙盘</strong>。用户在等待期间能看到"工作室里正在发生什么"，增加趣味性和参与感，降低感知等待时间。
</div>

<p>这是 Tideo 区别于所有同类产品的<strong>核心体验差异</strong>。</p>

<h3>四人虚拟工作坊</h3>
<p>处理过程被具象化为一间像素风工作室，四个 AI 角色各司其职：</p>

<table>
    <tr><th>角色</th><th>真名</th><th>职责</th><th>对应处理阶段</th></tr>
    <tr><td>🎬 导演</td><td>林雨晨</td><td>统筹分工、输出结果</td><td>任务调度 + 最终合成</td></tr>
    <tr><td>🎨 后期</td><td>陈默</td><td>画面处理</td><td>字幕/水印擦除</td></tr>
    <tr><td>📝 翻译</td><td>李明远</td><td>字幕识别和翻译</td><td>OCR/ASR + 翻译</td></tr>
    <tr><td>🎙️ 配音</td><td>苏雅</td><td>AI 克隆配音</td><td>配音合成</td></tr>
</table>

<h3>等待期间用户能看到什么</h3>
<ul>
    <li><strong>角色实时对话</strong> — 四个角色在聊天面板轮流汇报进度，有性格、有台词，不是机械的状态文字</li>
    <li><strong>进度卡片</strong> — 每个角色下方有子任务卡片，逐条从「排队中」→「处理中」→「完成」</li>
    <li><strong>像素工作室场景</strong> — 等距视角的工作室画面，角色在各自工位上忙碌</li>
    <li><strong>节奏同步</strong> — 所有视觉反馈与真实 MPS 处理进度完全同步，不是假动画</li>
</ul>

<h3>设计目标</h3>
<ul>
    <li>降低用户在处理等待期间的流失率</li>
    <li>让"等待"本身变成产品体验的一部分，而不是体验的断裂</li>
    <li>建立用户对 AI 处理过程的信任感（看得见每一步在做什么）</li>
</ul>

<h2>技术架构</h2>

<h3>前端</h3>
<ul>
    <li>纯 HTML/CSS/JS，无框架，轻量快速，托管在 GitHub Pages</li>
    <li>COS JS SDK 前端直传（不经过服务器）</li>
    <li><code>api-client.js</code> 封装所有 API 调用</li>
    <li><code>tracker.js</code> 全自动埋点（用户测试用）</li>
</ul>

<h3>后端</h3>
<ul>
    <li><strong>腾讯云 SCF 云函数</strong>（tideo-api）— 唯一的后端，约 150 行</li>
    <li>职责：API 签名代理（前端不暴露 SecretKey）</li>
    <li>路由：<code>/translate</code> · <code>/erase</code> · <code>/clip</code> · <code>/task/:id</code> · <code>/upload-credential</code> · <code>/track</code> · <code>/track-data</code></li>
</ul>

<h3>云服务依赖</h3>
<table>
    <tr><th>服务</th><th>用途</th></tr>
    <tr><td>腾讯云 MPS</td><td>视频处理引擎（擦除+翻译+配音）</td></tr>
    <tr><td>腾讯云 COS</td><td>视频/成片/埋点数据存储</td></tr>
    <tr><td>腾讯云 STS</td><td>生成临时上传凭证（前端安全直传）</td></tr>
    <tr><td>GitHub Pages</td><td>前端静态托管</td></tr>
</table>

<h3>数据流</h3>
<div class="callout callout-green">
用户选视频 → <strong>COS 直传</strong>（前端 → COS）<br>
→ 带 videoUrl 跳转到 translate-v8<br>
→ <strong>SCF 云函数</strong>调用 MPS ProcessMedia<br>
→ 前端每 5 秒轮询 <strong>DescribeTaskDetail</strong><br>
→ MPS 完成后成片写入 COS<br>
→ 前端拿到成片 URL，播放器 + 下载
</div>

<h2>当前状态</h2>

<div class="callout callout-yellow">
    <strong>2026-04-15 · visual1 版本 · 视觉稿还原阶段</strong>
</div>

<h3>已完成</h3>
<ul>
    <li>视频译制全流程真实可用（上传 → MPS 处理 → 成片下载）</li>
    <li>沉浸式四角色工作坊体验（对话进度与 MPS 同步）</li>
    <li>完整埋点系统（自动记录用户全操作路径）</li>
    <li>测试中心（生成链接 → 数据看板）</li>
    <li>产品中心/黄页</li>
    <li>项目时间线管理</li>
    <li>无 API 时自动降级为演示模式</li>
    <li>视觉稿还原版（visual1）：精调页点阵背景+毛玻璃、创作页配置栏重设计</li>
    <li>视频来源三路径弹窗（上传/导入任务/项目文件）</li>
    <li>精调直接入口模式（从任务导入/项目文件进入，跳过对话流）</li>
    <li>对话状态持久化（sessionStorage 多任务管理）</li>
    <li>全局去 emoji，统一 SVG icon</li>
    <li>字幕/配音精调面板重构（设置区+列表卡片式布局）</li>
</ul>

<h3>待做</h3>
<ul>
    <li>⏳ 直播剪辑对接 EditMedia API</li>
    <li>⏳ AI 视频生成对接</li>
    <li>⏳ 精调面板对接真实数据</li>
    <li>⏳ 多语言支持（目前只支持中→英）</li>
    <li>⏳ 轻量账号体系（替代腾讯云多处授权）</li>
    <li>⏳ 更多音视频能力持续扩充</li>
</ul>

<h2>产品规划</h2>
<table>
    <tr><th>阶段</th><th>内容</th><th>时间</th></tr>
    <tr><td><strong>首期 MVP</strong></td><td>视频译制跑通 + 体验设计 + 用户测试</td><td>2026.04</td></tr>
    <tr><td>首期完整版</td><td>三大功能全部对接（译制+生成+剪辑）</td><td>2026.05</td></tr>
    <tr><td>账号体系</td><td>轻量登录/注册，简化腾讯云授权流程</td><td>2026.05</td></tr>
    <tr><td>能力扩充</td><td>持续从云点播/云直播/MPS 引入更多公用功能</td><td>持续</td></tr>
</table>

<h2>版本演进</h2>
<table>
    <tr><th>时间</th><th>版本</th><th>里程碑</th></tr>
    <tr><td>2026-03</td><td>framex-app / av-saas</td><td>产品原型，基础页面结构</td></tr>
    <tr><td>2026-03</td><td>framex-studio</td><td>translate-v7，像素工作室场景</td></tr>
    <tr><td>2026-03-12</td><td>Tideo</td><td>品牌改名 FrameX → Tideo</td></tr>
    <tr><td>2026-03-20</td><td>model</td><td>仓库迁移，v7 视频 Loading 版</td></tr>
    <tr><td>2026-04</td><td>f1</td><td>translate-v8 沉浸式体验重设计</td></tr>
    <tr><td>2026-04-10</td><td>real1</td><td>真实 API 对接，MPS 译制跑通，埋点+测试系统</td></tr>
    <tr><td>2026-04-15</td><td><strong>visual1</strong></td><td>视觉稿还原版，精调页重设计，状态持久化，多路径来源弹窗</td></tr>
</table>

<h2>关键指标</h2>
<p>用户测试时重点关注：</p>
<table>
    <tr><th>指标</th><th>定义</th><th>健康值</th></tr>
    <tr><td>全流程完成率</td><td>从进入到拿到成片的用户比例</td><td>≥ 70%</td></tr>
    <tr><td>犹豫时间</td><td>进入页面到首次交互的时长</td><td>≤ 10 秒</td></tr>
    <tr><td>困惑操作</td><td>反复点同一个按钮 ≥3 次</td><td>0 次</td></tr>
    <tr><td>上传成功率</td><td>上传成功 / 上传尝试</td><td>≥ 95%</td></tr>
    <tr><td>处理中流失率</td><td>等待处理时离开的用户比例</td><td>≤ 20%</td></tr>
</table>

</div>
</body>
</html>


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)