T-579 内置默认AI提示词
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from importlib import resources
|
||||
|
||||
from . import appconfig
|
||||
|
||||
@@ -10,6 +11,8 @@ TITLE_PROMPT_PATH = appconfig.title_prompt_path()
|
||||
COVER_PROMPTS_DIR = appconfig.cover_prompts_dir()
|
||||
TEMPLATE_EXT = ".txt"
|
||||
INVALID_NAME_CHARS = set('\\/:*?"<>|')
|
||||
DEFAULT_PROMPTS_PACKAGE = "app.default_prompts"
|
||||
DEFAULT_COVER_PROMPTS_PACKAGE = "app.default_prompts.cover"
|
||||
|
||||
|
||||
class PromptError(RuntimeError):
|
||||
@@ -35,6 +38,27 @@ def save_title_prompt(text, path=TITLE_PROMPT_PATH) -> None:
|
||||
fh.write(str(text or ""))
|
||||
|
||||
|
||||
def ensure_default_prompts(
|
||||
title_prompt_path=TITLE_PROMPT_PATH,
|
||||
cover_prompts_dir=COVER_PROMPTS_DIR,
|
||||
) -> None:
|
||||
"""Seed bundled default prompts into an empty user data directory.
|
||||
|
||||
Existing user prompts are never overwritten. Defaults live in the packaged
|
||||
app and are copied into data/ only when the corresponding user files are
|
||||
missing, or the title prompt file is blank.
|
||||
"""
|
||||
|
||||
if not _has_non_empty_file(title_prompt_path):
|
||||
default_title = _read_default_prompt_text("title_prompt.txt")
|
||||
if default_title:
|
||||
save_title_prompt(default_title, title_prompt_path)
|
||||
|
||||
if not list_cover_templates(cover_prompts_dir):
|
||||
for name, text in _iter_default_cover_templates():
|
||||
save_cover_template(name, text, cover_prompts_dir)
|
||||
|
||||
|
||||
def list_cover_templates(directory=COVER_PROMPTS_DIR):
|
||||
"""Return cover template names sorted by display name."""
|
||||
|
||||
@@ -132,3 +156,40 @@ def _normalize_name(name) -> str:
|
||||
if os.path.basename(value) != value:
|
||||
raise PromptError(f"封面提示词模板名非法: {value}")
|
||||
return value
|
||||
|
||||
|
||||
def _has_non_empty_file(path) -> bool:
|
||||
try:
|
||||
if not os.path.exists(path):
|
||||
return False
|
||||
with open(path, "r", encoding="utf-8") as fh:
|
||||
return bool(fh.read().strip())
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _read_default_prompt_text(filename) -> str:
|
||||
try:
|
||||
return (
|
||||
resources.files(DEFAULT_PROMPTS_PACKAGE)
|
||||
.joinpath(filename)
|
||||
.read_text(encoding="utf-8")
|
||||
)
|
||||
except (FileNotFoundError, ModuleNotFoundError, OSError):
|
||||
return ""
|
||||
|
||||
|
||||
def _iter_default_cover_templates():
|
||||
try:
|
||||
root = resources.files(DEFAULT_COVER_PROMPTS_PACKAGE)
|
||||
except (ModuleNotFoundError, OSError):
|
||||
return
|
||||
for entry in root.iterdir():
|
||||
if not entry.is_file() or not entry.name.lower().endswith(TEMPLATE_EXT):
|
||||
continue
|
||||
name = entry.name[: -len(TEMPLATE_EXT)]
|
||||
try:
|
||||
text = entry.read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
continue
|
||||
yield name, text
|
||||
|
||||
Reference in New Issue
Block a user