T-583 标题提示词模板数据层
This commit is contained in:
@@ -245,6 +245,10 @@ def title_prompt_path(config=None) -> str:
|
|||||||
return data_path("title_prompt.txt", config=config)
|
return data_path("title_prompt.txt", config=config)
|
||||||
|
|
||||||
|
|
||||||
|
def title_templates_dir(config=None) -> str:
|
||||||
|
return data_path("prompts", "title", config=config)
|
||||||
|
|
||||||
|
|
||||||
def cover_prompts_dir(config=None) -> str:
|
def cover_prompts_dir(config=None) -> str:
|
||||||
return data_path("prompts", "cover", config=config)
|
return data_path("prompts", "cover", config=config)
|
||||||
|
|
||||||
|
|||||||
+92
-18
@@ -8,6 +8,7 @@ from importlib import resources
|
|||||||
from . import appconfig
|
from . import appconfig
|
||||||
|
|
||||||
TITLE_PROMPT_PATH = appconfig.title_prompt_path()
|
TITLE_PROMPT_PATH = appconfig.title_prompt_path()
|
||||||
|
TITLE_TEMPLATES_DIR = appconfig.title_templates_dir()
|
||||||
COVER_PROMPTS_DIR = appconfig.cover_prompts_dir()
|
COVER_PROMPTS_DIR = appconfig.cover_prompts_dir()
|
||||||
TEMPLATE_EXT = ".txt"
|
TEMPLATE_EXT = ".txt"
|
||||||
INVALID_NAME_CHARS = set('\\/:*?"<>|')
|
INVALID_NAME_CHARS = set('\\/:*?"<>|')
|
||||||
@@ -41,6 +42,7 @@ def save_title_prompt(text, path=TITLE_PROMPT_PATH) -> None:
|
|||||||
def ensure_default_prompts(
|
def ensure_default_prompts(
|
||||||
title_prompt_path=TITLE_PROMPT_PATH,
|
title_prompt_path=TITLE_PROMPT_PATH,
|
||||||
cover_prompts_dir=COVER_PROMPTS_DIR,
|
cover_prompts_dir=COVER_PROMPTS_DIR,
|
||||||
|
title_templates_dir=None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Seed bundled default prompts into an empty user data directory.
|
"""Seed bundled default prompts into an empty user data directory.
|
||||||
|
|
||||||
@@ -54,13 +56,20 @@ def ensure_default_prompts(
|
|||||||
if default_title:
|
if default_title:
|
||||||
save_title_prompt(default_title, title_prompt_path)
|
save_title_prompt(default_title, title_prompt_path)
|
||||||
|
|
||||||
|
if title_templates_dir is None:
|
||||||
|
title_templates_dir = _title_templates_dir_for_prompt_path(title_prompt_path)
|
||||||
|
if not list_templates(title_templates_dir):
|
||||||
|
default_title = _read_default_prompt_text("title_prompt.txt")
|
||||||
|
if default_title:
|
||||||
|
save_template("默认", default_title, title_templates_dir)
|
||||||
|
|
||||||
if not list_cover_templates(cover_prompts_dir):
|
if not list_cover_templates(cover_prompts_dir):
|
||||||
for name, text in _iter_default_cover_templates():
|
for name, text in _iter_default_cover_templates():
|
||||||
save_cover_template(name, text, cover_prompts_dir)
|
save_cover_template(name, text, cover_prompts_dir)
|
||||||
|
|
||||||
|
|
||||||
def list_cover_templates(directory=COVER_PROMPTS_DIR):
|
def list_templates(directory):
|
||||||
"""Return cover template names sorted by display name."""
|
"""Return prompt template names sorted by display name."""
|
||||||
|
|
||||||
if not os.path.isdir(directory):
|
if not os.path.isdir(directory):
|
||||||
return []
|
return []
|
||||||
@@ -71,18 +80,18 @@ def list_cover_templates(directory=COVER_PROMPTS_DIR):
|
|||||||
return sorted(names, key=str.casefold)
|
return sorted(names, key=str.casefold)
|
||||||
|
|
||||||
|
|
||||||
def load_cover_template(name, directory=COVER_PROMPTS_DIR) -> str:
|
def load_template(name, directory) -> str:
|
||||||
"""Load one cover prompt template."""
|
"""Load one prompt template."""
|
||||||
|
|
||||||
path = _template_path(name, directory)
|
path = _template_path(name, directory)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise PromptError(f"封面提示词模板不存在: {_normalize_name(name)}")
|
raise PromptError(f"提示词模板不存在: {_normalize_name(name)}")
|
||||||
with open(path, "r", encoding="utf-8") as fh:
|
with open(path, "r", encoding="utf-8") as fh:
|
||||||
return fh.read()
|
return fh.read()
|
||||||
|
|
||||||
|
|
||||||
def save_cover_template(name, text, directory=COVER_PROMPTS_DIR) -> None:
|
def save_template(name, text, directory) -> None:
|
||||||
"""Save one cover prompt template as UTF-8."""
|
"""Save one prompt template as UTF-8."""
|
||||||
|
|
||||||
path = _template_path(name, directory)
|
path = _template_path(name, directory)
|
||||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||||
@@ -90,26 +99,86 @@ def save_cover_template(name, text, directory=COVER_PROMPTS_DIR) -> None:
|
|||||||
fh.write(str(text or ""))
|
fh.write(str(text or ""))
|
||||||
|
|
||||||
|
|
||||||
def rename_cover_template(old, new, directory=COVER_PROMPTS_DIR) -> None:
|
def rename_template(old, new, directory) -> None:
|
||||||
"""Rename a cover prompt template with duplicate-name protection."""
|
"""Rename a prompt template with duplicate-name protection."""
|
||||||
|
|
||||||
old_path = _template_path(old, directory)
|
old_path = _template_path(old, directory)
|
||||||
new_path = _template_path(new, directory)
|
new_path = _template_path(new, directory)
|
||||||
if not os.path.exists(old_path):
|
if not os.path.exists(old_path):
|
||||||
raise PromptError(f"封面提示词模板不存在: {_normalize_name(old)}")
|
raise PromptError(f"提示词模板不存在: {_normalize_name(old)}")
|
||||||
if os.path.exists(new_path):
|
if os.path.exists(new_path):
|
||||||
raise PromptError(f"封面提示词模板已存在: {_normalize_name(new)}")
|
raise PromptError(f"提示词模板已存在: {_normalize_name(new)}")
|
||||||
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
||||||
os.replace(old_path, new_path)
|
os.replace(old_path, new_path)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_template(name, directory) -> None:
|
||||||
|
"""Delete one prompt template."""
|
||||||
|
|
||||||
|
path = _template_path(name, directory)
|
||||||
|
if not os.path.exists(path):
|
||||||
|
raise PromptError(f"提示词模板不存在: {_normalize_name(name)}")
|
||||||
|
os.remove(path)
|
||||||
|
|
||||||
|
|
||||||
|
def list_title_templates(directory=TITLE_TEMPLATES_DIR):
|
||||||
|
"""Return title prompt template names sorted by display name."""
|
||||||
|
|
||||||
|
return list_templates(directory)
|
||||||
|
|
||||||
|
|
||||||
|
def load_title_template(name, directory=TITLE_TEMPLATES_DIR) -> str:
|
||||||
|
"""Load one title prompt template."""
|
||||||
|
|
||||||
|
return load_template(name, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def save_title_template(name, text, directory=TITLE_TEMPLATES_DIR) -> None:
|
||||||
|
"""Save one title prompt template as UTF-8."""
|
||||||
|
|
||||||
|
save_template(name, text, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def rename_title_template(old, new, directory=TITLE_TEMPLATES_DIR) -> None:
|
||||||
|
"""Rename a title prompt template with duplicate-name protection."""
|
||||||
|
|
||||||
|
rename_template(old, new, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_title_template(name, directory=TITLE_TEMPLATES_DIR) -> None:
|
||||||
|
"""Delete one title prompt template."""
|
||||||
|
|
||||||
|
delete_template(name, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def list_cover_templates(directory=COVER_PROMPTS_DIR):
|
||||||
|
"""Return cover template names sorted by display name."""
|
||||||
|
|
||||||
|
return list_templates(directory)
|
||||||
|
|
||||||
|
|
||||||
|
def load_cover_template(name, directory=COVER_PROMPTS_DIR) -> str:
|
||||||
|
"""Load one cover prompt template."""
|
||||||
|
|
||||||
|
return load_template(name, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def save_cover_template(name, text, directory=COVER_PROMPTS_DIR) -> None:
|
||||||
|
"""Save one cover prompt template as UTF-8."""
|
||||||
|
|
||||||
|
save_template(name, text, directory)
|
||||||
|
|
||||||
|
|
||||||
|
def rename_cover_template(old, new, directory=COVER_PROMPTS_DIR) -> None:
|
||||||
|
"""Rename a cover prompt template with duplicate-name protection."""
|
||||||
|
|
||||||
|
rename_template(old, new, directory)
|
||||||
|
|
||||||
|
|
||||||
def delete_cover_template(name, directory=COVER_PROMPTS_DIR) -> None:
|
def delete_cover_template(name, directory=COVER_PROMPTS_DIR) -> None:
|
||||||
"""Delete one cover prompt template."""
|
"""Delete one cover prompt template."""
|
||||||
|
|
||||||
path = _template_path(name, directory)
|
delete_template(name, directory)
|
||||||
if not os.path.exists(path):
|
|
||||||
raise PromptError(f"封面提示词模板不存在: {_normalize_name(name)}")
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
|
|
||||||
def render_prompt(template_text, task) -> str:
|
def render_prompt(template_text, task) -> str:
|
||||||
@@ -150,14 +219,19 @@ def _normalize_name(name) -> str:
|
|||||||
value = value[: -len(TEMPLATE_EXT)]
|
value = value[: -len(TEMPLATE_EXT)]
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
if not value:
|
if not value:
|
||||||
raise PromptError("封面提示词模板名不能为空")
|
raise PromptError("提示词模板名不能为空")
|
||||||
if value in {".", ".."} or any(char in INVALID_NAME_CHARS for char in value):
|
if value in {".", ".."} or any(char in INVALID_NAME_CHARS for char in value):
|
||||||
raise PromptError(f"封面提示词模板名非法: {value}")
|
raise PromptError(f"提示词模板名非法: {value}")
|
||||||
if os.path.basename(value) != value:
|
if os.path.basename(value) != value:
|
||||||
raise PromptError(f"封面提示词模板名非法: {value}")
|
raise PromptError(f"提示词模板名非法: {value}")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _title_templates_dir_for_prompt_path(title_prompt_path) -> str:
|
||||||
|
data_root = os.path.dirname(os.path.abspath(title_prompt_path))
|
||||||
|
return os.path.join(data_root, "prompts", "title")
|
||||||
|
|
||||||
|
|
||||||
def _has_non_empty_file(path) -> bool:
|
def _has_non_empty_file(path) -> bool:
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ imported → collected → generated → applied
|
|||||||
- cmhub 网关 Key → `data/config/cmhub.json`,schema `{ "api_key": "..." }`;`config.json` 只保存 Base URL、别名和超时,不保存 Key。
|
- cmhub 网关 Key → `data/config/cmhub.json`,schema `{ "api_key": "..." }`;`config.json` 只保存 Base URL、别名和超时,不保存 Key。
|
||||||
- 业务数据(账号、任务、各阶段结果)→ SQLite `data/cmshopee.db`。
|
- 业务数据(账号、任务、各阶段结果)→ SQLite `data/cmshopee.db`。
|
||||||
- 图片(采集的旧封面、AI 生成的新封面)→ `data/images/`(路径记在 DB)。
|
- 图片(采集的旧封面、AI 生成的新封面)→ `data/images/`(路径记在 DB)。
|
||||||
- 提示词 → 标题提示词存单文件 `data/title_prompt.txt`;封面提示词存多模板 `data/prompts/cover/<名称>.txt`。
|
- 提示词 → 标题当前工作文本存单文件 `data/title_prompt.txt`;标题命名模板存 `data/prompts/title/<名称>.txt`;封面命名模板存 `data/prompts/cover/<名称>.txt`。
|
||||||
- 登录态 → 各账号 `data/chrome_user_data_dir/<slug>/`。
|
- 登录态 → 各账号 `data/chrome_user_data_dir/<slug>/`。
|
||||||
|
|
||||||
T-538 后统一数据根为 `data/`:打包版默认 `<exe目录>/data`,源码运行默认项目根 `data/`。`config.json` 中 `user_data_root`、`image_dir`、`db_path` 默认仍保存为 `chrome_user_data_dir`、`images`、`cmshopee.db` 等相对值,运行时由 `appconfig` 解析到 `data/` 下;绝对路径作为高级自定义仍按原值使用。启动时会迁移 T-524 旧包的 exe 顶层数据到 `data/`,并检测 `data/` 可写。
|
T-538 后统一数据根为 `data/`:打包版默认 `<exe目录>/data`,源码运行默认项目根 `data/`。`config.json` 中 `user_data_root`、`image_dir`、`db_path` 默认仍保存为 `chrome_user_data_dir`、`images`、`cmshopee.db` 等相对值,运行时由 `appconfig` 解析到 `data/` 下;绝对路径作为高级自定义仍按原值使用。启动时会迁移 T-524 旧包的 exe 顶层数据到 `data/`,并检测 `data/` 可写。
|
||||||
@@ -417,7 +417,7 @@ data/images/<batch_id>/<slug>/<task_id>_<item_id>_new.<ext> # AI 生成的新
|
|||||||
|
|
||||||
提示词管理:
|
提示词管理:
|
||||||
|
|
||||||
- **标题提示词**:单个文本,「保存」写入 `data/title_prompt.txt`;软件启动时加载该文件回显到输入框(缺失则空)。T-549 后标题提示词支持 `{旧标题}` 占位符:若提示词含 `{旧标题}`,生成前替换为该任务旧标题且不再自动追加旧标题块;若不含,则保持旧行为自动追加“旧标题:...”块。两种情况都会保留“请只返回新标题,不要解释。”输出约束。
|
- **标题提示词**:`data/title_prompt.txt` 是当前工作文本,「保存标题提示词」写入该文件;软件启动时加载该文件回显到输入框(缺失则空)。标题命名模板另存于 `data/prompts/title/*.txt`,只负责把命名模板载入编辑框或保存当前编辑框内容为模板,不改变生成读取路径。T-549 后标题提示词支持 `{旧标题}` 占位符:若提示词含 `{旧标题}`,生成前替换为该任务旧标题且不再自动追加旧标题块;若不含,则保持旧行为自动追加“旧标题:...”块。两种情况都会保留“请只返回新标题,不要解释。”输出约束。
|
||||||
- **封面提示词**:多模板。下拉选模板(读 `data/prompts/cover/*.txt`),图标工具栏 新建/保存/另存为/重命名/删除;重名校验、删除二次确认、删空给默认。
|
- **封面提示词**:多模板。下拉选模板(读 `data/prompts/cover/*.txt`),图标工具栏 新建/保存/另存为/重命名/删除;重名校验、删除二次确认、删空给默认。
|
||||||
- **变量**:标题提示词本阶段只支持 `{旧标题}`,左侧按钮「插入旧标题」在标题提示词光标处插入 `{旧标题}`。封面提示词支持占位符 `{旧标题}`、`{新标题}`、`{商品id}`、`{店铺}`,生成前用该任务真实值替换(`render_prompt`)。「插入标题」= 在封面提示词光标处插入 `{新标题}`;「预览」= 用某条任务的值替换封面变量后展示,确认实际发送给 AI 的内容。
|
- **变量**:标题提示词本阶段只支持 `{旧标题}`,左侧按钮「插入旧标题」在标题提示词光标处插入 `{旧标题}`。封面提示词支持占位符 `{旧标题}`、`{新标题}`、`{商品id}`、`{店铺}`,生成前用该任务真实值替换(`render_prompt`)。「插入标题」= 在封面提示词光标处插入 `{新标题}`;「预览」= 用某条任务的值替换封面变量后展示,确认实际发送给 AI 的内容。
|
||||||
|
|
||||||
@@ -499,8 +499,10 @@ cmshopee/
|
|||||||
│ ├── cmshopee.db # SQLite(账号/任务/结果)
|
│ ├── cmshopee.db # SQLite(账号/任务/结果)
|
||||||
│ ├── chrome_user_data_dir/ # 各账号 Chrome 配置(含登录态)
|
│ ├── chrome_user_data_dir/ # 各账号 Chrome 配置(含登录态)
|
||||||
│ ├── images/ # 旧封面/新封面本地图片
|
│ ├── images/ # 旧封面/新封面本地图片
|
||||||
│ ├── title_prompt.txt # 标题提示词(单文件,启动回显)
|
│ ├── title_prompt.txt # 标题当前工作文本(启动回显)
|
||||||
│ └── prompts/cover/<名称>.txt
|
│ └── prompts/
|
||||||
|
│ ├── title/<名称>.txt # 标题提示词命名模板
|
||||||
|
│ └── cover/<名称>.txt # 封面提示词命名模板
|
||||||
└── prototypes/ # 已验证原型/探查脚本(demo/set_*/get_title/cookies/inspect_images/grab/1.py)
|
└── prototypes/ # 已验证原型/探查脚本(demo/set_*/get_title/cookies/inspect_images/grab/1.py)
|
||||||
# 逻辑待并入 app/editor.py 后清理;见 prototypes/README.md
|
# 逻辑待并入 app/editor.py 后清理;见 prototypes/README.md
|
||||||
```
|
```
|
||||||
|
|||||||
+6
-2
@@ -3,7 +3,7 @@ id: T-583
|
|||||||
title: 标题提示词模板数据层:泛化 prompts 模板 CRUD + 新增 prompts/title 目录(加法,不换单文件)
|
title: 标题提示词模板数据层:泛化 prompts 模板 CRUD + 新增 prompts/title 目录(加法,不换单文件)
|
||||||
phase: 7
|
phase: 7
|
||||||
deps: []
|
deps: []
|
||||||
status: TODO
|
status: DONE
|
||||||
created: 2026-07-10
|
created: 2026-07-10
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -73,4 +73,8 @@ created: 2026-07-10
|
|||||||
|
|
||||||
## 执行记录
|
## 执行记录
|
||||||
|
|
||||||
(做完在这里写:改了什么文件、跑了什么验证命令及结果、遇到的阻塞、关键决策。)
|
- 2026-07-10:已完成数据层实现。`app/appconfig.py` 新增 `title_templates_dir(config=None)`,指向 `data/prompts/title`;`app/prompts.py` 新增通用 `list/load/save/rename/delete_templates` 能力,标题/封面模板复用同一套 CRUD,保留封面旧 API 薄封装,并新增标题模板薄封装。
|
||||||
|
- 2026-07-10:`ensure_default_prompts()` 增加 `title_templates_dir=None`,为空时从 `title_prompt_path` 推导同一数据根的 `prompts/title/`,为空目录时播入「默认」标题模板;不改 `title_prompt.txt` 工作文本语义,不改生成读取路径。
|
||||||
|
- 2026-07-10:同步 `docs/04-architecture.md` 提示词存储结构;补 `tests/test_prompts.py` 和 `tests/test_appconfig.py` 覆盖标题模板目录、通用 CRUD、默认播种、互不干扰与封面旧 API 回归。
|
||||||
|
- 当前工作区验证:`python -m ruff check app tests main.py` 通过;`py -3.10 -m compileall app main.py` 通过;`git diff --check` 通过。
|
||||||
|
- 当前工作区运行 `py -3.10 -m unittest tests.test_prompts tests.test_appconfig` 失败 1 项,原因是本任务开始前已有未提交改动把默认封面模板从 `papa1` 改成「默认」,导致旧断言仍期望 `papa1`;该封面默认模板改名不属于 T-583,本次未处理、未提交。提交后需用干净 worktree 验证本次提交本身。
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ class AppConfigTests(TempDirMixin, unittest.TestCase):
|
|||||||
self.assertEqual(os.path.join(data_root, "images"), appconfig.image_dir(cfg))
|
self.assertEqual(os.path.join(data_root, "images"), appconfig.image_dir(cfg))
|
||||||
self.assertEqual(os.path.join(data_root, "cmshopee.db"), appconfig.db_path(cfg))
|
self.assertEqual(os.path.join(data_root, "cmshopee.db"), appconfig.db_path(cfg))
|
||||||
self.assertEqual(os.path.join(data_root, "title_prompt.txt"), appconfig.title_prompt_path(cfg))
|
self.assertEqual(os.path.join(data_root, "title_prompt.txt"), appconfig.title_prompt_path(cfg))
|
||||||
|
self.assertEqual(os.path.join(data_root, "prompts", "title"), appconfig.title_templates_dir(cfg))
|
||||||
self.assertEqual(os.path.join(data_root, "prompts", "cover"), appconfig.cover_prompts_dir(cfg))
|
self.assertEqual(os.path.join(data_root, "prompts", "cover"), appconfig.cover_prompts_dir(cfg))
|
||||||
self.assertEqual(os.path.join(data_root, "logs"), appconfig.diagnostic_log_dir(cfg))
|
self.assertEqual(os.path.join(data_root, "logs"), appconfig.diagnostic_log_dir(cfg))
|
||||||
|
|
||||||
|
|||||||
@@ -45,14 +45,49 @@ class PromptTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_generic_template_crud_and_title_cover_directories_are_independent(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
title_dir = os.path.join(temp_dir, "prompts", "title")
|
||||||
|
cover_dir = os.path.join(temp_dir, "prompts", "cover")
|
||||||
|
|
||||||
|
prompts.save_template("基础", "通用模板", title_dir)
|
||||||
|
prompts.save_title_template("标题A", "标题模板", title_dir)
|
||||||
|
prompts.save_cover_template("封面A", "封面模板", cover_dir)
|
||||||
|
|
||||||
|
self.assertEqual(["基础", "标题A"], prompts.list_title_templates(title_dir))
|
||||||
|
self.assertEqual(["封面A"], prompts.list_cover_templates(cover_dir))
|
||||||
|
self.assertEqual("通用模板", prompts.load_template("基础", title_dir))
|
||||||
|
self.assertEqual("标题模板", prompts.load_title_template("标题A", title_dir))
|
||||||
|
self.assertEqual("封面模板", prompts.load_cover_template("封面A", cover_dir))
|
||||||
|
|
||||||
|
prompts.rename_template("基础", "基础2", title_dir)
|
||||||
|
self.assertEqual(["基础2", "标题A"], prompts.list_templates(title_dir))
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(prompts.PromptError, "提示词模板已存在"):
|
||||||
|
prompts.rename_template("基础2", "标题A", title_dir)
|
||||||
|
with self.assertRaisesRegex(prompts.PromptError, "提示词模板名非法"):
|
||||||
|
prompts.save_title_template("../bad", "x", title_dir)
|
||||||
|
|
||||||
|
prompts.delete_title_template("标题A", title_dir)
|
||||||
|
self.assertEqual(["基础2"], prompts.list_title_templates(title_dir))
|
||||||
|
self.assertEqual(["封面A"], prompts.list_cover_templates(cover_dir))
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
def test_ensure_default_prompts_seeds_empty_user_prompt_files(self):
|
def test_ensure_default_prompts_seeds_empty_user_prompt_files(self):
|
||||||
with self.make_temp_dir() as temp_dir:
|
with self.make_temp_dir() as temp_dir:
|
||||||
title_path = os.path.join(temp_dir, "title_prompt.txt")
|
title_path = os.path.join(temp_dir, "title_prompt.txt")
|
||||||
|
title_templates_dir = os.path.join(temp_dir, "prompts", "title")
|
||||||
cover_dir = os.path.join(temp_dir, "prompts", "cover")
|
cover_dir = os.path.join(temp_dir, "prompts", "cover")
|
||||||
|
|
||||||
prompts.ensure_default_prompts(title_path, cover_dir)
|
prompts.ensure_default_prompts(title_path, cover_dir)
|
||||||
|
|
||||||
self.assertIn("蝦皮台灣站", prompts.load_title_prompt(title_path))
|
self.assertIn("蝦皮台灣站", prompts.load_title_prompt(title_path))
|
||||||
|
self.assertEqual(["默认"], prompts.list_title_templates(title_templates_dir))
|
||||||
|
self.assertEqual(
|
||||||
|
prompts.load_title_prompt(title_path),
|
||||||
|
prompts.load_title_template("默认", title_templates_dir),
|
||||||
|
)
|
||||||
self.assertEqual(["papa1"], prompts.list_cover_templates(cover_dir))
|
self.assertEqual(["papa1"], prompts.list_cover_templates(cover_dir))
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"商品标题:{新标题}",
|
"商品标题:{新标题}",
|
||||||
@@ -64,13 +99,20 @@ class PromptTests(TempDirMixin, unittest.TestCase):
|
|||||||
def test_ensure_default_prompts_does_not_overwrite_user_prompts(self):
|
def test_ensure_default_prompts_does_not_overwrite_user_prompts(self):
|
||||||
with self.make_temp_dir() as temp_dir:
|
with self.make_temp_dir() as temp_dir:
|
||||||
title_path = os.path.join(temp_dir, "title_prompt.txt")
|
title_path = os.path.join(temp_dir, "title_prompt.txt")
|
||||||
|
title_templates_dir = os.path.join(temp_dir, "prompts", "title")
|
||||||
cover_dir = os.path.join(temp_dir, "prompts", "cover")
|
cover_dir = os.path.join(temp_dir, "prompts", "cover")
|
||||||
prompts.save_title_prompt("用户标题提示词", title_path)
|
prompts.save_title_prompt("用户标题提示词", title_path)
|
||||||
|
prompts.save_title_template("用户标题模板", "用户标题模板内容", title_templates_dir)
|
||||||
prompts.save_cover_template("用户模板", "用户封面提示词", cover_dir)
|
prompts.save_cover_template("用户模板", "用户封面提示词", cover_dir)
|
||||||
|
|
||||||
prompts.ensure_default_prompts(title_path, cover_dir)
|
prompts.ensure_default_prompts(title_path, cover_dir)
|
||||||
|
|
||||||
self.assertEqual("用户标题提示词", prompts.load_title_prompt(title_path))
|
self.assertEqual("用户标题提示词", prompts.load_title_prompt(title_path))
|
||||||
|
self.assertEqual(["用户标题模板"], prompts.list_title_templates(title_templates_dir))
|
||||||
|
self.assertEqual(
|
||||||
|
"用户标题模板内容",
|
||||||
|
prompts.load_title_template("用户标题模板", title_templates_dir),
|
||||||
|
)
|
||||||
self.assertEqual(["用户模板"], prompts.list_cover_templates(cover_dir))
|
self.assertEqual(["用户模板"], prompts.list_cover_templates(cover_dir))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
"用户封面提示词",
|
"用户封面提示词",
|
||||||
@@ -79,6 +121,19 @@ class PromptTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_ensure_default_prompts_accepts_explicit_title_templates_dir(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
title_path = os.path.join(temp_dir, "custom", "title_prompt.txt")
|
||||||
|
cover_dir = os.path.join(temp_dir, "custom", "cover")
|
||||||
|
title_templates_dir = os.path.join(temp_dir, "other", "title_templates")
|
||||||
|
|
||||||
|
prompts.ensure_default_prompts(title_path, cover_dir, title_templates_dir)
|
||||||
|
|
||||||
|
self.assertEqual(["默认"], prompts.list_title_templates(title_templates_dir))
|
||||||
|
self.assertFalse(os.path.exists(os.path.join(temp_dir, "custom", "prompts", "title")))
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
def test_render_prompt_replaces_known_variables(self):
|
def test_render_prompt_replaces_known_variables(self):
|
||||||
task = {
|
task = {
|
||||||
"old_title": "舊T恤",
|
"old_title": "舊T恤",
|
||||||
|
|||||||
Reference in New Issue
Block a user