智能文档生成与维护系统:AI驱动的技术文档自动化

摘要

技术文档是软件开发过程中不可或缺的组成部分,但传统的文档编写和维护工作往往耗时且容易过时。本文将深入探讨如何利用AI技术构建智能文档生成与维护系统,从API文档自动生成到用户手册智能编写,从代码注释提取到文档版本管理,全面提升文档质量和开发效率。

目录

  1. 智能文档系统概述
  2. API文档自动生成
  3. 代码注释智能提取
  4. 用户手册智能编写
  5. 文档版本管理
  6. 多语言文档生成
  7. 文档质量评估
  8. 实时文档更新
  9. 实战案例分析
  10. 总结与最佳实践

智能文档系统概述

文档生成架构

智能文档系统
代码分析引擎
文档生成器
内容管理器
发布系统
语法解析
注释提取
API分析
API文档生成
用户手册生成
技术规范生成
版本控制
内容审核
质量评估
静态站点生成
PDF导出
在线发布

核心文档生成框架

import ast
import re
import json
import markdown
from typing import Dict, List, Any, Optional, Union
from dataclasses import dataclass, asdict
from abc import ABC, abstractmethod
from pathlib import Path
import time

@dataclass
class DocumentSection:
    """文档章节数据结构"""
    title: str
    content: str
    level: int
    section_type: str
    metadata: Dict[str, Any]
    subsections: List['DocumentSection']

@dataclass
class APIEndpoint:
    """API端点信息"""
    path: str
    method: str
    summary: str
    description: str
    parameters: List[Dict[str, Any]]
    responses: Dict[str, Dict[str, Any]]
    examples: List[Dict[str, Any]]
    tags: List[str]

class DocumentGenerator(ABC):
    """文档生成器基类"""
    
    @abstractmethod
    def generate(self, source_data: Any) -> str:
        """生成文档内容"""
        pass
    
    @abstractmethod
    def get_template(self) -> str:
        """获取文档模板"""
        pass

