Files
dreamweaver/backend/app/services/adapters/demo.py
Yuyan 44405ff7ac
Some checks failed
Build and Push Docker Images / changes (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-admin-frontend (push) Has been cancelled
feat: enable local docker demo mode
2026-04-18 12:01:27 +08:00

152 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Local deterministic demo adapters for portfolio Docker demos."""
from __future__ import annotations
from typing import Literal
from app.services.adapters.base import BaseAdapter
from app.services.adapters.registry import AdapterRegistry
from app.services.adapters.storybook.primary import Storybook, StorybookPage
from app.services.adapters.text.models import StoryOutput
def _compact_topic(data: str) -> str:
parts = [
item.strip(" ,。.!?")
for item in data.replace("\n", " ").split()
if item.strip(" ,。.!?")
]
if parts:
return "".join(parts[:3])
return data.strip()[:20] or "星光森林"
def _demo_image_data_url(label: str) -> str:
return (
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' "
"viewBox='0 0 1200 800'%3E%3Crect width='1200' height='800' "
"fill='%23fef3c7'/%3E%3Ccircle cx='250' cy='180' r='130' "
"fill='%23f59e0b'/%3E%3Cpath d='M120 600C320 420 520 700 "
"720 500S1020 420 1100 560' fill='none' stroke='%237c3aed' "
"stroke-width='42'/%3E%3C/svg%3E"
)
@AdapterRegistry.register("text", "demo")
class DemoTextAdapter(BaseAdapter[StoryOutput]):
"""Generate a stable local story without external AI services."""
adapter_type = "text"
adapter_name = "demo"
async def execute(
self,
input_type: Literal["keywords", "full_story"],
data: str,
education_theme: str | None = None,
memory_context: str | None = None,
**kwargs,
) -> StoryOutput:
theme = education_theme or "勇气与想象力"
topic = _compact_topic(data)
title = f"{topic}的晚安冒险"
protagonist = "小星"
if memory_context and "名字" in memory_context:
protagonist = "故事里的小朋友"
story_text = (
f"睡前,{protagonist}把“{topic}”写在一张小纸条上,轻轻放进枕头下面。"
f"月光刚好照进房间,纸条变成了一只会发光的小船,邀请{protagonist}去寻找"
f"关于“{theme}”的答案。\n\n"
f"小船穿过云朵河,来到一片会唱歌的森林。森林里的小鹿说:真正的勇敢不是"
f"一点也不害怕,而是害怕的时候,还愿意牵住朋友的手往前走。{protagonist}"
f"听完以后,把一颗星星种进土里,星星长成了照亮回家路的小灯。\n\n"
f"回到房间时,纸条已经变成了一枚金色书签。{protagonist}把它夹进故事书,"
f"决定明天也带着好奇心和温柔,继续新的冒险。"
)
return StoryOutput(
mode="generated" if input_type == "keywords" else "enhanced",
title=title,
story_text=story_text,
cover_prompt_suggestion=f"温暖水彩儿童绘本封面,主题:{topic}{theme}",
)
async def health_check(self) -> bool:
return True
@property
def estimated_cost(self) -> float:
return 0.0
@AdapterRegistry.register("image", "demo")
class DemoImageAdapter(BaseAdapter[str]):
"""Return a compact SVG data URL as a generated-image placeholder."""
adapter_type = "image"
adapter_name = "demo"
async def execute(self, prompt: str, **kwargs) -> str:
return _demo_image_data_url(prompt)
async def health_check(self) -> bool:
return True
@property
def estimated_cost(self) -> float:
return 0.0
@AdapterRegistry.register("storybook", "demo")
class DemoStorybookAdapter(BaseAdapter[Storybook]):
"""Generate a stable local storybook without external AI services."""
adapter_type = "storybook"
adapter_name = "demo"
async def execute(
self,
keywords: str,
page_count: int = 6,
education_theme: str | None = None,
memory_context: str | None = None,
**kwargs,
) -> Storybook:
theme = education_theme or "勇气"
topic = _compact_topic(keywords)
page_count = max(4, min(page_count, 8))
page_texts = [
f"小星在枕头下发现一张写着“{topic}”的星光地图。",
"地图带他来到云朵河边,一只小船正在等他上船。",
f"森林里的小鹿告诉他:{theme}藏在每一次温柔的选择里。",
"小星把一颗星星种进土里,星星长成了回家的灯。",
"他把今天的发现画进故事本,准备明天讲给家人听。",
"月亮轻轻合上窗帘,房间里只剩下甜甜的梦。",
"星光地图变成书签,陪他继续下一次冒险。",
"每个勇敢的小问题,都能长出一个温暖的故事。",
]
pages = [
StorybookPage(
page_number=index + 1,
text=page_texts[index],
image_prompt=f"温暖儿童绘本插画,第 {index + 1} 页,{topic}{theme}",
)
for index in range(page_count)
]
return Storybook(
title=f"{topic}的星光绘本",
main_character="小星",
art_style="温暖水彩",
pages=pages,
cover_prompt=f"温暖水彩儿童绘本封面,{topic}{theme}",
)
async def health_check(self) -> bool:
return True
@property
def estimated_cost(self) -> float:
return 0.0