""" API文档生成器 - 离线生成Swagger文档 """ import hashlib import json import os from pathlib import Path from typing import Optional from ..utils import get_logger logger = get_logger(__name__) # 文档缓存目录 STATIC_DIR = Path("static") CACHE_FILE = STATIC_DIR / ".openapi_cache" DOC_FILE = STATIC_DIR / "doc.html" def get_openapi_hash(openapi_spec: dict) -> str: """计算OpenAPI规范的哈希值""" spec_str = json.dumps(openapi_spec, sort_keys=True, ensure_ascii=False) return hashlib.md5(spec_str.encode()).hexdigest() def get_cached_hash() -> Optional[str]: """获取缓存的哈希值""" try: if CACHE_FILE.exists(): return CACHE_FILE.read_text().strip() except Exception: pass return None def save_cache_hash(hash_value: str): """保存哈希值到缓存""" try: CACHE_FILE.write_text(hash_value) except Exception as e: logger.warning(f"无法保存文档缓存: {e}") def generate_doc_html(openapi_spec: dict) -> str: """生成文档HTML内容""" # 将OpenAPI规范内嵌到HTML中 spec_json = json.dumps(openapi_spec, ensure_ascii=False, indent=2) api_version = openapi_spec.get("info", {}).get("version", "1.0.0") api_title = openapi_spec.get("info", {}).get("title", "API文档") html_content = f''' {api_title} - 接口文档
''' return html_content def generate_loading_html() -> str: """生成加载中的HTML页面""" return ''' 生成文档中...

正在生成API文档

请稍候,页面将自动刷新...

''' def should_regenerate(openapi_spec: dict) -> bool: """检查是否需要重新生成文档""" # 检查文档文件是否存在 if not DOC_FILE.exists(): return True # 检查本地资源是否存在 vendor_dir = STATIC_DIR / "vendor" if not (vendor_dir / "swagger-ui.css").exists() or not (vendor_dir / "swagger-ui-bundle.js").exists(): return True # 比较哈希值 current_hash = get_openapi_hash(openapi_spec) cached_hash = get_cached_hash() return current_hash != cached_hash def generate_docs(app) -> bool: """ 生成API文档 Args: app: FastAPI应用实例 Returns: bool: 是否重新生成了文档 """ try: # 获取OpenAPI规范 openapi_spec = app.openapi() # 检查是否需要重新生成 if not should_regenerate(openapi_spec): logger.info("API文档未变化,使用缓存") return False logger.info("检测到API变化,正在生成文档...") # 先写入加载页面 DOC_FILE.write_text(generate_loading_html(), encoding='utf-8') # 生成文档HTML doc_html = generate_doc_html(openapi_spec) # 写入文档文件 DOC_FILE.write_text(doc_html, encoding='utf-8') # 保存哈希值 current_hash = get_openapi_hash(openapi_spec) save_cache_hash(current_hash) logger.info("API文档生成完成") return True except Exception as e: logger.error(f"生成API文档失败: {e}") return False