feat: enable local docker demo mode
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
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
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
"""适配器模块 - 供应商平台化架构核心。"""
|
||||
|
||||
# Demo adapters
|
||||
from app.services.adapters import demo as _demo_adapters # noqa: F401
|
||||
from app.services.adapters.base import AdapterConfig, BaseAdapter
|
||||
|
||||
# Image adapters
|
||||
@@ -15,6 +17,7 @@ from app.services.adapters.text import gemini as _text_gemini_adapter # noqa: F
|
||||
from app.services.adapters.text import openai as _text_openai_adapter # noqa: F401
|
||||
|
||||
# TTS adapters
|
||||
from app.services.adapters.tts import edge_tts as _tts_edge_tts_adapter # noqa: F401
|
||||
from app.services.adapters.tts import elevenlabs as _tts_elevenlabs_adapter # noqa: F401
|
||||
from app.services.adapters.tts import minimax as _tts_minimax_adapter # noqa: F401
|
||||
|
||||
|
||||
151
backend/app/services/adapters/demo.py
Normal file
151
backend/app/services/adapters/demo.py
Normal file
@@ -0,0 +1,151 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user