Merge branch 'refactor/backend-architecture' into development

This commit is contained in:
yangshilin
2026-03-18 17:18:23 +08:00
parent 2070a03d35
commit 48b70e1350
266 changed files with 12386 additions and 9690 deletions

View File

10
api/app/ports/asr.py Normal file
View File

@@ -0,0 +1,10 @@
"""ASRProvider port — 语音转文字能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class ASRProvider(Protocol):
async def transcribe(self, audio: bytes, format: str = "m4a") -> str:
"""Transcribe audio bytes to text."""
...

View File

@@ -0,0 +1,14 @@
"""EmbeddingProvider port — 文本向量化能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class EmbeddingProvider(Protocol):
async def embed_text(self, text: str) -> list[float]:
"""Embed a single text into a vector."""
...
async def embed_texts(self, texts: list[str]) -> list[list[float]]:
"""Embed multiple texts into vectors."""
...

View File

@@ -0,0 +1,36 @@
"""ImageGenerator port — 图片生成能力契约。"""
from dataclasses import dataclass
from enum import Enum
from typing import Protocol, runtime_checkable
class TaskStatus(Enum):
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
@dataclass
class ImageResult:
status: TaskStatus
task_id: str
image_url: str | None = None
image_bytes: bytes | None = None
error: str | None = None
@runtime_checkable
class ImageGenerator(Protocol):
def generate(self, prompt: str, size: str, style: str) -> ImageResult:
"""Submit generation, poll until done, return result (sync, may block)."""
...
def check_status(self, task_id: str) -> ImageResult:
"""Check current status of a generation task."""
...
def download_image(self, image_url: str) -> bytes:
"""Download image bytes from a generated image URL (e.g. from ImageResult.image_url)."""
...

27
api/app/ports/llm.py Normal file
View File

@@ -0,0 +1,27 @@
"""LLMProvider port — 大语言模型能力契约。"""
from collections.abc import AsyncIterator
from typing import Protocol, runtime_checkable
@runtime_checkable
class LLMProvider(Protocol):
async def complete(
self,
messages: list[dict],
*,
temperature: float = 0.7,
model: str | None = None,
) -> str:
"""Single-turn completion, returns full response text."""
...
def stream(
self,
messages: list[dict],
*,
temperature: float = 0.7,
model: str | None = None,
) -> AsyncIterator[str]:
"""Streaming completion, yields text chunks (async generator)."""
...

10
api/app/ports/reranker.py Normal file
View File

@@ -0,0 +1,10 @@
"""Reranker port — 可选,二期 cross-encoder rerank 能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class Reranker(Protocol):
async def rerank(self, query: str, documents: list[str]) -> list[float]:
"""Score documents against a query, return relevance scores."""
...

10
api/app/ports/sms.py Normal file
View File

@@ -0,0 +1,10 @@
"""SmsSender port — 短信发送能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class SmsSender(Protocol):
def send_verification_code(self, phone: str, code: str) -> bool:
"""Send a verification code via SMS. Return True on success."""
...

18
api/app/ports/storage.py Normal file
View File

@@ -0,0 +1,18 @@
"""ObjectStorage port — 对象存储能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class ObjectStorage(Protocol):
def upload(self, key: str, data: bytes, content_type: str) -> str:
"""Upload object, return its public or base URL."""
...
def get_url(self, key: str, expires: int = 3600) -> str:
"""Generate a presigned download URL."""
...
def delete(self, key: str) -> None:
"""Delete an object by key."""
...

10
api/app/ports/tts.py Normal file
View File

@@ -0,0 +1,10 @@
"""TTSProvider port — 文字转语音能力契约。"""
from typing import Protocol, runtime_checkable
@runtime_checkable
class TTSProvider(Protocol):
async def synthesize(self, text: str, voice: str = "alloy") -> bytes:
"""Convert text to speech audio bytes."""
...