| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- """
- 配置 API 路由
- 提供数据源配置的读取和管理
- """
- from fastapi import APIRouter, HTTPException
- from pathlib import Path
- from typing import List, Dict, Any
- import yaml
- from loguru import logger
- from models.schemas import HealthResponse
- router = APIRouter(prefix="/api/config", tags=["config"])
- def _get_config_dir() -> Path:
- """获取配置目录路径"""
- return Path(__file__).parent.parent / "config" / "data_sources"
- def _resolve_template(template: str, variables: Dict[str, str]) -> str:
- """解析模板变量"""
- resolved = template
- for key, value in variables.items():
- resolved = resolved.replace(f"{{{{{key}}}}}", value)
- resolved = resolved.replace(f"{{{{ {key} }}}}", value)
- return resolved
- def _parse_data_source(config: Dict[str, Any]) -> Dict[str, Any]:
- """解析数据源配置,展开模板变量"""
- if 'data_source' not in config:
- return config
-
- ds = config['data_source']
-
- # 准备变量字典
- variables = {
- 'name': ds.get('name', ''),
- 'base_dir': ds.get('base_dir', '')
- }
-
- # 解析路径模板
- if 'json_dir' in ds:
- ds['json_dir'] = _resolve_template(ds['json_dir'], variables)
- if 'image_dir' in ds:
- ds['image_dir'] = _resolve_template(ds['image_dir'], variables)
- if 'output' in ds and 'directory' in ds['output']:
- ds['output']['directory'] = _resolve_template(ds['output']['directory'], variables)
-
- return ds
- @router.get("/data-sources")
- async def list_data_sources() -> Dict[str, List[Dict[str, Any]]]:
- """
- 列出所有预定义数据源
-
- Returns:
- 包含 sources 列表的字典,每个数据源包含 filename 字段(不含 .yaml 扩展名)
- """
- config_dir = _get_config_dir()
- sources = []
-
- try:
- if not config_dir.exists():
- logger.warning(f"配置目录不存在: {config_dir}")
- return {"sources": []}
-
- for yaml_file in sorted(config_dir.glob("*.yaml")):
- if yaml_file.name == "README.md":
- continue
-
- try:
- with open(yaml_file, 'r', encoding='utf-8') as f:
- config = yaml.safe_load(f)
-
- if config and 'data_source' in config:
- parsed = _parse_data_source(config)
- # 添加文件名作为唯一标识符(不含 .yaml 扩展名)
- filename = yaml_file.stem # 获取不含扩展名的文件名
- parsed['filename'] = filename
- sources.append(parsed)
- logger.debug(f"加载数据源配置: {yaml_file.name} (filename: {filename})")
- except Exception as e:
- logger.error(f"加载配置文件失败 {yaml_file}: {e}")
- continue
-
- logger.info(f"成功加载 {len(sources)} 个数据源配置")
- return {"sources": sources}
-
- except Exception as e:
- logger.exception(f"列出数据源失败: {e}")
- raise HTTPException(status_code=500, detail=f"列出数据源失败: {e}")
- @router.get("/data-sources/{filename}")
- async def get_data_source(filename: str) -> Dict[str, Any]:
- """
- 获取指定数据源配置
-
- Args:
- filename: 数据源配置文件名(不含 .yaml 扩展名)
-
- Returns:
- 数据源配置
- """
- config_dir = _get_config_dir()
-
- try:
- # 直接使用文件名查找配置文件
- yaml_file = config_dir / f"{filename}.yaml"
-
- if not yaml_file.exists():
- raise HTTPException(status_code=404, detail=f"数据源配置文件不存在: {filename}.yaml")
-
- with open(yaml_file, 'r', encoding='utf-8') as f:
- config = yaml.safe_load(f)
-
- if config and 'data_source' in config:
- parsed = _parse_data_source(config)
- # 添加文件名作为唯一标识符
- parsed['filename'] = filename
- return parsed
- else:
- raise HTTPException(status_code=404, detail=f"配置文件格式错误: {filename}.yaml")
-
- except HTTPException:
- raise
- except Exception as e:
- logger.exception(f"获取数据源失败: {e}")
- raise HTTPException(status_code=500, detail=f"获取数据源失败: {e}")
- @router.get("/health", response_model=HealthResponse)
- async def config_health_check():
- """配置服务健康检查"""
- return HealthResponse(
- status="ok",
- service="config"
- )
|