class CodeAnalyzer:
    """代码分析器"""
    
    def __init__(self):
        self.functions = []
        self.classes = []
        self.modules = []
        self.api_endpoints = []
    
    def analyze_python_file(self, file_path: str) -> Dict[str, Any]:
        """分析Python文件"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            tree = ast.parse(content)
            
            analysis = {
                'file_path': file_path,
                'module_docstring': ast.get_docstring(tree),
                'functions': self._extract_functions(tree),
                'classes': self._extract_classes(tree),
                'imports': self._extract_imports(tree),
                'constants': self._extract_constants(tree),
                'api_routes': self._extract_api_routes(content)
            }
            
            return analysis
            
        except Exception as e:
            return {'error': f'分析文件失败: {e}'}
    
    def _extract_functions(self, tree: ast.AST) -> List[Dict[str, Any]]:
        """提取函数信息"""
        functions = []
        
        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                func_info = {
                    'name': node.name,
                    'docstring': ast.get_docstring(node),
                    'args': self._extract_function_args(node),
                    'returns': self._extract_return_annotation(node),
                    'decorators': self._extract_decorators(node),
                    'line_number': node.lineno,
                    'is_async': isinstance(node, ast.AsyncFunctionDef),
                    'examples': self._extract_examples_from_docstring(ast.get_docstring(node))
                }
                functions.append(func_info)
        
        return functions
    
    def _extract_classes(self, tree: ast.AST) -> List[Dict[str, Any]]:
        """提取类信息"""
        classes = []
        
        for node in ast.walk(tree):
            if isinstance(node, ast.ClassDef):
                class_info = {
                    'name': node.name,
                    'docstring': ast.get_docstring(node),
                    'bases': [self._get_name(base) for base in node.bases],
                    'methods': [],
                    'attributes': [],
                    'line_number': node.lineno,
                    'decorators': self._extract_decorators(node)
                }
                
                # 提取方法
                for item in node.body:
                    if isinstance(item, ast.FunctionDef):
                        method_info = {
                            'name': item.name,
                            'docstring': ast.get_docstring(item),
                            'args': self._extract_function_args(item),
                            'returns': self._extract_return_annotation(item),
                            'is_property': self._is_property(item),
                            'is_static': self._is_static_method(item),
                            'is_class_method': self._is_class_method(item),
                            'visibility': self._get_method_visibility(item.name)
                        }
                        class_info['methods'].append(method_info)
                    
                    elif isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
                        # 类属性
                        attr_info = {
                            'name': item.target.id,
                            'type': self._get_annotation_string(item.annotation),
                            'line_number': item.lineno
                        }
                        class_info['attributes'].append(attr_info)
                
                classes.append(class_info)
        
        return classes
    
    def _extract_function_args(self, func_node: ast.FunctionDef) -> List[Dict[str, Any]]:
        """提取函数参数"""
        args = []
        
        # 普通参数
        for arg in func_node.args.args:
            arg_info = {
                'name': arg.arg,
                'type': self._get_annotation_string(arg.annotation) if arg.annotation else None,
                'kind': 'positional'
            }
            args.append(arg_info)
        
        # 默认参数
        defaults = func_node.args.defaults
        if defaults:
            default_offset = len(func_node.args.args) - len(defaults)
            for i, default in enumerate(defaults):
                if default_offset + i < len(args):
                    args[default_offset + i]['default'] = self._get_default_value(default)
        
        # *args
        if func_node.args.vararg:
            args.append({
                'name': func_node.args.vararg.arg,
                'type': self._get_annotation_string(func_node.args.vararg.annotation) if func_node.args.vararg.annotation else None,
                'kind': 'var_positional'
            })
        
        # **kwargs
        if func_node.args.kwarg:
            args.append({
                'name': func_node.args.kwarg.arg,
                'type': self._get_annotation_string(func_node.args.kwarg.annotation) if func_node.args.kwarg.annotation else None,
                'kind': 'var_keyword'
            })
        
        return args
    
    def _extract_return_annotation(self, func_node: ast.FunctionDef) -> Optional[str]:
        """提取返回值注解"""
        if func_node.returns:
            return self._get_annotation_string(func_node.returns)
        return None
    
    def _extract_decorators(self, node: Union[ast.FunctionDef, ast.ClassDef]) -> List[str]:
        """提取装饰器"""
        decorators = []
        for decorator in node.decorator_list:
            decorators.append(self._get_name(decorator))
        return decorators
    
    def _extract_examples_from_docstring(self, docstring: Optional[str]) -> List[str]:
        """从文档字符串中提取示例"""
        if not docstring:
            return []
        
        examples = []
        lines = docstring.split('\n')
        in_example = False
        current_example = []
        
        for line in lines:
            stripped = line.strip()
            if stripped.startswith('>>>') or stripped.startswith('Example'):
                in_example = True
                if current_example:
                    examples.append('\n'.join(current_example))
                    current_example = []
                current_example.append(line)
            elif in_example:
                if stripped == '' and current_example:
                    examples.append('\n'.join(current_example))
                    current_example = []
                    in_example = False
                else:
                    current_example.append(line)
        
        if current_example:
            examples.append('\n'.join(current_example))
        
        return examples
    
    def _extract_api_routes(self, content: str) -> List[Dict[str, Any]]:
        """提取API路由信息"""
        routes = []
        
        # 查找Flask路由
        flask_pattern = r'@app\.route\([\'"]([^\'"]+)[\'"](?:,\s*methods\s*=\s*\[([^\]]+)\])?\)'
        flask_matches = re.finditer(flask_pattern, content)
        
        for match in flask_matches:
            route_path = match.group(1)
            methods = match.group(2)
            if methods:
                methods = [m.strip().strip('\'"') for m in methods.split(',')]
            else:
                methods = ['GET']
            
            routes.append({
                'path': route_path,
                'methods': methods,
                'framework': 'flask'
            })
        
        # 查找FastAPI路由
        fastapi_pattern = r'@app\.(get|post|put|delete|patch)\([\'"]([^\'"]+)[\'"]'
        fastapi_matches = re.finditer(fastapi_pattern, content)
        
        for match in fastapi_matches:
            method = match.group(1).upper()
            route_path = match.group(2)
            
            routes.append({
                'path': route_path,
                'methods': [method],
                'framework': 'fastapi'
            })
        
        return routes
    
    def _get_name(self, node: ast.AST) -> str:
        """获取节点名称"""
        if isinstance(node, ast.Name):
            return node.id
        elif isinstance(node, ast.Attribute):
            return f"{self._get_name(node.value)}.{node.attr}"
        elif isinstance(node, ast.Call):
            return self._get_name(node.func)
        else:
            return str(node)
    
    def _get_annotation_string(self, annotation: ast.AST) -> str:
        """获取注解字符串"""
        if isinstance(annotation, ast.Name):
            return annotation.id
        elif isinstance(annotation, ast.Attribute):
            return f"{self._get_name(annotation.value)}.{annotation.attr}"
        elif isinstance(annotation, ast.Subscript):
            return f"{self._get_name(annotation.value)}[{self._get_name(annotation.slice)}]"
        else:
            return str(annotation)
    
    def _get_default_value(self, node: ast.AST) -> str:
        """获取默认值"""
        if isinstance(node, ast.Constant):
            return repr(node.value)
        elif isinstance(node, ast.Name):
            return node.id
        else:
            return str(node)
    
    def _is_property(self, func_node: ast.FunctionDef) -> bool:
        """判断是否为属性"""
        return any(self._get_name(d) == 'property' for d in func_node.decorator_list)
    
    def _is_static_method(self, func_node: ast.FunctionDef) -> bool:
        """判断是否为静态方法"""
        return any(self._get_name(d) == 'staticmethod' for d in func_node.decorator_list)
    
    def _is_class_method(self, func_node: ast.FunctionDef) -> bool:
        """判断是否为类方法"""
        return any(self._get_name(d) == 'classmethod' for d in func_node.decorator_list)
    
    def _get_method_visibility(self, method_name: str) -> str:
        """获取方法可见性"""
        if method_name.startswith('__') and method_name.endswith('__'):
            return 'magic'
        elif method_name.startswith('_'):
            return 'private'
        else:
            return 'public'
    
    def _extract_imports(self, tree: ast.AST) -> List[Dict[str, Any]]:
        """提取导入信息"""
        imports = []
        
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    imports.append({
                        'type': 'import',
                        'module': alias.name,
                        'alias': alias.asname,
                        'line': node.lineno
                    })
            elif isinstance(node, ast.ImportFrom):
                for alias in node.names:
                    imports.append({
                        'type': 'from_import',
                        'module': node.module,
                        'name': alias.name,
                        'alias': alias.asname,
                        'line': node.lineno
                    })
        
        return imports
    
    def _extract_constants(self, tree: ast.AST) -> List[Dict[str, Any]]:
        """提取常量"""
        constants = []
        
        for node in ast.walk(tree):
            if isinstance(node, ast.Assign):
                for target in node.targets:
                    if isinstance(target, ast.Name) and target.id.isupper():
                        constants.append({
                            'name': target.id,
                            'value': self._get_default_value(node.value),
                            'line': node.lineno
                        })
        
        return constants

class APIDocumentGenerator(DocumentGenerator):
    """API文档生成器"""
    
    def __init__(self):
        self.template_engine = MarkdownTemplateEngine()
    
    def generate(self, analysis_data: Dict[str, Any]) -> str:
        """生成API文档"""
        sections = []
        
        # 生成概述
        overview = self._generate_overview(analysis_data)
        sections.append(overview)
        
        # 生成API端点文档
        if 'api_routes' in analysis_data:
            api_section = self._generate_api_endpoints(analysis_data)
            sections.append(api_section)
        
        # 生成数据模型文档
        if 'classes' in analysis_data:
            models_section = self._generate_data_models(analysis_data['classes'])
            sections.append(models_section)
        
        # 生成工具函数文档
        if 'functions' in analysis_data:
            utils_section = self._generate_utility_functions(analysis_data['functions'])
            sections.append(utils_section)
        
        return self._combine_sections(sections)
    
    def _generate_overview(self, analysis_data: Dict[str, Any]) -> DocumentSection:
        """生成概述部分"""
        module_doc = analysis_data.get('module_docstring', '暂无描述')
        
        content = f"""
