Files
cmshoppe/docs/troubleshooting.md
T

13 KiB
Raw Blame History

常见问题排查

本文只记录可复用的本地排障步骤。T-538 后用户数据默认位于 data/,涉及 data/config.json、data/data/config/ai_models.json、data/config/cmhub.json、data/cmshopee.db、data/chrome_user_data_dir/、data/images/ 时,默认它们是本机敏感或业务数据,必须保持 gitignore,不把真实密码、API Key、Cookie、token 写入文档、日志或提交。

启动时报 “AI 模型 category 必须是 text 或 image”

现象

运行 python main.py / python -m app 启动 GUI 时,弹出或输出:

AI 模型 category 必须是 text 或 image

原因

data/data/config/ai_models.json 是本地 AI 模型清单,里面每个模型都必须有合法的 category:

  • text:标题生成模型,会出现在“标题大模型”下拉。
  • image:封面生成模型,会出现在“图片大模型”下拉。

早期或手工维护过的 data/data/config/ai_models.json 可能缺少 category,或者填了中文、空值、旧字段,导致 appconfig.load_ai_models_config() 严格校验失败,GUI 启动被阻断。

不要这样做

  • 不要删除 data/data/config/ai_models.json 来“重置”,否则会丢失本地明文 API Key 和模型配置。
  • 不要把 data/data/config/ai_models.json 提交到 git。
  • 不要把完整文件内容贴到聊天、文档或日志里;该文件含本地明文 API Key。

推荐修复

先只查看非敏感字段,确认哪些模型缺少 category:

python -c "import json; p='data/config/ai_models.json'; data=json.load(open(p,encoding='utf-8')); [print({'index': i+1, 'name': m.get('name'), 'category': m.get('category'), 'api_type': m.get('api_type'), 'enabled': m.get('enabled'), 'has_api_key': bool(m.get('api_key'))}) for i,m in enumerate(data.get('models', []))]"

然后手工编辑 data/data/config/ai_models.json,只补这些字段:

{
  "name": "示例文本模型",
  "category": "text",
  "enabled": true
}
{
  "name": "示例图片模型",
  "category": "image",
  "enabled": true
}

如果要用脚本批量修复,只按模型名或 api_type 推断 category,并保留原有 url、model、api_key、extra_body 等字段。示例:

python -c "import json; p='data/config/ai_models.json'; data=json.load(open(p,encoding='utf-8')); mapping={'你的文本模型名':'text','你的图片模型名':'image'}; changed=False
for m in data.get('models', []):
    name=m.get('name')
    if not m.get('category') and name in mapping:
        m['category']=mapping[name]; changed=True
    if m.get('enabled') is None:
        m['enabled']=True; changed=True
open(p,'w',encoding='utf-8').write(json.dumps(data,ensure_ascii=False,indent=2)+'\n')
print('updated' if changed else 'unchanged')"

验证

验证时只输出模型名、类别、是否启用、是否存在 Key,不输出 Key 本身:

python -c "import os,sys; sys.path.insert(0, os.getcwd()); from app import appconfig; print([(m['name'], m['category'], m['enabled'], m['api_key_set']) for m in appconfig.list_ai_models()])"

确认 data/data/config/ai_models.json 仍被忽略:

git status --short --ignored data/config/ai_models.json

正常输出应包含:

!! data/config/ai_models.json

最后重新启动:

python main.py

⑤ 设置里测试连接提示 “HTTP 404”

现象

在⑤设置里填写文本大模型信息后,点击「测试连接」,结果显示:

HTTP 404

原因

HTTP 404 表示服务端已响应,但当前请求 URL 路径不存在。旧代码会把「网址」字段原样作为 POST 地址;如果只填 OpenAI-compatible base URL,例如:

https://api.vectorengine.ai/v1

程序会直接 POST 到 /v1,部分服务商会返回 404。当前代码已兼容 base URL:

  • api_type=chat 或 auto:/v1、/api/v1 会自动补成 /chat/completions。
  • api_type=images_edits:/v1、/api/v1 会自动补成 /images/edits。
  • 已经填写完整 endpoint(如 /v1/chat/completions)时保持不变。

推荐修复

更新到包含该修复的代码后,保留当前配置即可;也可以手工把「网址」改成完整 endpoint:

https://api.vectorengine.ai/v1/chat/completions

