From b12e55a776928a0c29bbe55661ad9f6247a3d43c Mon Sep 17 00:00:00 2001 From: Nostars Developer Date: Fri, 17 Apr 2026 19:30:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A4=E4=BA=92=E5=8E=9F=E5=9E=8B=E5=A4=A7?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/changelog/changelog-full.md | 41 ++ .cursor/changelog/changelog-headlines.md | 19 +- .cursor/changelog/changelog-recent.md | 10 + .cursor/skills/dev-changelog/SKILL.md | 4 +- .cursor/skills/epee-orchestrator/registry.md | 2 +- .gitignore | 2 + .../frontend/src/app/characters/[id]/page.tsx | 511 ++++++++++++++++++ .../frontend/src/app/characters/page.tsx | 217 ++++++++ art-agent/frontend/src/app/gallery/page.tsx | 139 ++++- art-agent/frontend/src/app/globals.css | 46 ++ art-agent/frontend/src/app/page.tsx | 49 ++ art-agent/frontend/src/app/settings/page.tsx | 308 +++++++++++ .../frontend/src/app/styles/[id]/page.tsx | 464 ++++++++++++++++ art-agent/frontend/src/app/styles/page.tsx | 251 +++++++++ .../frontend/src/app/training/[id]/page.tsx | 347 ++++++++++++ .../frontend/src/app/training/new/page.tsx | 353 ++++++++++++ art-agent/frontend/src/app/training/page.tsx | 186 +++++++ .../components/chat/session-quick-picks.tsx | 257 +++++++++ .../src/components/chat/task-card.tsx | 108 ++++ .../components/layout/project-switcher.tsx | 165 ++++++ .../src/components/layout/top-nav.tsx | 138 ++++- .../src/components/sidebar/project-card.tsx | 104 ++++ .../src/components/sidebar/sidebar.tsx | 2 + .../workbench/advanced-controls.tsx | 131 +++++ .../components/workbench/candidate-panel.tsx | 110 ++++ art-agent/frontend/src/lib/app-context.tsx | 152 +++++- .../frontend/src/lib/placeholder-store.ts | 347 ++++++++++++ art-agent/frontend/src/lib/types.ts | 136 +++++ art-agent/start-tunnel.ps1 | 32 +- 29 files changed, 4574 insertions(+), 57 deletions(-) create mode 100644 art-agent/frontend/src/app/characters/[id]/page.tsx create mode 100644 art-agent/frontend/src/app/characters/page.tsx create mode 100644 art-agent/frontend/src/app/settings/page.tsx create mode 100644 art-agent/frontend/src/app/styles/[id]/page.tsx create mode 100644 art-agent/frontend/src/app/styles/page.tsx create mode 100644 art-agent/frontend/src/app/training/[id]/page.tsx create mode 100644 art-agent/frontend/src/app/training/new/page.tsx create mode 100644 art-agent/frontend/src/app/training/page.tsx create mode 100644 art-agent/frontend/src/components/chat/session-quick-picks.tsx create mode 100644 art-agent/frontend/src/components/chat/task-card.tsx create mode 100644 art-agent/frontend/src/components/layout/project-switcher.tsx create mode 100644 art-agent/frontend/src/components/sidebar/project-card.tsx create mode 100644 art-agent/frontend/src/components/workbench/advanced-controls.tsx create mode 100644 art-agent/frontend/src/components/workbench/candidate-panel.tsx create mode 100644 art-agent/frontend/src/lib/placeholder-store.ts diff --git a/.cursor/changelog/changelog-full.md b/.cursor/changelog/changelog-full.md index 6e64801..8e84bca 100644 --- a/.cursor/changelog/changelog-full.md +++ b/.cursor/changelog/changelog-full.md @@ -4,6 +4,47 @@ ## 记录 +### [CL-20260417-1510] 2026-04-17 15:10 — Cloudflare Quick Tunnel 脚本修复(PS5.1 编码 + 本地 cloudflared) +- **tags**: 内网穿透, cloudflared, PowerShell, start-tunnel, UTF-8, gitignore +- **affected_files**: + - art-agent/start-tunnel.ps1 + - .gitignore +- **what**: 修复 `start-tunnel.ps1` 在 Windows PowerShell 5.1 下因脚本 UTF-8 无 BOM、含中文的 here-string(`@"`)被误解析而导致的 `ParserError`。将写入 `frontend/.env.local` 的两处 here-string 改为 `[System.IO.File]::WriteAllLines` + UTF-8 无 BOM(与 Next 读取 `.env` 习惯一致)。用 PowerShell 将脚本全文重写为 **UTF-8 BOM**,便于 PS5.1 正确分词。在脚本开头增加:若存在与脚本同目录的 `cloudflared.exe`,则把该目录插入 `PATH` 最前,便于未全局安装 cloudflared 时使用本地下载的可执行文件。根目录 `.gitignore` 增加 `art-agent/cloudflared.exe`,避免误提交约 65MB 二进制。 +- **why**: 用户请求开启穿透时,脚本在 Cursor 集成终端中立即解析失败,隧道无法拉起;当前环境亦未必安装 winget/系统 PATH 中的 cloudflared,需要可放置于项目目录的 fallback。 +- **decisions**: 不改为仅英文输出(保留原有中文提示与框线字符);`.env.local` 注释改为英文短句以避免无 BOM 环境下再次出现字符串边界问题。 +- **notes**: 会话中曾从 GitHub latest release 下载 `cloudflared-windows-amd64.exe` 至 `art-agent/cloudflared.exe` 并成功启动双隧道;该文件已被 gitignore。 + +### [CL-20260417-1500] 2026-04-17 15:00 — 按 INFOLAYER.md 实现完整前端信息架构(Phase 1+ 占位骨架) +- **tags**: 前端, UI骨架, INFOLAYER, 多项目, 风格库, 角色库, 训练中心, 项目设置, TaskCard, 候选评估, 占位数据 +- **affected_files**: + - art-agent/frontend/src/lib/types.ts + - art-agent/frontend/src/lib/placeholder-store.ts + - art-agent/frontend/src/lib/app-context.tsx + - art-agent/frontend/src/app/globals.css + - art-agent/frontend/src/app/page.tsx + - art-agent/frontend/src/app/gallery/page.tsx + - art-agent/frontend/src/app/styles/page.tsx + - art-agent/frontend/src/app/styles/[id]/page.tsx + - art-agent/frontend/src/app/characters/page.tsx + - art-agent/frontend/src/app/characters/[id]/page.tsx + - art-agent/frontend/src/app/training/page.tsx + - art-agent/frontend/src/app/training/[id]/page.tsx + - art-agent/frontend/src/app/training/new/page.tsx + - art-agent/frontend/src/app/settings/page.tsx + - art-agent/frontend/src/components/layout/top-nav.tsx + - art-agent/frontend/src/components/layout/project-switcher.tsx + - art-agent/frontend/src/components/sidebar/sidebar.tsx + - art-agent/frontend/src/components/sidebar/project-card.tsx + - art-agent/frontend/src/components/chat/session-quick-picks.tsx + - art-agent/frontend/src/components/chat/task-card.tsx + - art-agent/frontend/src/components/workbench/advanced-controls.tsx + - art-agent/frontend/src/components/workbench/candidate-panel.tsx +- **what**: 按 `docs/art-agent/INFOLAYER.md` 规范一次性铺开 Phase 1–3 产品形态的前端 UI 骨架:新增风格库 `/styles`、角色库 `/characters`、训练中心 `/training`、项目设置 `/settings` 四大页面模块(含列表 + 详情 + 创建流程);工作台输入区上方加入风格/角色/资产规格快选条、高级控制抽屉、候选评估侧面板、Task Card IR 占位组件;资源库新增资产类型/风格/角色多维过滤和语义搜索切换;TopNav 扩充导航项与项目切换器,Sidebar 加入项目信息卡;新增 `lib/placeholder-store.ts` 管理 Phase 1+ 占位数据(项目/风格集/角色卡/训练任务)并在 `app-context.tsx` 中统一暴露;`globals.css` 补充 `phase-chip` / `placeholder-card` / `hide-scrollbar` / `section-divider` 工具类。 +- **why**: INFOLAYER.md 规划了 Phase 0–3 完整产品形态,其中 Phase 1+(多项目、风格库/角色库、训练中心、Task Card、候选评估等)尚未具备后端能力。用户希望先把完整交互结构和界面落地,"数据或展示上写占位"即可,方便内部演示、收集反馈以及后续按 Phase 增量接入真实后端。 +- **decisions**: (1) 占位数据用独立的 `placeholder-store.ts` + `localStorage` 持久化,与现有 `store.ts` 解耦,首次加载注入示例数据(2 个项目 / 4 个风格集 / 2 个角色 / 4 个训练任务)。(2) 详情页直接用 `[id]/page.tsx` 同时处理 `new` 与编辑两种模式(判断 `params.id === 'new'`),不再新增 `/styles/new` 等专用子路由。(3) Task Card 作为独立可复用组件 (`components/chat/task-card.tsx`),不强制接入当前 chat loop,等真实 IR 管线就绪时再 wire up。(4) 候选评估面板从"最后一条含 images 的 assistant 消息"取数据做 demo。(5) Gallery 风格/角色过滤用 prompt 关键词子串匹配做占位,未来等后端补 asset 归因字段后再切到真实字段。(6) 所有 Phase 1+ 功能按钮均挂 `phase-chip`(P1/P2/P3)明示阶段,避免用户误以为已可用。 +- **notes**: 所有"应用到会话""Fork""训练""批量下载"等交互都是 `alert("(占位)...")`,不产生真实后端调用;真实接入时搜索 `(占位)` 或 `phase-chip` 可快速定位需要替换的位置。`AppContext` 新增字段:`projects` / `activeProjectId` / `stylePacks` / `characters` / `trainingTasks` / `sessionStyleId` / `sessionCharacterId` / `sessionAssetSpec` 及对应 upsert/delete 方法;切换用户时会重新加载全部占位数据。`/styles/[id]` 和 `/characters/[id]` 的"生成图片"列表也是基于关键词从现有 assets 里筛的占位结果,不是真正的归因。`ChatMessage` 未扩展,Task Card 目前仅以组件形式存在,实际渲染位置需要后续决定(工作台消息流或独立抽屉)。 +- **source_chat**: [实现 INFOLAYER 完整 UI 骨架](607b2d99-ff5b-48a6-91b5-1ada004cd8d5) + ### [CL-20260416-1600] 2026-04-16 16:00 — 视觉风格从暗绿底全面转为白底青绿(绢本山水) - **tags**: 前端, 视觉风格, 色彩体系, CSS变量, 白底, 千里江山图 - **affected_files**: diff --git a/.cursor/changelog/changelog-headlines.md b/.cursor/changelog/changelog-headlines.md index a94d596..4d566d8 100644 --- a/.cursor/changelog/changelog-headlines.md +++ b/.cursor/changelog/changelog-headlines.md @@ -2,6 +2,8 @@ 最近 ~50 次改动的一句话概要,按时间倒序排列。每次会话自动注入上下文。 +- [CL-20260417-1510] start-tunnel.ps1 修复 PS5.1 中文 here-string 解析失败:WriteAllLines 写 .env、脚本 UTF-8 BOM、同目录 cloudflared.exe 优先;根 .gitignore 忽略下载的 cloudflared.exe +- [CL-20260417-1500] 按 INFOLAYER.md 一次性铺开 Phase 1+ 前端 UI 骨架:新增风格库/角色库/训练中心/项目设置四大页面模块+工作台快选条+高级控制+候选评估+Task Card+资源库多维过滤,placeholder-store.ts 管理占位数据,phase-chip 标注阶段 - [CL-20260416-1600] 视觉风格从暗绿底全面转为白底青绿(绢本山水):背景#FAFAF7+文字#1A1A1A+accent#2E8B7A,13个文件颜色替换,面板改白色毛玻璃,云雾透明度降低,VISUAL-STYLE-GUIDE.md重写 - [CL-20260416-1500] UX风格指南实现度补全:涟漪/sendBounce/会话切换动画/Error飘散/云雾加载/流式opacity/排版类使用/左上切角/石青占位等10项全部落地,文档每项标注✅状态+实现文件 - [CL-20260416-1330] 交互体验全面升级:新增framer-motion动画引擎,7级排版体系+4级Surface层级+网格底纹科技感,萤火粒子/数据流光/水墨晕染/投石入水/云雾凝聚/萤火点亮等微交互,用户/助手消息视觉拉开差距,统一Loading/空态/Error状态,全组件hover浮起+侧栏竖线+呼吸脉冲,新增UX-STYLE-GUIDE.md文档 @@ -50,20 +52,3 @@ - [CL-20260413-0540] 非 vision LLM + 参考图时禁止猜测风格,prompt 只描述内容不写画风,风格交由 IP-Adapter 处理 - [CL-20260413-0520] 多图生成改为单次 API 调用(利用模型原生批量参数),避免速率限制 + 修复空错误信息显示 - [CL-20260413-0500] 图片生成后在对话中显示实际使用的模型名称(如"由 Kolors IP-Adapter 生成"),便于模型溯源 -- [CL-20260413-0440] 修复 Kolors IP-Adapter 404 错误:社区模型需 `owner/model:version_hash` 格式,补全版本 hash 后生图成功 -- [CL-20260413-0430] 图片生成失败时将具体错误信息(Replicate API 报错等)透传到前端展示,新增 tool_error SSE 事件 -- [CL-20260413-0330] README 补充访问地址汇总(本机/局域网/外网)+ 穿透管理文档(安装/启停/排错) -- [CL-20260412-2345] 参考图上传独立化:选图即上传 + 环形进度条 + 成功/失败状态反馈 + 失败重试,后端新增独立上传端点 -- [CL-20260412-2315] 修复 Cloudflare Tunnel 跨域开发警告:next.config.ts 新增 allowedDevOrigins 通配符 -- [CL-20260412-2300] 集成 Kolors IP-Adapter 模型:参考图可直接用于风格生成,模型注册表新增通用参考图支持机制 -- [CL-20260412-2230] 用户消息气泡中显示参考图缩略图:ChatMessage 新增 refImageUrl,发送后在气泡中渲染参考图 -- [CL-20260412-2200] 修复 DeepSeek 不支持 image_url 参考图上传报错:新增 vision 能力检测,非 vision 模型走文字提示 -- [CL-20260412-2130] 修复图片生成失败时前端显示破碎图标:后端分离错误信息与有效 URL,前端过滤无效 URL 不渲染空图片 -- [CL-20260412-2100] 生图模型动态切换:Provider 抽象架构 + 前端模型选择器 + Replicate 多模型(flux-schnell/flux-dev/SDXL)按消息粒度切换 -- [CL-20260412-1800] 移动端适配 + Cloudflare Tunnel 内网穿透:响应式布局改造(9 个组件)+ 一键穿透脚本 + cloudflared 安装 -- [CL-20260412-1530] 修复 .env 配置加载时序问题:load_dotenv 前置 + override=True + config.py 改函数式懒读取 -- [CL-20260412-1500] 品牌重命名 Art Agent → EPEEKit + 后端 API/模型配置集中化到 .env + config.py -- [CL-20260412-0300] 完成交互原型全面重构:三栏布局 + 多会话标签系统 + Canvas 标注 + 资源库页面 -- [CL-20260411-1630] 安装 Node.js v24.14.1 + Python venv + 前后端依赖,后端启动验证通过 -- [CL-20260411-1600] 从零创建美术 Agent MVP 全部前后端代码(FastAPI + Next.js + Agent Loop + SSE) -- [CL-20260411-1500] 完成美术 Agent 产品决策(5 个核心问题)和技术选型(8 个维度)两份文档 diff --git a/.cursor/changelog/changelog-recent.md b/.cursor/changelog/changelog-recent.md index f7dc98c..0074918 100644 --- a/.cursor/changelog/changelog-recent.md +++ b/.cursor/changelog/changelog-recent.md @@ -3,6 +3,16 @@ 最近 ~10 次改动的摘要记录,按时间倒序排列。 当 Agent 检测到当前任务与近期改动相关时自动读取。 +### [CL-20260417-1510] 2026-04-17 — Cloudflare 穿透脚本兼容 PS5.1 + 本地 cloudflared +- **tags**: 内网穿透, cloudflared, PowerShell, start-tunnel, env +- **affected_files**: art-agent/start-tunnel.ps1, .gitignore +- **summary**: Windows PowerShell 5.1 在 UTF-8 无 BOM 下解析含中文的 `@"` here-string 会报错,导致穿透脚本无法运行。改为用 `WriteAllLines` 写入 `frontend/.env.local`,并将脚本保存为 UTF-8 BOM。脚本启动时若存在 `art-agent/cloudflared.exe` 则自动加入 PATH 优先使用。根目录 `.gitignore` 忽略本地下载的 `cloudflared.exe`(体积大)。 + +### [CL-20260417-1500] 2026-04-17 — 按 INFOLAYER.md 实现完整前端信息架构(Phase 1+ 占位骨架) +- **tags**: 前端, UI骨架, INFOLAYER, 多项目, 风格库, 角色库, 训练中心, 项目设置, TaskCard, 候选评估, 占位数据 +- **affected_files**: types.ts, placeholder-store.ts, app-context.tsx, globals.css, app/page.tsx, app/gallery/page.tsx, app/styles/*, app/characters/*, app/training/*, app/settings/page.tsx, top-nav.tsx, project-switcher.tsx, project-card.tsx, session-quick-picks.tsx, task-card.tsx, advanced-controls.tsx, candidate-panel.tsx, sidebar.tsx +- **summary**: 一次性铺开 INFOLAYER.md Phase 1–3 完整 UI 骨架:新增 /styles /characters /training /settings 四大模块(列表+详情+创建流程),工作台加入风格/角色/规格快选条、高级控制抽屉、候选评估面板、Task Card 组件,资源库加二级过滤(资产类型/风格/角色)+ 语义搜索切换;TopNav 加项目切换器和新导航项;Sidebar 加项目信息卡。所有 Phase 1+ 数据通过新建的 placeholder-store.ts + localStorage 占位持久化(首次注入示例),AppContext 扩充相关字段。所有真实后端行为均为 `alert("(占位)...")`,UI 上以 phase-chip(P1/P2/P3)明示阶段。搜索"(占位)"可快速定位待接入点。 + ### [CL-20260416-1600] 2026-04-16 — 视觉风格从暗绿底全面转为白底青绿(绢本山水) - **tags**: 前端, 视觉风格, 色彩体系, CSS变量, 白底, 千里江山图 - **affected_files**: globals.css, page.tsx, login/page.tsx, gallery/page.tsx, chat-messages.tsx, chat-input.tsx, top-nav.tsx, sidebar.tsx, session-list.tsx, profile-modal.tsx, image-detail-panel.tsx, ambient-particles.tsx, VISUAL-STYLE-GUIDE.md diff --git a/.cursor/skills/dev-changelog/SKILL.md b/.cursor/skills/dev-changelog/SKILL.md index 20f538f..2375bcd 100644 --- a/.cursor/skills/dev-changelog/SKILL.md +++ b/.cursor/skills/dev-changelog/SKILL.md @@ -83,7 +83,7 @@ Agent 完成了一个涉及**代码或配置文件实质性改动**的任务后 4. 写入三个文件(按以下顺序): a. 读取 changelog-full.md,在 "## 记录" 下方追加 L1 条目 - b. 读取 changelog-recent.md,在顶部插入 L2 条目,如超过 10 条则移除最旧的 + b. 读取 changelog-recent.md,在顶部插入 L2 条目,如超过 20 条则移除最旧的(与下方「L2 窗口」一致) c. 读取 changelog-headlines.md,在顶部插入 L3 条目,如超过 50 条则移除最旧的 5. 在回复末尾附一行提示:"[已记录到开发日志]" @@ -247,3 +247,5 @@ Agent 完成了一个涉及**代码或配置文件实质性改动**的任务后 ### 已知必要检查 1. **大任务收尾遗漏风险** — 当单次任务涉及 5+ 个文件改动时,Agent 容易在输出总结回复后遗漏被动写入流程。应在生成最终回复前,先执行 `changelog-recall.mdc` 中的"任务完成 Checklist",确认三层日志已写入后再输出回复。绝不能"先回复再补写"。 + +2. **L3/L2 滚动窗口必须落地** — 操作 A 第 4 步不是「插入即结束」:写入后必须数清条目(L3 为以 `- [` 开头的列表行,L2 为 `### [CL-` 标题行)。L3 超过 50 条、L2 超过 20 条时,必须从**文件底部(最旧)**整段删除条目直至恰好满足上限;禁止长期只追加不修剪。若发现 `changelog-headlines.md` 列表行多于 50,说明上次写入未执行本项,本次补修剪并自检。 diff --git a/.cursor/skills/epee-orchestrator/registry.md b/.cursor/skills/epee-orchestrator/registry.md index bba1e5e..3753334 100644 --- a/.cursor/skills/epee-orchestrator/registry.md +++ b/.cursor/skills/epee-orchestrator/registry.md @@ -39,7 +39,7 @@ - **触发场景**: "开发日志"、"changelog"、"最近改了什么"、"回顾改动"、"查看开发记录"、代码改动后自动写入 - **输出**: .cursor/changelog/ 下的 changelog-full.md、changelog-recent.md、changelog-headlines.md - **路径**: .cursor/skills/dev-changelog/SKILL.md -- **备注**: 写入由 changelog-recall Rule 的"任务完成 Checklist"触发(原被动写入提醒已升级为强制 checklist);L3 概要每次会话自动注入上下文;stop Hook 双保险兜底 +- **备注**: 写入由 changelog-recall Rule 的"任务完成 Checklist"触发(原被动写入提醒已升级为强制 checklist);L3 概要每次会话自动注入上下文;stop Hook 双保险兜底;写入后须维护 L3≤50 / L2≤20 滚动窗口(见 Skill 自迭代检查项) ### pitfall-journal - **类型**: 基础设施 diff --git a/.gitignore b/.gitignore index 62027a9..03a70d4 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ out/ art-agent/backend/uploads/ art-agent/backend/generated/ art-agent/backend/data/ +# 本地下载的 cloudflared CLI(体积大,见 README / start-tunnel.ps1) +art-agent/cloudflared.exe # ─── 工具二进制 ────────────────────────────────────────── *.exe diff --git a/art-agent/frontend/src/app/characters/[id]/page.tsx b/art-agent/frontend/src/app/characters/[id]/page.tsx new file mode 100644 index 0000000..13e764e --- /dev/null +++ b/art-agent/frontend/src/app/characters/[id]/page.tsx @@ -0,0 +1,511 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useParams, useRouter } from "next/navigation"; +import Link from "next/link"; +import { TopNav } from "@/components/layout/top-nav"; +import { AmbientParticles } from "@/components/ui/ambient-particles"; +import { useApp } from "@/lib/app-context"; +import type { CharacterCard, CharacterRefImage } from "@/lib/types"; + +const ANGLES = [ + "正面", + "半侧面", + "侧面", + "背面", + "半身", + "全身", + "表情·微笑", + "表情·愤怒", + "表情·惊讶", + "服饰细节", +]; + +export default function CharacterDetailPage() { + const params = useParams<{ id: string }>(); + const router = useRouter(); + const isNew = params.id === "new"; + const { + characters, + upsertCharacter, + deleteCharacter, + setSessionCharacterId, + projects, + activeProjectId, + assets, + } = useApp(); + + const [c, setC] = useState(null); + + useEffect(() => { + if (isNew) { + const now = Date.now(); + setC({ + id: `char-${now.toString(36)}`, + name: "", + description: "", + personality: [], + visualHooks: [], + consistency: "medium", + refImages: [], + projectId: activeProjectId, + createdAt: now, + updatedAt: now, + }); + } else { + const found = characters.find((x) => x.id === params.id); + if (found) setC(found); + } + }, [params.id, characters, isNew, activeProjectId]); + + if (!c) { + return ( +
+ +
+

