feat: Phase 1+2 — project setup and core infrastructure

- requirements.txt, config.yaml, .env, Dockerfile, docker-compose.yml
- app/core: config (YAML+env override), logging (JSON structured),
  exceptions (typed hierarchy), json_utils (Markdown fence stripping)
- app/clients: LLMClient ABC + ZhipuAIClient (run_in_executor),
  StorageClient ABC + RustFSClient (boto3 head_object for size check)
- app/main.py: FastAPI app with health endpoint and router registration
- app/core/dependencies.py: lru_cache singleton factories
- tests/conftest.py: mock_llm, mock_storage, test_app, client fixtures
- pytest.ini: asyncio_mode=auto
- 11 unit tests passing
This commit is contained in:
wh
2026-04-10 15:22:45 +08:00
parent 4162d9f4e6
commit e1eb5e47b1
54 changed files with 716 additions and 0 deletions

19
app/core/json_utils.py Normal file
View File

@@ -0,0 +1,19 @@
import json
import re
from app.core.exceptions import LLMParseError
def extract_json(text: str) -> any:
"""Parse JSON from LLM response, stripping Markdown code fences if present."""
text = text.strip()
# Strip ```json ... ``` or ``` ... ``` fences
fence_match = re.search(r"```(?:json)?\s*([\s\S]+?)\s*```", text)
if fence_match:
text = fence_match.group(1).strip()
try:
return json.loads(text)
except json.JSONDecodeError as e:
raise LLMParseError(f"大模型返回非合法 JSON: {e}") from e