如果仍然 404,优先检查服务商文档要求的 endpoint 路径和 api_type,不要把 data/data/config/ai_models.json 或 API Key 贴到日志、文档或聊天里。

非敏感检查

只输出非密钥字段确认 URL 形态:

python -c "import json; from urllib.parse import urlsplit,urlunsplit; p='data/config/ai_models.json'; data=json.load(open(p,encoding='utf-8')); [print({'name':m.get('name'),'category':m.get('category'),'api_type':m.get('api_type'),'url_without_query':urlunsplit((urlsplit(m.get('url','')).scheme,urlsplit(m.get('url','')).netloc,urlsplit(m.get('url','')).path,'','')),'has_api_key':bool(m.get('api_key'))}) for m in data.get('models', [])]"

⑤ cmhub「刷新别名 / 测试连接」提示 notfound / 404

现象

在⑤设置切到 cmhub 后端,手动填入 Base URL、API Key,点「刷新别名」或「测试连接」,提示 notfound(即 HTTP 404)。

原因

先明确:cmshopee 的请求本身是达标的——GET {Base URL}/api/v1/models,头 Authorization: Bearer <key>,与对接文档《cmhub-接口对接文档-桌面端生文生图》§4.4 和 cmhub 服务端路由 path("v1/models", ModelsView) 完全一致。404 表示服务端已响应但该路径不存在,原因在请求之外,通常是两类:

  1. Base URL 填了多余路径(手动填入最常见):Base URL 只能填网关根,例如 https://cmhub.example.com。T-530 后程序会在保存和请求前规整 Base URL,填成 https://host/api/v1 也会按 https://host 拼出 https://host/api/v1/models;仍建议只填网关根,便于人工排查。
  2. 连的那台 cmhub 实例没有该路由:ModelsView 在 cmhub 仓库代码里有,但运行中的实例若未重新部署/重启,/api/v1/models(较新接口)会 404,而 /api/v1/balance(较老接口)可能正常。

隔离方法(一条 curl 定位)

curl -i "https://<你的BaseURL>/api/v1/models"  -H "Authorization: Bearer sk_cmhub_xxx"
curl -i "https://<你的BaseURL>/api/v1/balance" -H "Authorization: Bearer sk_cmhub_xxx"
  • 两个都 404 → Base URL 填错,改成网关根(不带 /api、/api/v1)。
  • balance 通、models 404 → cmhub 实例未更新,让部署方重启/重部署带上 ModelsView。
  • models 通 → cmshopee 侧别的问题,回代码排查。

不要把 API Key 贴进日志、文档或聊天;curl 里的 sk_cmhub_xxx 是占位。

当前处理(T-530 后)

T-530 已实现:保存和请求前都会把 Base URL 规整为网关根,去掉多余路径、查询串和片段;HTTP 404 会映射为 not_found,显示“cmhub 接口不存在,请检查 Base URL 或该实例是否已部署 /api/v1/models”,不再透传 notfound 这类生涩原文。

②AI生成提示“当前筛选结果没有可生成任务”

现象

在②AI生成模块选中某个批次,列表里看到多条“失败”记录,点击「开始生成」后,状态栏提示:

当前筛选结果没有待生成或生成失败可重试任务;请先在①导入采集完成旧数据采集

旧版本可能提示:

当前筛选结果没有可生成任务

原因

②AI生成只能处理两类任务:

  • 已完成①采集的待生成任务:底层通常是 stage=collected。
  • AI 生成阶段失败、可以重试的任务:例如生成标题或生成封面失败。

如果列表里的“失败”其实是①采集失败,任务还停在 stage=imported/status=failed,没有旧标题和旧封面,②无法直接生成。2026-07-06 的实测问题就是这种情况:本地最新批次 5 条任务都是 stage=imported/status=failed/collect_attempts>0/generate_attempts=0,属于采集失败,不是 AI 生成失败。

如果失败来自③更新shopee,任务通常已有新标题/新封面,但这是更新阶段失败,也不应回到②自动重新生成。

当前处理

当前代码已把②AI生成列表的失败状态细分为:

  • 采集失败:需要先回①重新采集旧标题/旧封面。
  • 生成失败:可以在②当前筛选范围内再次点击「开始生成」重试。
  • 更新失败:应去③更新shopee重试或重置更新状态,不会被②误当成生成任务。

②「开始生成」使用统一的 ai.is_generatable_task() 判断可生成范围,GUI、Worker 和底层 generate_batch() 口径一致。