加载中...

+
+
+ ); + } + + const handleSave = () => { + if (!c.name.trim()) { + alert("请填写角色名称"); + return; + } + upsertCharacter(c); + alert("已保存(占位)"); + if (isNew) router.push(`/characters/${c.id}`); + }; + + const handleApply = () => { + setSessionCharacterId(c.id); + alert(`已将角色 "${c.name}" 应用到当前会话(占位)`); + router.push("/"); + }; + + const handleDelete = () => { + if (!confirm(`确认删除角色 "${c.name}"?`)) return; + deleteCharacter(c.id); + router.push("/characters"); + }; + + const addRef = (angle: string) => { + setC({ + ...c, + refImages: [ + ...c.refImages, + { id: `r-${Date.now()}`, url: "", angle, caption: "占位参考图" }, + ], + }); + }; + + const removeRef = (id: string) => { + setC({ ...c, refImages: c.refImages.filter((r) => r.id !== id) }); + }; + + const addPersonality = (kw: string) => { + if (!kw || c.personality.includes(kw)) return; + setC({ ...c, personality: [...c.personality, kw] }); + }; + + const addHook = (kw: string) => { + if (!kw || c.visualHooks.includes(kw)) return; + setC({ ...c, visualHooks: [...c.visualHooks, kw] }); + }; + + const relatedAssets = assets + .filter((a) => + c.visualHooks.some((h) => a.prompt.toLowerCase().includes(h.toLowerCase())) || + a.prompt.toLowerCase().includes(c.name.toLowerCase()) + ) + .slice(0, 6); + + return ( +
+ + + +
+
+
+ + 角色库 + + / + + {isNew ? "新建角色" : c.name || "未命名"} + +
+ +
+
+
+ setC({ ...c, name: e.target.value })} + placeholder="角色名称" + className="text-2xl font-bold bg-transparent border-none + text-[var(--text-primary)] placeholder:text-[var(--text-secondary)]/60 + focus:outline-none flex-1" + /> + Phase 1 +
+
+
+ + + {!isNew && ( + <> + + 训练角色 LoRA + P2 + + + + )} +
+
+ +
+
+ {/* 基本信息 */} +
+

基本信息

+