Merge branch 'refactor/backend-architecture' into development
This commit is contained in:
0
api/app/ports/__init__.py
Normal file
0
api/app/ports/__init__.py
Normal file
10
api/app/ports/asr.py
Normal file
10
api/app/ports/asr.py
Normal 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."""
|
||||
...
|
||||
14
api/app/ports/embedding.py
Normal file
14
api/app/ports/embedding.py
Normal 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."""
|
||||
...
|
||||
36
api/app/ports/image_gen.py
Normal file
36
api/app/ports/image_gen.py
Normal 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
27
api/app/ports/llm.py
Normal 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
10
api/app/ports/reranker.py
Normal 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
10
api/app/ports/sms.py
Normal 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
18
api/app/ports/storage.py
Normal 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
10
api/app/ports/tts.py
Normal 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."""
|
||||
...
|
||||
Reference in New Issue
Block a user