推荐处理

  1. 如果②状态列显示“采集失败”:回到①导入采集,确认对应账号 Chrome 已启动且已登录,再重新采集旧标题/旧封面。
  2. 如果②状态列显示“生成失败”:留在②,确认 cmhub Base URL、API Key、别名和点数正常后,直接点击「开始生成」重试当前筛选结果。
  3. 如果②状态列显示“更新失败”:到③更新shopee处理;需要重复更新时使用③的重置更新状态入口,不要在②重新生成。

排查时不要把 data/cmshopee.db、data/config/cmhub.json、data/data/config/ai_models.json 或任何 API Key、密码、Cookie 发到聊天、文档或提交里。

AI生成:标题成功但图片生成失败,且看不到原因

当前代码会为 ② AI生成写两层日志:

  • 页面右下「AI生成运行日志」显示最近一次 run_type=generate 的逐条事件,例如 phase=cover step=cover_request result=failed detail=...。
  • 本地 data/logs/cmshopee.log 保存脱敏后的 traceback、任务 id、alias、item_id、phase 和 step,用于判断卡在模型配置、封面请求、图片解析、保存文件还是写库。

排查顺序:先看 ② 页面运行日志里的 phase / step / detail;如果只看到简短错误,再查看本地 data/logs/cmshopee.log。不要把 data/data/config/ai_models.json 或 API Key 发到聊天、文档或提交里。

④启动登录重复打开 Chrome

现象:在④账号管理中选中同一个账号,第一次点击「启动登录」会打开该账号 Chrome;不关闭该 Chrome 的情况下再次点击「启动登录」,旧版本会再打开一个 Chrome 窗口,而不是复用已打开的账号窗口创建/激活 tab。

旧原因:原代码路径是 AccountsTab.launch_login() → accounts.launch_for_login() → chrome.launch_chrome() → subprocess.Popen(),每次点击都会直接启动进程;已有的 chrome.is_running(debug_port) 没有接入启动入口,login_statuses[alias]="已启动" 也只是界面状态,不会阻止下一次点击。

已修复:T-105b 已把④「启动登录」改成幂等流程。先检查该账号 debug_port 是否已有 CDP 响应;已响应时不再 Popen,而是复用现有 Chrome/CDP 并打开或激活 https://<region_host>/portal/ 登录/卖家中心 tab;未响应时才新启动 Chrome。该修复不自动登录、不填密码、不绕过验证码,也不改变①/③预检“不自动启动 Chrome”的规则。

验证方式:同一账号第一次点击「启动登录」应显示“Chrome 已启动,请人工登录”;保持该账号 Chrome 不关闭,再点一次应显示“该账号 Chrome 已打开,已复用现有窗口”,且不会新增 Chrome 进程。

打包版窗口左上角显示不全,标题栏不可拖动

现象

在 Windows 10 虚拟机或小分辨率环境运行打包后的 dist/cmshopee/cmshopee.exe / release 包后,主窗口出现在屏幕左上角,左边和标题栏显示不全,看不到「蝦皮圈優化助手」标题,导致无法用鼠标拖动窗口到中间。

原因

旧逻辑只设置固定窗口大小:

self.resize(1180, 760)

没有按当前屏幕可用区域限制初始尺寸、居中显示,也没有保证窗口标题栏完整落在屏幕内。虚拟机、小分辨率、高 DPI、任务栏占用较多或多显示器切换环境下更容易暴露该问题;PyInstaller 打包不是根因。

临时处理

如果已经遇到窗口无法拖动:

  1. 按 Alt + Space。
  2. 按 M 选择移动。
  3. 用方向键把窗口移回屏幕中间,再按回车。

也可以尝试 Win + 方向键 贴靠/恢复窗口,或先调高虚拟机分辨率。

当前修复(T-541 后)

T-541 已在主窗口启动时读取 QApplication.primaryScreen().availableGeometry():

  • 大屏保持接近 1180x760。
  • 小屏自动缩小到可用区域内。
  • resize() 后按可用区域居中 move()。
  • 确保窗口左上角不小于可用区域左上角,标题栏完整可见、可拖动。
  • 不保存坏的历史窗口坐标,避免下次继续打开到屏幕外。

修复后需要在普通桌面和 Windows 10 虚拟机/小分辨率环境各启动一次打包版,确认标题栏完整可见。