🐛 fix(config): 修复 Windows 下配置文件保存时的权限错误
- 在 `ConfigManager.save()` 方法中增加重试逻辑,当 `os.replace` 因目标文件被占用而抛出 `PermissionError` 时,最多重试 3 次,每次间隔 0.1 秒 ♻️ refactor(import): 修正模块导入路径 - 在 `LLMService.get_sd_prompt_guide` 方法中,将 `from sd_service import ...` 修正为 `from services.sd_service import ...`,以修复因相对导入路径错误导致的模块未找到问题 🔧 chore(ui): 优化 UI 组件交互性与初始化参数 - 在 `_fn_batch_generate` 函数中,为 `PublishQueue` 实例化明确指定工作空间参数 `"xhs_workspace"` - 在 `tab_create.py` 的封面图策略 `gr.Radio` 组件中,添加 `interactive=True` 参数以启用用户交互
This commit is contained in:
parent
1ec520b47e
commit
1889e9a222
@ -95,13 +95,22 @@ class ConfigManager:
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""原子写:临时文件 + os.replace,防止写中断导致数据损坏"""
|
"""原子写:临时文件 + os.replace,防止写中断导致数据损坏"""
|
||||||
|
import time
|
||||||
config_dir = os.path.dirname(os.path.abspath(CONFIG_FILE)) or "."
|
config_dir = os.path.dirname(os.path.abspath(CONFIG_FILE)) or "."
|
||||||
try:
|
try:
|
||||||
fd, tmp_path = tempfile.mkstemp(dir=config_dir, suffix=".tmp", prefix="config_")
|
fd, tmp_path = tempfile.mkstemp(dir=config_dir, suffix=".tmp", prefix="config_")
|
||||||
try:
|
try:
|
||||||
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
||||||
json.dump(self._config, f, indent=4, ensure_ascii=False)
|
json.dump(self._config, f, indent=4, ensure_ascii=False)
|
||||||
os.replace(tmp_path, CONFIG_FILE)
|
# Windows 下目标文件被占用时 os.replace 会抛 PermissionError(WinError 5),重试最多 3 次
|
||||||
|
for attempt in range(3):
|
||||||
|
try:
|
||||||
|
os.replace(tmp_path, CONFIG_FILE)
|
||||||
|
break
|
||||||
|
except PermissionError:
|
||||||
|
if attempt == 2:
|
||||||
|
raise
|
||||||
|
time.sleep(0.1)
|
||||||
except Exception:
|
except Exception:
|
||||||
try:
|
try:
|
||||||
os.remove(tmp_path)
|
os.remove(tmp_path)
|
||||||
|
|||||||
@ -370,7 +370,7 @@ class LLMService:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_sd_prompt_guide(sd_model_name: str = None, persona: str = None) -> str:
|
def get_sd_prompt_guide(sd_model_name: str = None, persona: str = None) -> str:
|
||||||
"""根据当前 SD 模型 + 人设 生成 LLM 使用的绘图 Prompt 指南(含反 AI 检测指导 + 人设视觉风格)"""
|
"""根据当前 SD 模型 + 人设 生成 LLM 使用的绘图 Prompt 指南(含反 AI 检测指导 + 人设视觉风格)"""
|
||||||
from sd_service import SD_MODEL_PROFILES, detect_model_profile, get_persona_sd_profile
|
from services.sd_service import SD_MODEL_PROFILES, detect_model_profile, get_persona_sd_profile
|
||||||
|
|
||||||
key = detect_model_profile(sd_model_name) if sd_model_name else "juggernautXL"
|
key = detect_model_profile(sd_model_name) if sd_model_name else "juggernautXL"
|
||||||
profile = SD_MODEL_PROFILES.get(key, SD_MODEL_PROFILES["juggernautXL"])
|
profile = SD_MODEL_PROFILES.get(key, SD_MODEL_PROFILES["juggernautXL"])
|
||||||
|
|||||||
@ -70,7 +70,7 @@ def _fn_topic_recommend(model_name):
|
|||||||
|
|
||||||
def _fn_batch_generate(model_name, topics, style, sd_model_name, persona_text, template_name):
|
def _fn_batch_generate(model_name, topics, style, sd_model_name, persona_text, template_name):
|
||||||
"""批量生成文案并入草稿队列"""
|
"""批量生成文案并入草稿队列"""
|
||||||
pq = PublishQueue()
|
pq = PublishQueue("xhs_workspace")
|
||||||
return batch_generate_copy(
|
return batch_generate_copy(
|
||||||
model=model_name,
|
model=model_name,
|
||||||
topics=topics,
|
topics=topics,
|
||||||
|
|||||||
@ -83,6 +83,7 @@ def build_tab(
|
|||||||
label="封面图策略",
|
label="封面图策略",
|
||||||
value="人物特写",
|
value="人物特写",
|
||||||
info="影响 SD 构图和尺寸",
|
info="影响 SD 构图和尺寸",
|
||||||
|
interactive=True,
|
||||||
)
|
)
|
||||||
quality_mode = gr.Radio(
|
quality_mode = gr.Radio(
|
||||||
sd_preset_names,
|
sd_preset_names,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user