# API 文档

## 概述

{module_doc}

## 快速开始

```python
# 安装依赖
pip install -r requirements.txt

# 启动服务
python app.py

基础信息

  • 基础URL: http://localhost:5000

  • 认证方式: Bearer Token

  • 数据格式: JSON

  • 字符编码: UTF-8
    “”"

      return DocumentSection(
          title="概述",
          content=content,
          level=1,
          section_type="overview",
          metadata={'generated_at': time.time()},
          subsections=[]
      )
    

    def _generate_api_endpoints(self, analysis_data: Dict[str, Any]) -> DocumentSection:
    “”“生成API端点文档”“”
    routes = analysis_data.get(‘api_routes’, [])
    functions = analysis_data.get(‘functions’, [])

      content = "# API 端点\n\n"
      
      for route in routes:
          # 查找对应的函数
          route_func = self._find_route_function(route, functions)
          
          content += f"## {' | '.join(route['methods'])} {route['path']}\n\n"
          
          if route_func:
              if route_func['docstring']:
                  content += f"{route_func['docstring']}\n\n"
              
              # 参数文档
              if route_func['args']:
                  content += "### 参数\n\n"
                  content += "| 参数名 | 类型 | 必需 | 描述 |\n"
                  content += "|--------|------|------|------|\n"
                  
                  for arg in route_func['args']:
                      if arg['name'] not in ['self', 'request']:
                          required = "是" if 'default' not in arg else "否"
                          arg_type = arg.get('type', 'Any')
                          content += f"| {arg['name']} | {arg_type} | {required} | - |\n"
                  content += "\n"
              
              # 示例
              if route_func['examples']:
                  content += "### 示例\n\n"
                  for example in route_func['examples']:
                      content += f"```python\n{example}\n```\n\n"
          
          # 响应示例
          content += "### 响应示例\n\n"
          content += "```json\n"
          content += "{\n"
          content += '  "status": "success",\n'
          content += '  "data": {},\n'
          content += '  "message": "操作成功"\n'
          content += "}\n"
          content += "```\n\n"
      
      return DocumentSection(
          title="API端点",
          content=content,
          level=1,
          section_type="api_endpoints",
          metadata={'endpoint_count': len(routes)},
          subsections=[]
      )
    

    def _generate_data_models(self, classes: List[Dict[str, Any]]) -> DocumentSection:
    “”“生成数据模型文档”“”
    content = “# 数据模型\n\n”

      for cls in classes:
          content += f"## {cls['name']}\n\n"
          
          if cls['docstring']:
              content += f"{cls['docstring']}\n\n"
          
          # 属性
          if cls['attributes']:
              content += "### 属性\n\n"
              content += "| 属性名 | 类型 | 描述 |\n"
              content += "|--------|------|------|\n"
              
              for attr in cls['attributes']:
                  content += f"| {attr['name']} | {attr.get('type', 'Any')} | - |\n"
              content += "\n"
          
          # 方法
          public_methods = [m for m in cls['methods'] if m['visibility'] == 'public']
          if public_methods:
              content += "### 方法\n\n"
              
              for method in public_methods:
                  content += f"#### {method['name']}\n\n"
                  
                  if method['docstring']:
                      content += f"{method['docstring']}\n\n"
                  
                  # 方法签名
                  args_str = ', '.join([
                      f"{arg['name']}: {arg.get('type', 'Any')}"
                      for arg in method['args'] if arg['name'] != 'self'
                  ])
                  return_type = method.get('returns', 'None')
                  
                  content += f"```python\n"
                  content += f"def {method['name']}({args_str}) -> {return_type}\n"
                  content += f"```\n\n"
      
      return DocumentSection(
          title="数据模型",
          content=content,
          level=1,
          section_type="data_models",
          metadata={'model_count': len(classes)},
          subsections=[]
      )
    

    def _generate_utility_functions(self, functions: List[Dict[str, Any]]) -> DocumentSection:
    “”“生成工具函数文档”“”
    content = “# 工具函数\n\n”

      # 过滤掉路由函数
      utility_functions = [f for f in functions if not self._is_route_function(f)]
      
      for func in utility_functions:
          content += f"## {func['name']}\n\n"
          
          if func['docstring']:
              content += f"{func['docstring']}\n\n"
          
          # 函数签名
          args_str = ', '.join([
              f"{arg['name']}: {arg.get('type', 'Any')}"
              for arg in func['args']
          ])
          return_type = func.get('returns', 'None')
          
          content += f"```python\n"
          if func['is_async']:
              content += f"async def {func['name']}({args_str}) -> {return_type}\n"
          else:
              content += f"def {func['name']}({args_str}) -> {return_type}\n"
          content += f"```\n\n"
          
          # 参数说明
          if func['args']:
              content += "### 参数\n\n"
              content += "| 参数名 | 类型 | 描述 |\n"
              content += "|--------|------|------|\n"
              
              for arg in func['args']:
                  content += f"| {arg['name']} | {arg.get('type', 'Any')} | - |\n"
              content += "\n"
          
          # 示例
          if func['examples']:
              content += "### 示例\n\n"
              for example in func['examples']:
                  content += f"```python\n{example}\n```\n\n"
      
      return DocumentSection(
          title="工具函数",
          content=content,
          level=1,
          section_type="utility_functions",
          metadata={'function_count': len(utility_functions)},
          subsections=[]
      )
    

    def find_route_function(self, route: Dict[str, Any], functions: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
    “”“查找路由对应的函数”“”
    # 简化的匹配逻辑
    route_path = route[‘path’].replace(‘/’, '
    ‘).replace(’<‘, ‘’).replace(’>‘, ‘’).strip(’_')

      for func in functions:
          if route_path in func['name'] or func['name'] in route_path:
              return func
      
      return None
    

    def _is_route_function(self, func: Dict[str, Any]) -> bool:
    “”“判断是否为路由函数”“”
    route_decorators = [‘route’, ‘get’, ‘post’, ‘put’, ‘delete’, ‘patch’]
    return any(decorator in func[‘decorators’] for decorator in route_decorators)

    def _combine_sections(self, sections: List[DocumentSection]) -> str:
    “”“合并文档章节”“”
    content = “”
    for section in sections:
    content += section.content + “\n\n”
    return content.strip()

    def get_template(self) -> str:
    “”“获取API文档模板”“”
    return “”"

{title}

概述

{overview}

API端点

{endpoints}

数据模型

{models}

工具函数

{utilities}

错误码

{error_codes}

更新日志

{changelog}
“”"

class MarkdownTemplateEngine:
“”“Markdown模板引擎”“”

def __init__(self):
    self.templates = {}

def register_template(self, name: str, template: str):
    """注册模板"""
    self.templates[name] = template

def render(self, template_name: str, context: Dict[str, Any]) -> str:
    """渲染模板"""
    if template_name not in self.templates:
        raise ValueError(f"模板 {template_name} 不存在")
    
    template = self.templates[template_name]
    
    # 简单的模板替换
    for key, value in context.items():
        placeholder = f"{{{key}}}"
        template = template.replace(placeholder, str(value))
    
    return template

def render_string(self, template_string: str, context: Dict[str, Any]) -> str:
    """渲染模板字符串"""
    for key, value in context.items():
        placeholder = f"{{{key}}}"
        template_string = template_string.replace(placeholder, str(value))
    
    return template_string

class DocumentationSystem:
“”“文档系统”“”

def __init__(self):
    self.analyzer = CodeAnalyzer()
    self.generators = {
        'api': APIDocumentGenerator(),
        'user_manual': None,  # 后续实现
        'technical_spec': None  # 后续实现
    }
    self.template_engine = MarkdownTemplateEngine()
    self.output_formats = ['markdown', 'html', 'pdf']

def generate_documentation(self, source_path: str, doc_type: str = 'api', output_format: str = 'markdown') -> str:
    """生成文档"""
    # 分析源代码
    analysis = self.analyzer.analyze_python_file(source_path)
    
    if 'error' in analysis:
        return f"# 错误\n\n{analysis['error']}"
    
    # 生成文档
    generator = self.generators.get(doc_type)
    if not generator:
        return f"# 错误\n\n不支持的文档类型: {doc_type}"
    
    content = generator.generate(analysis)
    
    # 格式转换
    if output_format == 'html':
        content = self._convert_to_html(content)
    elif output_format == 'pdf':
        content = self._convert_to_pdf(content)
    
    return content

def batch_generate(self, source_dir: str, output_dir: str, doc_type: str = 'api'):
    """批量生成文档"""
    source_path = Path(source_dir)
    output_path = Path(output_dir)
    
    # 确保输出目录存在
    output_path.mkdir(parents=True, exist_ok=True)
    
    # 处理所有Python文件
    for py_file in source_path.rglob('*.py'):
        if py_file.name.startswith('__'):
            continue
        
        print(f"处理文件: {py_file}")
        
        # 生成文档
        doc_content = self.generate_documentation(str(py_file), doc_type)
        
        # 保存文档
        output_file = output_path / f"{py_file.stem}_doc.md"
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(doc_content)
        
        print(f"文档已保存: {output_file}")

def _convert_to_html(self, markdown_content: str) -> str:
    """转换为HTML格式"""
    try:
        import markdown
        html = markdown.markdown(markdown_content, extensions=['tables', 'codehilite'])
        
        # 添加HTML模板
        html_template = """
API 文档 {content} """ return html_template.format(content=html) except ImportError: return f"# 错误\n\n需要安装markdown库: pip install markdown"
def _convert_to_pdf(self, markdown_content: str) -> str:
    """转换为PDF格式"""
    # 这里只是示例,实际需要使用如weasyprint等库
    return f"# PDF转换\n\n需要实现PDF转换功能\n\n{markdown_content[:200]}..."

使用示例

def demo_documentation_system():
“”“演示文档系统”“”

# 创建示例Python文件
sample_code = '''

“”"
用户管理API模块

提供用户注册、登录、信息管理等功能
“”"

from flask import Flask, request, jsonify
from typing import Dict, List, Optional

app = Flask(name)

class User:
“”“用户数据模型”“”

def __init__(self, username: str, email: str, age: int = 18):
    """
    初始化用户对象
    
    Args:
        username: 用户名
        email: 邮箱地址
        age: 年龄,默认18岁
    """
    self.username = username
    self.email = email
    self.age = age
    self.is_active = True

def to_dict(self) -> Dict[str, any]:
    """
    转换为字典格式
    
    Returns:
        用户信息字典
    
    Example:
        >>> user = User("test", "test@example.com")
        >>> user.to_dict()
        {'username': 'test', 'email': 'test@example.com', 'age': 18}
    """
    return {
        'username': self.username,
        'email': self.email,
        'age': self.age,
        'is_active': self.is_active
    }

def validate_email(self) -> bool:
    """验证邮箱格式"""
    return '@' in self.email and '.' in self.email

@app.route(‘/users’, methods=[‘POST’])
def create_user():
“”"
创建新用户

接收用户信息并创建新用户账户
"""
data = request.get_json()
user = User(
    username=data['username'],
    email=data['email'],
    age=data.get('age', 18)
)

if not user.validate_email():
    return jsonify({'error': '邮箱格式不正确'}), 400

return jsonify({
    'status': 'success',
    'data': user.to_dict(),
    'message': '用户创建成功'
}), 201

@app.route(‘/users/int:user_id’, methods=[‘GET’])
def get_user(user_id: int):
“”"
获取用户信息

根据用户ID获取用户详细信息
"""
# 模拟数据库查询
user_data = {
    'id': user_id,
    'username': f'user_{user_id}',
    'email': f'user_{user_id}@example.com',
    'age': 25
}

return jsonify({
    'status': 'success',
    'data': user_data
})

def validate_user_data(data: Dict[str, any]) -> List[str]:
“”"
验证用户数据

Args:
    data: 用户数据字典

Returns:
    错误信息列表,空列表表示验证通过

Example:
    >>> validate_user_data({'username': 'test'})
    ['缺少邮箱字段']
"""
errors = []

if 'username' not in data:
    errors.append('缺少用户名字段')

if 'email' not in data:
    errors.append('缺少邮箱字段')

return errors

if name == ‘main’:
app.run(debug=True)
‘’’

# 保存示例文件
with open('sample_api.py', 'w', encoding='utf-8') as f:
    f.write(sample_code)

# 创建文档系统
doc_system = DocumentationSystem()

# 生成API文档
api_doc = doc_system.generate_documentation('sample_api.py', 'api', 'markdown')

print("生成的API文档:")
print("=" * 50)
print(api_doc)

# 保存文档
with open('api_documentation.md', 'w', encoding='utf-8') as f:
    f.write(api_doc)

print("\n文档已保存到 api_documentation.md")

# 生成HTML版本
html_doc = doc_system.generate_documentation('sample_api.py', 'api', 'html')
with open('api_documentation.html', 'w', encoding='utf-8') as f:
    f.write(html_doc)

print("HTML文档已保存到 api_documentation.html")

if name == “main”:
demo_documentation_system()


## API文档自动生成

### OpenAPI规范生成器

```python
class OpenAPIGenerator:
    """OpenAPI规范生成器"""
    
    def __init__(self):
        self.spec = {
            'openapi': '3.0.0',
            'info': {
                'title': 'API Documentation',
                'version': '1.0.0',
                'description': '自动生成的API文档'
            },
            'paths': {},
            'components': {
                'schemas': {},
                'responses': {},
                'parameters': {}
            }
        }
    
    def generate_from_analysis(self, analysis_data: Dict[str, Any]) -> Dict[str, Any]:
        """从代码分析结果生成OpenAPI规范"""
        
        # 设置基本信息
        self._set_basic_info(analysis_data)
        
        # 生成路径
        self._generate_paths(analysis_data)
        
        # 生成数据模型
        self._generate_schemas(analysis_data)
        
        return self.spec
    
    def _set_basic_info(self, analysis_data: Dict[str, Any]):
        """设置基本信息"""
        module_doc = analysis_data.get('module_docstring', '')
        if module_doc:
            lines = module_doc.split('\n')
            if lines:
                self.spec['info']['title'] = lines[0].strip()
                if len(lines) > 1:
                    self.spec['info']['description'] = '\n'.join(lines[1:]).strip()
    
    def _generate_paths(self, analysis_data: Dict[str, Any]):
        """生成路径信息"""
        routes = analysis_data.get('api_routes', [])
        functions = analysis_data.get('functions', [])
        
        for route in routes:
            path = route['path']
            methods = route['methods']
            
            if path not in self.spec['paths']:
                self.spec['paths'][path] = {}
            
            # 查找对应的函数
            route_func = self._find_route_function(route, functions)
            
            for method in methods:
                method_lower = method.lower()
                
                operation = {
                    'summary': f'{method} {path}',
                    'description': '',
                    'responses': {
                        '200': {
                            'description': '成功响应',
                            'content': {
                                'application/json': {
                                    'schema': {
                                        'type': 'object',
                                        'properties': {
                                            'status': {'type': 'string'},
                                            'data': {'type': 'object'},
                                            'message': {'type': 'string'}
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                
                if route_func:
                    if route_func['docstring']:
                        operation['description'] = route_func['docstring']
                    
                    # 添加参数
                    if route_func['args']:
                        operation['parameters'] = []
                        for arg in route_func['args']:
                            if arg['name'] not in ['self', 'request']:
                                param = {
                                    'name': arg['name'],
                                    'in': 'query' if method_lower == 'get' else 'body',
                                    'required': 'default' not in arg,
                                    'schema': {
                                        'type': self._python_type_to_openapi(arg.get('type', 'string'))
                                    }
                                }
                                operation['parameters'].append(param)
                
                self.spec['paths'][path][method_lower] = operation
    
    def _generate_schemas(self, analysis_data: Dict[str, Any]):
        """生成数据模型"""
        classes = analysis_data.get('classes', [])
        
        for cls in classes:
            schema = {
                'type': 'object',
                'properties': {},
                'required': []
            }
            
            if cls['docstring']:
                schema['description'] = cls['docstring']
            
            # 添加属性
            for attr in cls['attributes']:
                schema['properties'][attr['name']] = {
                    'type': self._python_type_to_openapi(attr.get('type', 'string'))
                }
            
            # 从__init__方法推断属性
            init_method = next((m for m in cls['methods'] if m['name'] == '__init__'), None)
            if init_method:
                for arg in init_method['args']:
                    if arg['name'] not in ['self']:
                        schema['properties'][arg['name']] = {
                            'type': self._python_type_to_openapi(arg.get('type', 'string'))
                        }
                        
                        if 'default' not in arg:
                            schema['required'].append(arg['name'])
            
            self.spec['components']['schemas'][cls['name']] = schema
    
    def _python_type_to_openapi(self, python_type: str) -> str:
        """Python类型转OpenAPI类型"""
        type_mapping = {
            'str': 'string',
            'int': 'integer',
            'float': 'number',
            'bool': 'boolean',
            'list': 'array',
            'dict': 'object',
            'List': 'array',
            'Dict': 'object',
            'Optional': 'string'
        }
        
        # 处理复杂类型
        if '[' in python_type:
            base_type = python_type.split('[')[0]
            return type_mapping.get(base_type, 'string')
        
        return type_mapping.get(python_type, 'string')
    
    def _find_route_function(self, route: Dict[str, Any], functions: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
        """查找路由对应的函数"""
        # 简化的匹配逻辑
        for func in functions:
            if any(decorator in str(func['decorators']) for decorator in ['route', 'get', 'post', 'put', 'delete']):
                return func
        return None
    
    def export_yaml(self) -> str:
        """导出为YAML格式"""
        try:
            import yaml
            return yaml.dump(self.spec, default_flow_style=False, allow_unicode=True)
        except ImportError:
            return "需要安装PyYAML: pip install PyYAML"
    
    def export_json(self) -> str:
        """导出为JSON格式"""
        return json.dumps(self.spec, indent=2, ensure_ascii=False)

# 使用示例
def demo_openapi_generation():
    """演示OpenAPI生成"""
    
    # 模拟代码分析结果
    analysis_data = {
        'module_docstring': '用户管理API\n提供用户相关的CRUD操作',
        'api_routes': [
            {'path': '/users', 'methods': ['GET', 'POST'], 'framework': 'flask'},
            {'path': '/users/{id}', 'methods': ['GET', 'PUT', 'DELETE'], 'framework': 'flask'}
        ],
        'functions': [
            {
                'name': 'get_users',
                'docstring': '获取用户列表',
                'args': [
                    {'name': 'page', 'type': 'int', 'default': 1},
                    {'name': 'limit', 'type': 'int', 'default': 10}
                ],
                'decorators': ['@app.route']
            },
            {
                'name': 'create_user',
                'docstring': '创建新用户',
                'args': [
                    {'name': 'username', 'type': 'str'},
                    {'name': 'email', 'type': 'str'},
                    {'name': 'age', 'type': 'int', 'default': 18}
                ],
                'decorators': ['@app.route']
            }
        ],
        'classes': [
            {
                'name': 'User',
                'docstring': '用户数据模型',
                'attributes': [
                    {'name': 'id', 'type': 'int'},
                    {'name': 'username', 'type': 'str'},
                    {'name': 'email', 'type': 'str'}
                ],
                'methods': [
                    {
                        'name': '__init__',
                        'args': [
                            {'name': 'self'},
                            {'name': 'username', 'type': 'str'},
                            {'name': 'email', 'type': 'str'},
                            {'name': 'age', 'type': 'int', 'default': 18}
                        ]
                    }
                ]
            }
        ]
    }
    
    # 生成OpenAPI规范
    generator = OpenAPIGenerator()
    spec = generator.generate_from_analysis(analysis_data)
    
    print("生成的OpenAPI规范:")
    print("=" * 50)
    print(generator.export_json())
    
    # 保存规范文件
    with open('openapi.json', 'w', encoding='utf-8') as f:
        f.write(generator.export_json())
    
    print("\nOpenAPI规范已保存到 openapi.json")

if __name__ == "__main__":
    demo_openapi_generation()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CarlowZJ

我的文章对你有用的话,可以支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值