Files
EPEEAIKit/.cursor/changelog/changelog-full.md

415 lines
35 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dev Changelog — Full
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
## 记录
### [CL-20260413-0800] 2026-04-13 08:00 — 修复 InstantStyle ReadTimeout + 多次生成丢失参考图
- **tags**: bug修复, Replicate, InstantStyle, timeout, 参考图, Agent Loop, wait, SDK
- **affected_files**:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/agent/loop.py
- **what**: 修复 InstantStyle 首次调用 ReadTimeout (61.4s) + 后续调用丢失参考图返回 "No input, Save money"
- **why**: 两个运行时日志证实的独立问题:(1) `wait=60` 时 SDK `_create_prediction_timeout` 生成 `httpx.Timeout(5.0, read=60.5)` 作为 per-request timeout 传给 `httpx.AsyncClient.request()`,优先级高于客户端级 300s timeout(2) 成功生成后执行 `ref_image_url = None`,但 LLM 可能在后续轮次继续调用工具,此时 InstantStyle 因没有 `style_image` 返回 "No input, Save money"
- **decisions**: (1) `wait=60``wait=False`:不发 `Prefer: wait` headercreate 请求立即返回 prediction IDSDK 自动进入 `prediction.async_wait()` 轮询路径。轮询请求不带 per-request timeout使用客户端级 `read=300s`。代价:比 `Prefer: wait` 模式多几秒轮询延迟,但绝不会 timeout。(2) 完全移除 `ref_image_url = None`:消息构建(附加参考图到 LLM 消息在外层循环前一次性完成不受影响。ref_image_url 只在 `execute_tool()` 中使用,整个对话期间都应该传递
- **notes**: 迭代了 CL-0700 和 CL-0730 的方案。wait 参数完整语义:`True` = `Prefer: wait` + read=60.5s`int(n)` = `Prefer: wait={n}` + read={n+0.5}sn 必须 1-60`False` = 不等待、纯轮询。对慢模型InstantStyle ~128s配合大 payload1.6MB base64`wait=False` 是唯一可靠选项
### [CL-20260413-0730] 2026-04-13 07:30 — 修复生图失败后 LLM 重试丢失参考图
- **tags**: bug修复, Agent Loop, 参考图, InstantStyle, ref_image_url
- **affected_files**:
- art-agent/backend/app/agent/loop.py
- **what**: 修复 LLM 第一次生图工具调用失败后重试时参考图丢失InstantStyle 返回 "No input, Save money"
- **why**: `loop.py` 在每轮工具调用循环结束后无条件执行 `ref_image_url = None`。当第一次调用超时失败后LLM 决定重试,但此时 ref_image_url 已被清空第二次工具调用没有参考图。InstantStyle 模型必须有 `style_image` 才能工作
- **decisions**: 改为条件性清除:在工具调用循环中标记 `tc_data["_had_images"] = True`,循环结束后检查是否有任何成功产出,只有 `any_success` 时才清除 ref_image_url。失败时保留参考图供后续重试
- **notes**: 这个改动对所有参考图模型生效Kolors、InstantStyle 等。只要本轮所有工具调用都失败了ref_image_url 会一直保留直到某次成功为止
### [CL-20260413-0700] 2026-04-13 07:00 — 修复 InstantStyle 生图 422 + ReadTimeoutwait 参数超限与 SDK 内部 timeout 覆盖
- **tags**: bug修复, Replicate, InstantStyle, API参数, async_run, Prefer header, timeout
- **affected_files**:
- art-agent/backend/app/services/image_gen.py
- **what**: 修复 InstantStyle 生图 422`Prefer: wait=x must be 1-60`)和后续 ReadTimeout61.4s 超时)
- **why**: 上次修超时时将 `async_run(wait=300)` 设为 300 秒。Replicate SDK 将 int 类型的 wait 值设为 `Prefer: wait=300` header → API 返回 422。改为 `wait=True` 后 SDK 生成内部 `httpx.Timeout(read=60.5)` 作为请求级 timeout 覆盖了客户端级 300s timeout → 上传 1.6MB base64 style_image + 等待响应超过 60s → ReadTimeout
- **decisions**: 最终改为 `wait=60`API 允许的最大 int 值。SDK 行为:(1) `Prefer: wait=60` header合法(2) 内部 timeout `read=60.5s` 用于初始 create prediction 请求;(3) 60s 内未完成自动 fallback 到 `prediction.async_wait()` 轮询;(4) 轮询请求用客户端级 `httpx.Timeout(read=300s)`
- **notes**: Replicate SDK wait 参数语义:`True` = `Prefer: wait` + read=60.5s`int(n)` = `Prefer: wait={n}` + read={n+0.5}sn 必须 1-60`False` = 不等待。对慢模型用 `wait=60` + 长客户端 timeout 是最优组合
### [CL-20260413-0630] 2026-04-13 06:30 — 修复 Replicate SDK 不走代理 + 超时:自定义 Client 注入代理和长超时
- **tags**: bug修复, Replicate, InstantStyle, 代理, httpx, 超时, 图像生成
- **affected_files**:
- art-agent/backend/app/services/image_gen.py
- **what**: 修复 InstantStyle 调用时 ConnectTimeout / ReadTimeout + "URL missing protocol" 连环错误
- **why**: Replicate Python SDK 的 `_build_httpx_client` 显式传入 `transport=AsyncHTTPTransport()`,导致 httpx 跳过环境变量中的 `HTTPS_PROXY` 代理配置直连 Replicate API。网络不稳定时直连超时SDK 内部状态异常导致后续请求报 "URL missing protocol"。同时默认 read timeout 30s 不够 InstantStyle 的 ~128s 生成时间
- **decisions**: 创建 `_make_replicate_client()` 工厂函数,从环境变量读取代理并注入到 `AsyncHTTPTransport(proxy=...)` 中传给 `ReplicateClient`。read timeout 300s、connect timeout 30s。`_download_image` 也加了代理和 60s 超时
- **notes**: Replicate SDK 的代理绕过是个已知设计缺陷(显式 transport 覆盖了 httpx 的代理自动检测)。此修复对所有通过 `_replicate_client` 的 Replicate API 调用生效。无代理环境下也兼容(`proxy=None` 时 httpx 不走代理)
### [CL-20260413-0600] 2026-04-13 06:00 — 新增 InstantStyle 模型:强风格迁移选项
- **tags**: 模型注册, InstantStyle, 风格迁移, IP-Adapter, 模型配置
- **affected_files**:
- art-agent/backend/app/config.py
- **what**: 在模型注册表中新增 InstantStyle`jyoung105/instant-style`),专门做风格分离迁移,与 Kolors IP-Adapter 并列为两个参考图模型选项
- **why**: Kolors IP-Adapter 的风格迁移弱(内容+风格+构图混合提取),经调研 InstantStyle 是 Replicate 上风格迁移能力最强的可用模型,能从参考图中分离出纯画风(线条、着色、色调)
- **decisions**: 利用现有 `supports_ref_image` + `ref_image_param` 抽象机制InstantStyle 的 `style_image` 参数名通过配置映射,无需修改 `_build_input` 逻辑。默认 `block_mode: "style-only"`(只迁移风格不迁移构图),`style_strength: 1.0`
- **notes**: InstantStyle 较贵(~$0.12/次)且慢(~128s适合风格定调阶段使用Kolors 保留为低成本快速测试选项。社区模型需版本 hash
### [CL-20260413-0540] 2026-04-13 05:40 — 非 vision LLM + 参考图时禁止猜测风格,避免 prompt 与参考图风格冲突
- **tags**: prompt 工程, IP-Adapter, 风格一致性, system prompt, 非vision模型
- **affected_files**:
- art-agent/backend/app/agent/loop.py
- **what**: 修改 system prompt 和非 vision 模型的参考图文字提示,明确要求 LLM 不要猜测/指定画风关键词,风格完全交给 IP-Adapter 从参考图提取
- **why**: DeepSeek 等非 vision LLM 看不到参考图内容,会根据"2D 游戏"等关键词脑补风格(如 pixel art导致 prompt 中的风格描述与参考图实际风格严重冲突。IP-Adapter 优先服从 prompt 的显式风格指令,参考图的风格影响被稀释
- **decisions**: 双重约束——system prompt 中加入"看不到参考图时不猜风格"的通用指引 + 注入的文字提示中用编号列表明确三条规则。保留了 vision 模型路径不变vision 模型能看图,可以写风格词)
- **notes**: 这是过渡方案,等切换到 vision LLM如 GPT-4oLLM 可直接看图描述风格,此约束自动失效(走 vision_capable 分支)
### [CL-20260413-0520] 2026-04-13 05:20 — 多图生成改为单次 API 调用 + 修复空错误信息
- **tags**: 性能优化, Replicate, 速率限制, 错误处理, 模型配置
- **affected_files**:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/config.py
- **what**: 多图生成从 for 循环多次 API 调用改为单次调用(利用模型原生批量参数),同时修复异常 str() 为空时的错误信息丢失
- **why**: LLM 传 num_images=3 时会发 3 个独立 API 请求在低余额账户的严格速率限制burst=1下后续请求会被 429 拦截。改为单次调用后只消耗 1 次请求配额。空错误信息(`[生成失败: ]`)导致用户无法诊断失败原因
- **decisions**: 新增 `num_images_param` 配置字段Flux 用 `num_outputs`Kolors 用 `number_of_images`),由 `_build_input` 统一注入。从 kolors 的 default_params 中移除了硬编码的 `number_of_images: 1`,改为动态设置
- **notes**: 空异常现在显示为 `{TypeName}: {repr(e)}`,确保始终有诊断信息
### [CL-20260413-0500] 2026-04-13 05:00 — 生成图片后显示使用的模型名称
- **tags**: 模型溯源, SSE, 图片生成, 前端展示
- **affected_files**:
- art-agent/backend/app/services/image_gen.py
- art-agent/backend/app/agent/tools.py
- art-agent/backend/app/agent/loop.py
- art-agent/frontend/src/lib/types.ts
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/components/chat/chat-messages.tsx
- **what**: 图片生成后在对话中显示实际使用的模型名称(如"由 Kolors IP-Adapter 生成"),失败时也附带模型名称
- **why**: 用户无法确认前端选择的模型是否真的被用于生图,特别是在多模型切换场景下需要明确溯源
- **decisions**: `generate_images` 返回值从 `list[str]` 改为 `GenerateResult` 数据类(包含 urls + model_name + model_id模型名称通过 SSE `image_result``tool_error` 事件透传到前端。ChatMessage 类型新增 `modelName` 可选字段,消息归档后仍可查看模型来源
- **notes**: 模型名称来自 config.py 注册表中的 `name` 字段,所以显示的是友好名称而非 Replicate 的 model_id
### [CL-20260413-0440] 2026-04-13 04:40 — 修复 Kolors IP-Adapter 模型 404 错误:补全 Replicate 版本 hash
- **tags**: bug修复, Replicate, Kolors, IP-Adapter, 模型配置
- **affected_files**:
- art-agent/backend/app/config.py
- **what**: 在 kolors-ipadapter 的 model_id 中补全版本 hash`fofr/kolors-with-ipadapter` 改为 `fofr/kolors-with-ipadapter:5a1a92b2...`
- **why**: Replicate SDK `async_run` 对非 official 模型(社区模型)只用 `owner/model` 格式调用时,会尝试 official model predictions 端点,该端点返回 404。必须使用 `owner/model:version_hash` 格式才能正确创建 prediction
- **decisions**: 只修复 kolors 模型唯一报错的其他三个模型flux-schnell、flux-dev、sdxl均为 official/热门模型,`owner/model` 格式能正常工作
- **notes**: 未来新增社区模型时,需确保 model_id 包含版本 hash。经实测加版本 hash 后生图成功
### [CL-20260413-0430] 2026-04-13 04:30 — 图片生成失败时将具体错误信息透传到前端
- **tags**: 错误处理, Agent Loop, SSE, 调试体验
- **affected_files**:
- art-agent/backend/app/agent/loop.py
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/lib/api.ts
- **what**: 新增 `tool_error` SSE 事件类型,将图片生成工具的具体错误信息(如 Replicate API 报错详情)直接透传到前端展示
- **why**: 之前工具调用失败时,错误信息只传回给 LLMLLM 会自行"翻译"错误(如说成"速率限制"),用户无法看到真实报错,排查困难。典型场景:使用 Kolors IP-Adapter 生图失败,前端只看到 LLM 的模糊描述,无法定位是参数错误、超时还是 API 限制
- **decisions**: 错误信息同时发给前端展示和 LLM 继续对话,不互斥。前端用 ⚠️ 前缀醒目显示错误详情
- **notes**: 此改动不影响 LLM 的重试机制(工具结果仍然回传给 LLM只是额外增加了一条面向用户的 SSE 事件
### [CL-20260413-0330] 2026-04-13 03:30 — README 补充访问地址汇总 + 穿透管理文档
- **tags**: 文档, README, 穿透, Cloudflare, cloudflared
- **affected_files**:
- art-agent/README.md (新增"访问地址"章节 + 重写"远程访问"章节)
- **what**: README 新增三种访问场景(本机/局域网/外网)的地址汇总表,重写远程访问章节补充 cloudflared 安装指引、穿透管理操作表、代理配置排错
- **why**: 原 README 远程访问章节过于简略,缺少 cloudflared 安装方式、穿透的启动/停止/排错说明,用户实际操作时需要这些信息
- **decisions**:
- 访问地址章节放在"使用"之后、"配置说明"之前,让用户启动后立即看到访问方式
- cloudflared 安装提供 winget 和手动下载两种方式winget 安装后可能不在 PATH 中)
- 穿透管理用表格呈现(启动/停止/查看状态/重启),简洁直观
- 代理排错放在注意事项中,因为国内环境常需代理才能连上 Cloudflare
- **notes**: 无
### [CL-20260412-2345] 2026-04-12 23:45 — 参考图上传独立化:进度条 + 状态反馈 + 失败重试
- **tags**: 前端, 后端, 参考图, 上传, UX, 进度反馈
- **affected_files**:
- art-agent/backend/app/api/chat.py (新增 POST /api/upload-ref-image 独立上传端点chat 端点新增 ref_image_url 字段)
- art-agent/frontend/src/lib/api.ts (新增 uploadRefImage 函数XMLHttpRequest 实现进度回调sendChat 参数从 File 改为服务端路径字符串)
- art-agent/frontend/src/components/chat/chat-input.tsx (重写上传流程选图即上传、环形进度条、状态角标、失败重试、input value 重置)
- art-agent/frontend/src/app/page.tsx (handleSend 适配新签名:接收服务端路径而非 File标注截图也走独立上传)
- **what**: 将参考图从"随消息一起提交"改为"选中后立即独立上传",全程有进度条、状态提示、失败重试入口
- **why**: 原方案图片上传绑定在发送消息时才执行,无任何进度反馈。大图或走 Cloudflare Tunnel 时用户完全无法判断上传是否开始、是否成功、是否卡住。多次上传参考图后 file input 不重置也导致交互异常
- **decisions**: 使用 XMLHttpRequest 而非 fetchfetch 不支持 upload progress 事件);后端同时保留 ref_image 文件上传和 ref_image_url 路径两种方式,向后兼容
- **notes**: 上传超时设为 120 秒;支持 AbortController 取消file input 每次选择后立即重置 value确保同一文件可重复选择
### [CL-20260412-2315] 2026-04-12 23:15 — 修复 Cloudflare Tunnel 跨域开发警告
- **tags**: 前端, 配置, Next.js, Cloudflare, 跨域
- **affected_files**:
- art-agent/frontend/next.config.ts (新增 allowedDevOrigins)
- **what**: 在 next.config.ts 中添加 `allowedDevOrigins: ["*.trycloudflare.com"]`,消除 Cloudflare Tunnel 穿透时的跨域警告
- **why**: Next.js 检测到来自 trycloudflare.com 的跨域请求,发出警告提示未来版本将强制要求配置
- **decisions**: 使用通配符 `*.trycloudflare.com` 覆盖所有 Quick Tunnel 随机域名
- **notes**: 仅影响开发模式,生产构建不受影响
### [CL-20260412-2300] 2026-04-12 23:00 — 集成 Kolors IP-Adapter 模型,参考图可直接用于风格生成
- **tags**: 后端, 前端, IP-Adapter, 风格迁移, 参考图, 模型注册, Replicate, 架构
- **affected_files**:
- art-agent/backend/app/config.py (新增 kolors-ipadapter 模型注册 + supports_ref_image / ref_image_param 通用字段)
- art-agent/backend/app/services/image_gen.py (ReplicateProvider._build_input 支持参考图注入 + to_data_uri 公共工具函数)
- art-agent/backend/app/agent/loop.py (复用 to_data_uri 替代原 _to_vision_url移除冗余 import)
- art-agent/frontend/src/lib/types.ts (ImageModelInfo 新增 supports_ref_image 字段)
- art-agent/frontend/src/components/chat/model-selector.tsx (模型列表中显示"参考图"标记)
- **what**: 集成 Kolors IP-Adapter 模型fofr/kolors-with-ipadapter参考图可真正参与图像生成的风格控制架构上为后续切换其他 IP-Adapter 模型预留了通用扩展机制
- **why**: 之前参考图仅由 LLM 侧理解(且 DeepSeek 看不到图),生图工具侧完全忽略了参考图。用户希望参考图能真正影响生成结果的风格
- **decisions**:
- 模型注册表新增两个通用字段supports_ref_image布尔标记和 ref_image_param参考图参数名不同模型可能不同
- _build_input 根据 supports_ref_image 自动走不同构建逻辑,新增 IP-Adapter 模型只需加注册表配置
- 参考图通过 base64 data URI 传递给 Replicate避免本地 URL 不可达的问题)
- to_data_uri 抽为 image_gen.py 中的公共函数loop.py 复用(替代原 _to_vision_url
- Kolors IP-Adapter 默认 ip_adapter_weight=0.8(非 1.0),给 prompt 文字留一些影响空间
- 前端模型列表中为支持参考图的模型显示绿色"参考图"徽章
- get_image_models_list 返回 supports_ref_image 字段,前端据此渲染标记
- **notes**:
- Kolors IP-Adapter 成本极低(~$0.004/次),速度快(~4s
- 后续要换其他 IP-Adapter 模型(如 Flux IP-Adapter v2只需在 IMAGE_MODELS 中新增配置
- 分层组合产线方案IP-Adapter → LoRA → ControlNet已记录为延期方案 [style-pipeline-layered]
### [CL-20260412-2230] 2026-04-12 22:30 — 用户消息气泡中显示参考图缩略图
- **tags**: 前端, 参考图, UX, chat-messages
- **affected_files**:
- art-agent/frontend/src/lib/types.ts (ChatMessage 新增 refImageUrl 字段)
- art-agent/frontend/src/app/page.tsx (构造 userMessage 时保存参考图 Blob URL)
- art-agent/frontend/src/components/chat/chat-messages.tsx (用户消息气泡中渲染参考图缩略图)
- **what**: 用户上传参考图发送后,在聊天气泡中显示参考图缩略图,让用户确认图片确实被附带发送了
- **why**: 之前用户上传参考图后,发送消息后气泡中看不到参考图,无法确认是否上传成功,体验不好
- **decisions**:
- 使用 URL.createObjectURL 创建 Blob URL 用于当前会话内显示(轻量、即时)
- Blob URL 不持久化到 localStorage刷新后失效避免存储 base64 data URI 的空间开销
- 参考图缩略图显示在消息文本上方,最大尺寸 160×120px
- **notes**:
- Blob URL 仅在当前标签页有效刷新页面后旧消息中的参考图缩略图不可见MVP 可接受)
- 如需持久化,后续可改为存储后端上传路径(需要等后端返回 upload URL 后再构造 userMessage
### [CL-20260412-2200] 2026-04-12 22:00 — 修复 DeepSeek 不支持 image_url 导致参考图上传报错
- **tags**: bug修复, 后端, Agent Loop, vision, DeepSeek, 多模态
- **affected_files**:
- art-agent/backend/app/agent/loop.py (新增 vision 能力检测,非 vision 模型走文字提示)
- **what**: 修复使用 DeepSeek 作为 LLM 时,上传参考图后报 400 错误 `unknown variant 'image_url', expected 'text'`
- **why**: 代码原本假设所有 LLM 都支持 OpenAI Vision API 的 `image_url` content type但 DeepSeek 的 Chat API 只支持 `text` 类型
- **decisions**:
- 通过模型名称关键词检测 vision 能力gpt-4o / gpt-4-vision / claude 视为支持)
- 不支持 vision 的模型:用文字提示告知 LLM 有参考图存在,参考图仍由图像生成工具侧处理
- 支持 vision 的模型:保持原有 image_url 格式不变
- **notes**:
- 此方案确保参考图功能在任何 LLM 下都不会报错
- 非 vision 模型无法"看到"参考图,但生图工具仍会收到参考图用于 img2img 场景
- 如需更精确的 vision 能力检测,可后续改为在 config.py 中按模型注册 vision 标志
### [CL-20260412-2130] 2026-04-12 21:30 — 修复图片生成失败时前端显示破碎图标
- **tags**: bug修复, 前端, 后端, 图像生成, 错误处理
- **affected_files**:
- art-agent/backend/app/agent/tools.py (分离有效 URL 和错误信息)
- art-agent/frontend/src/app/page.tsx (过滤无效 URL空列表时不渲染图片网格)
- **what**: 修复 Replicate API 失败时前端出现 4 个破碎图标框的问题
- **why**: 用户在 Replicate 余额不足402时生图错误字符串被当作图片 URL 传给 `<img>` 标签
- **decisions**:
- 后端 tools.py将 generate_images 返回值分为 images有效 URL和 errors错误信息两个字段
- 前端 page.tsx过滤以 `[` 开头的无效 URL无有效图片时直接 break 不创建 ImageAsset
- **notes**:
- 根因是 Replicate 账户余额不足,需用户到 https://replicate.com/account/billing#billing 充值
- 此修复确保任何 API 错误场景下前端都不会显示破碎图标
### [CL-20260412-2100] 2026-04-12 21:00 — 生图模型动态切换Provider 抽象 + 前端模型选择器
- **tags**: 后端, 前端, 图像生成, 模型切换, Provider, 重构, Replicate
- **affected_files**:
- art-agent/backend/app/config.py (新增 IMAGE_MODELS 注册表 + get_image_model_config / get_image_models_list / get_default_image_model_id)
- art-agent/backend/app/services/image_gen.py (重构ImageProvider 抽象基类 + ReplicateProvider 实现 + generate_images 接受 model_id)
- art-agent/backend/app/api/chat.py (新增 GET /api/models 端点 + POST /api/chat 增加 image_model 参数)
- art-agent/backend/app/agent/loop.py (run_agent_loop 增加 image_model 参数透传)
- art-agent/backend/app/agent/tools.py (execute_tool 增加 image_model 参数透传)
- art-agent/backend/.env (IMAGE_MODEL 改为短 ID 格式)
- art-agent/backend/.env.example (同步更新)
- art-agent/frontend/src/lib/types.ts (新增 ImageModelInfo 类型)
- art-agent/frontend/src/lib/api.ts (新增 fetchModels() + sendChat 增加 imageModel 参数)
- art-agent/frontend/src/components/chat/model-selector.tsx (新建:模型选择下拉组件)
- art-agent/frontend/src/components/chat/chat-input.tsx (集成 ModelSelector + onSend 签名扩展)
- art-agent/frontend/src/app/page.tsx (handleSend 透传 imageModel 到 sendChat)
- **what**: 将图像生成服务从 Replicate 硬绑定重构为 Provider 抽象架构,支持 Replicate 上多模型flux-schnell / flux-dev / SDXL按消息粒度切换
- **why**: 用户希望能在对话中随时切换生图模型来对比不同模型的效果
- **decisions**:
- Provider 模式:抽象基类 ImageProvider + 具体实现(当前只有 ReplicateProvider预留 DalleProvider/ComfyUIProvider 等扩展点
- 模型注册表放在 config.py 中Python dict新增模型只需加一条配置
- 前端模型列表由后端 API 驱动GET /api/models不在前端硬编码
- 切换粒度为每条消息级(最灵活),通过 FormData 传递 image_model 参数
- 模型选择持久化到 localStorage作为后续消息的默认值
- Flux 系列使用 aspect_ratio 参数SDXL 使用 width/height 参数,由 ReplicateProvider._build_input 内部分流处理
- **notes**:
- 向后兼容image_model 参数可选,不传时使用 .env 中的默认模型
- .env 中 IMAGE_MODEL 支持短 IDflux-schnell和完整 Replicate IDblack-forest-labs/flux-schnell自动转换
### [CL-20260412-1800] 2026-04-12 18:00 — 移动端适配 + Cloudflare Tunnel 内网穿透
- **tags**: 前端, 响应式, 移动端, 部署, Cloudflare, 穿透, 配置
- **affected_files**:
- art-agent/frontend/src/app/layout.tsx (viewport meta 配置)
- art-agent/frontend/src/app/globals.css (iOS bounce 防护、tap highlight、dvh 支持、遮罩动画)
- art-agent/frontend/src/app/page.tsx (桌面端展开按钮加 hidden md:flex)
- art-agent/frontend/src/app/gallery/page.tsx (网格 gap/列数适配、hover 操作移动端始终可见、选择框可见)
- art-agent/frontend/src/components/sidebar/sidebar.tsx (移动端固定定位抽屉 + 遮罩)
- art-agent/frontend/src/components/layout/top-nav.tsx (新增汉堡菜单按钮、间距微调)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (移动端全屏 overlay)
- art-agent/frontend/src/components/chat/chat-messages.tsx (气泡宽度 90%、间距收紧)
- art-agent/frontend/src/components/chat/chat-input.tsx (padding 收紧)
- art-agent/frontend/src/components/chat/image-grid.tsx (max-width 适配、操作栏移动端可见)
- art-agent/frontend/src/lib/app-context.tsx (小屏默认折叠侧边栏、切换会话自动收起)
- art-agent/frontend/next.config.ts (trycloudflare.com + replicate.delivery 白名单)
- art-agent/start-tunnel.ps1 (新建:一键穿透脚本)
- art-agent/README.md (新增远程访问章节、uvicorn 加 --host 0.0.0.0)
- **what**: 为实现手机浏览器远程访问完成移动端响应式适配9 个组件)和 Cloudflare Quick Tunnel 穿透方案
- **why**: 用户希望把项目发给自己和朋友在手机上通过浏览器使用
- **decisions**:
- 移动端断点统一用 `md:` (768px),与 Tailwind 默认保持一致
- 侧边栏移动端用 fixed + overlay 抽屉模式,桌面端保持原有 w-0/w-[280px] 切换
- 图片详情面板移动端全屏fixed inset-0不做半屏因为手机屏幕空间有限
- 穿透方案选 Cloudflare Quick Tunnel免费、免注册不选 ngrok有连接限制
- 穿透脚本自动管理 .env.local 的更新和恢复,减少手动操作
- hover 操作在移动端始终显示(无 hover 事件),避免操作不可达
- 路线 B云服务器正式部署记录为延期方案待后续实施
- **notes**:
- 构建验证通过,无 lint 错误
- cloudflared 通过 winget 安装,版本 2025.8.1
- Quick Tunnel 每次启动分配随机域名xxx.trycloudflare.com非固定
- 穿透启动后需重启前端才能读取新的 NEXT_PUBLIC_API_URL
- project-launcher Skill 中的 uvicorn 命令也同步加了 --host 0.0.0.0
### [CL-20260412-1530] 2026-04-12 15:30 — 修复 .env 配置加载时序问题
- **tags**: 后端, bug修复, 配置, dotenv, Python
- **affected_files**:
- art-agent/backend/app/main.py (load_dotenv 前置 + override=True)
- art-agent/backend/app/config.py (模块级常量 → 函数式懒读取)
- art-agent/backend/app/agent/loop.py (引用改为函数调用)
- art-agent/backend/app/services/image_gen.py (引用改为函数调用)
- art-agent/backend/.env (OPENAI_BASE_URL 去掉 /v1)
- **what**: 修复切换 DeepSeek API 后报 "Model Not Exist" 400 错误
- **why**: 用户修改 .env 切换到 DeepSeek但实际发出的请求仍使用默认模型名 gpt-4o-mini
- **decisions**:
- load_dotenv(override=True) 放在 main.py 所有业务 import 之前,确保环境变量在任何模块读取前就位
- config.py 从模块级常量改为函数get_llm_model() 等),避免 import 时求值被固化
- 不使用 lru_cache避免首次调用在 load_dotenv 前就缓存了空值)
- **notes**:
- 根因有两层import 时序config.py 在 load_dotenv 前被 import+ override 默认行为(不覆盖已有环境变量)
- 通过在 uvicorn 同环境中运行 Python 脚本成功复现了 API 调通,证明问题在进程内加载顺序而非 API 本身
- DeepSeek base_url 使用 https://api.deepseek.com不带 /v1与官方文档一致
### [CL-20260412-1500] 2026-04-12 15:00 — 品牌重命名 EPEEKit + API 配置集中化
- **tags**: EPEEKit, 品牌, 配置, 后端, 前端, 重构
- **affected_files**:
- art-agent/frontend/src/app/layout.tsx (title/description)
- art-agent/frontend/src/components/layout/top-nav.tsx (Logo SVG + 品牌名)
- art-agent/frontend/src/app/page.tsx (欢迎文案)
- art-agent/frontend/src/lib/store.ts (localStorage 键名)
- art-agent/frontend/src/app/gallery/page.tsx (下载前缀)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (下载前缀)
- art-agent/frontend/src/components/chat/image-grid.tsx (下载前缀)
- art-agent/frontend/package.json (项目名)
- art-agent/frontend/package-lock.json (项目名)
- art-agent/backend/app/main.py (FastAPI title)
- art-agent/backend/app/config.py (新建:集中配置)
- art-agent/backend/app/agent/loop.py (引用集中配置)
- art-agent/backend/app/services/image_gen.py (引用集中配置 + 简化重复分支)
- art-agent/backend/.env (重组为分组结构 + 新增 LLM_MODEL/IMAGE_MODEL 等)
- art-agent/backend/.env.example (新建)
- art-agent/README.md (全文更新)
- **what**: 将应用从 "Art Agent" 正式命名为 "EPEEKit",同时将后端所有硬编码的 API/模型配置抽取到 .env 文件,通过 config.py 集中管理
- **why**: 用户要求正式命名应用并希望能方便地切换 LLM 和图像生成模型进行测试
- **decisions**:
- 品牌名全部统一为 "EPEEKit"包括页面标题、Logo、下载文件名、localStorage 键名
- Logo 采用内联 SVG 设计(主题色圆角方块 + A/i 组合),不引入外部图片资源
- API 配置走 .env + config.py 方案(非 settings.py 类模式),保持极简
- 切换 LLM 只需改 .env 中 3 个值OPENAI_BASE_URL + OPENAI_API_KEY + LLM_MODEL
- image_gen.py 中去除了参考图分支的重复代码(两个分支逻辑完全相同)
- **notes**:
- localStorage 键名变更意味着旧数据不会自动迁移MVP 阶段可接受)
- .env 文件中含真实密钥,需确认 .gitignore 覆盖
### [CL-20260412-0300] 2026-04-12 03:00 — 完成交互原型全面重构
- **tags**: art-agent, 前端, 交互设计, 三栏布局, 标签系统, Canvas标注, 资源库, 后端
- **affected_files**:
- art-agent/frontend/src/app/page.tsx (重写)
- art-agent/frontend/src/app/layout.tsx (添加 AppProvider)
- art-agent/frontend/src/app/globals.css (增加样式)
- art-agent/frontend/src/app/gallery/page.tsx (新建)
- art-agent/frontend/src/lib/types.ts (新建:全局类型定义)
- art-agent/frontend/src/lib/store.ts (新建localStorage 持久化存储)
- art-agent/frontend/src/lib/app-context.tsx (新建:全局状态 Context)
- art-agent/frontend/src/lib/api.ts (更新类型兼容)
- art-agent/frontend/src/components/layout/top-nav.tsx (新建)
- art-agent/frontend/src/components/sidebar/sidebar.tsx (新建)
- art-agent/frontend/src/components/sidebar/session-list.tsx (新建)
- art-agent/frontend/src/components/sidebar/tag-filter.tsx (新建)
- art-agent/frontend/src/components/chat/chat-messages.tsx (适配新类型)
- art-agent/frontend/src/components/chat/chat-input.tsx (增加拖拽上传)
- art-agent/frontend/src/components/chat/image-grid.tsx (增加操作栏)
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (新建)
- art-agent/frontend/src/components/detail/annotation-canvas.tsx (新建)
- art-agent/backend/app/agent/loop.py (System Prompt + base64 转换)
- **what**: 从单页对话 MVP 全面重构为完整交互原型,三个 Phase 一次性完成
- **why**: 用户要求完整设计交互原型,通过规划讨论确定了三栏布局 + 标签系统 + 标注 + 资源库的完整方案
- **decisions**:
- 数据持久化使用 localStorageMVP 阶段),后续可迁移到后端数据库
- 全局状态管理使用 React Context + useReducer 模式,不引入第三方状态库
- 标注功能使用原生 Canvas API不引入第三方画板库减少依赖
- 标注坐标使用归一化比例0-1与图片实际分辨率解耦
- 资源库使用 Modal overlay 展示详情,而非独立路由页面
- 标注截图通过 base64 data URI 直接传给 OpenAI Vision后端自动处理本地路径转换
- **notes**:
- 新增 12 个源文件,修改 6 个现有文件,无新依赖引入
- 内置标签 6 个UI、Icon、原画、风格探索、立绘、概念图
- 标注工具 4 种:矩形框选、箭头、自由画笔、文字,含撤销/清除
- 构建验证通过,无 linter 错误
- 未来可优化:标签自动推荐逻辑(当前仅预留接口)、后端会话持久化、图片搜索索引
### [CL-20260411-1500] 2026-04-11 15:00 — 完成美术 Agent 产品决策和技术选型
- **tags**: art-agent, 产品决策, 技术选型, 规划
- **affected_files**:
- docs/art-agent/DECISIONS.md
- docs/art-agent/TECH-STACK.md
- **what**: 通过 5 轮结构化讨论确定了美术 Agent 工具的产品决策产品形态、交互模型、AI 架构、风格管理、资源 Pipeline并完成全部 8 个维度的技术选型
- **why**: 项目从零开始,需要先把产品方向和技术基准定下来再动手写代码
- **decisions**:
- 产品形态选 Chat-first Web App排除纯 Bot 和桌面应用)
- 前端 Next.js / 后端 Python FastAPI / 自建 Agent Loop不用 LangChain
- 数据库 PostgreSQL / 图像生成 Replicate / 部署 Vercel + Railway
- 对象存储 MVP 先用本地文件系统
- **notes**: 技术选型中图像生成 API、部署方案、异步任务三项用户未明确选定采用了推荐方案
### [CL-20260411-1600] 2026-04-11 16:00 — 搭建美术 Agent MVP 全部前后端代码
- **tags**: art-agent, MVP, 前端, 后端, FastAPI, Next.js, Agent Loop
- **affected_files**:
- art-agent/README.md
- art-agent/backend/requirements.txt
- art-agent/backend/.env.example
- art-agent/backend/app/main.py
- art-agent/backend/app/api/chat.py
- art-agent/backend/app/agent/loop.py
- art-agent/backend/app/agent/tools.py
- art-agent/backend/app/services/image_gen.py
- art-agent/frontend/package.json
- art-agent/frontend/src/app/page.tsx
- art-agent/frontend/src/app/layout.tsx
- art-agent/frontend/src/app/globals.css
- art-agent/frontend/src/components/chat/chat-messages.tsx
- art-agent/frontend/src/components/chat/chat-input.tsx
- art-agent/frontend/src/components/chat/image-grid.tsx
- art-agent/frontend/src/lib/api.ts
- docs/art-agent/MVP-PLAN.md
- **what**: 从零创建了完整的 MVP 前后端代码,包括 FastAPI 后端Agent Loop + Replicate 图像生成 + SSE 流式推送)和 Next.js 前端Chat UI + 参考图上传 + 图片下载),后端已验证可正常启动
- **why**: 以最小流程跑通端到端闭环(对话 → 生图 → 迭代 → 保存),快速暴露集成问题
- **decisions**:
- MVP 范围刻意砍掉:数据库/持久化、Skill/Rules 机制、风格库、用户认证、云端部署
- Agent Loop 硬编码 system prompt不走 Skill 扩展(最简化)
- 图像模型选 flux-schnell快速版优先验证流程通畅
- OpenAI 客户端延迟初始化,避免无 Key 时模块加载失败
- **notes**:
- 前端使用 Tailwind CSS v4 + PostCSS 配置方式(非 tailwind.config.ts
- 参考图在 MVP 阶段仅通过 GPT vision 理解风格后融入 prompt未直接传给图像模型做 img2img
### [CL-20260411-1630] 2026-04-11 16:30 — 完成开发环境搭建和依赖安装
- **tags**: art-agent, 环境搭建, Node.js, Python
- **affected_files**:
- art-agent/backend/venv/
- art-agent/frontend/node_modules/
- **what**: 通过 winget 安装 Node.js v24.14.1,创建 Python 虚拟环境并安装后端依赖9 个包),安装前端 npm 依赖46 个包),后端启动验证通过
- **why**: 代码写好后需要实际运行环境来验证
- **decisions**:
- Node.js 用 winget 安装 LTS 版本
- Python 虚拟环境放在 backend/venv/ 下
- **notes**:
- 遇到 3 个环境问题已解决OpenAI 延迟初始化、PowerShell 不支持 &&、脚本执行策略限制
- 端到端完整测试待用户配置 API Key 后进行