fix: harden memoir image generation flow
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from typing import Any, Optional
|
||||
|
||||
from .settings import MemoirImageSettings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_CJK_RE = re.compile(r"[\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]")
|
||||
|
||||
|
||||
class MemoirImagePromptService:
|
||||
CATEGORY_STYLE_MAP = {
|
||||
@@ -14,6 +19,16 @@ class MemoirImagePromptService:
|
||||
"beliefs": "editorial illustration",
|
||||
"summary": "editorial illustration",
|
||||
}
|
||||
CATEGORY_FALLBACK_SUBJECT_MAP = {
|
||||
"childhood": "childhood memory",
|
||||
"education": "school memory",
|
||||
"career_early": "early career memory",
|
||||
"career_achievement": "career achievement memory",
|
||||
"career_challenge": "career challenge memory",
|
||||
"family": "family memory",
|
||||
"beliefs": "reflective life memory",
|
||||
"summary": "memoir summary scene",
|
||||
}
|
||||
|
||||
def __init__(self, llm: Optional[Any], settings: MemoirImageSettings):
|
||||
self.llm = llm
|
||||
@@ -47,17 +62,69 @@ class MemoirImagePromptService:
|
||||
)
|
||||
parsed = json.loads(response.content)
|
||||
return {
|
||||
"prompt": parsed["prompt"],
|
||||
"prompt": _ensure_style_in_prompt(parsed["prompt"], parsed.get("style", style)),
|
||||
"style": parsed.get("style", style),
|
||||
"size": parsed.get("size", self.settings.default_size),
|
||||
"prompt_context": prompt_context,
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"图片 prompt 生成回退到默认模板: chapter_category=%s, title=%s, error=%s",
|
||||
chapter_category,
|
||||
chapter_title,
|
||||
exc,
|
||||
)
|
||||
|
||||
return {
|
||||
"prompt": f"{description}\n\nScene context: {context_excerpt}",
|
||||
"prompt": _ensure_style_in_prompt(
|
||||
self._build_fallback_prompt(
|
||||
chapter_category=chapter_category,
|
||||
description=description,
|
||||
context_excerpt=context_excerpt,
|
||||
style=style,
|
||||
),
|
||||
style,
|
||||
),
|
||||
"style": style,
|
||||
"size": self.settings.default_size,
|
||||
"prompt_context": prompt_context,
|
||||
}
|
||||
|
||||
def _build_fallback_prompt(
|
||||
self,
|
||||
chapter_category: str,
|
||||
description: str,
|
||||
context_excerpt: str,
|
||||
style: str,
|
||||
) -> str:
|
||||
subject = self.CATEGORY_FALLBACK_SUBJECT_MAP.get(chapter_category, "memoir scene")
|
||||
if _contains_cjk(description) or _contains_cjk(context_excerpt):
|
||||
return (
|
||||
f"A {style} illustration of a {subject}, emotionally resonant, cinematic composition, "
|
||||
"authentic everyday details, natural lighting, expressive environment, no text overlay."
|
||||
)
|
||||
|
||||
details = ". ".join(part.strip() for part in (description, context_excerpt) if part.strip())
|
||||
if not details:
|
||||
details = "A personal life story scene with authentic emotional detail"
|
||||
return (
|
||||
f"A {style} illustration of a {subject}. "
|
||||
f"Scene details: {details}. "
|
||||
"Cinematic composition, authentic emotions, natural lighting, no text overlay."
|
||||
)
|
||||
|
||||
|
||||
def _contains_cjk(value: str) -> bool:
|
||||
return bool(_CJK_RE.search(value or ""))
|
||||
|
||||
|
||||
def _ensure_style_in_prompt(prompt: str, style: str) -> str:
|
||||
cleaned_prompt = (prompt or "").strip()
|
||||
cleaned_style = (style or "").strip()
|
||||
if not cleaned_style:
|
||||
return cleaned_prompt
|
||||
if cleaned_style.lower() in cleaned_prompt.lower():
|
||||
return cleaned_prompt
|
||||
if not cleaned_prompt:
|
||||
return cleaned_style
|
||||
return f"{cleaned_style}, {cleaned_prompt}"
|
||||
|
||||
Reference in New Issue
Block a user