| """ |
| 数据模型定义 |
| """ |
|
|
| import os |
| from dataclasses import dataclass |
| from typing import List, Dict, Any, Literal, TypedDict, Optional |
| from enum import Enum |
|
|
|
|
| def _get_default_max_tokens() -> int: |
| """ |
| 从环境变量获取默认的 max_tokens 值 |
| |
| Returns: |
| 默认的 max_tokens 值 |
| """ |
| try: |
| |
| env_value = os.getenv("MAX_TOKENS") |
| if env_value: |
| return int(env_value) |
| except (ValueError, TypeError): |
| pass |
|
|
| |
| return 4000 |
|
|
|
|
| def _get_default_temperature() -> float: |
| """ |
| 从环境变量获取默认的 temperature 值 |
| |
| Returns: |
| 默认的 temperature 值 |
| """ |
| try: |
| |
| env_value = os.getenv("TEMPERATURE") |
| if env_value: |
| return float(env_value) |
| except (ValueError, TypeError): |
| pass |
|
|
| |
| return 0.7 |
|
|
|
|
| class ChunkStrategy(Enum): |
| """文档分块策略""" |
| PARAGRAPH = "paragraph" |
| SEMANTIC = "semantic" |
| RECURSIVE = "recursive" |
| HYBRID = "hybrid" |
| FAST = "fast" |
|
|
|
|
| @dataclass |
| class SlideInfo: |
| """幻灯片信息数据类""" |
| page_number: int |
| title: str |
| content_points: List[str] |
| slide_type: Literal["title", "content", "conclusion"] |
| description: str |
| chart_config: Optional[Dict[str, Any]] = None |
|
|
| def to_dict(self) -> Dict[str, Any]: |
| """转换为字典格式""" |
| result = { |
| "page_number": self.page_number, |
| "title": self.title, |
| "content_points": self.content_points, |
| "slide_type": self.slide_type, |
| "description": self.description, |
| } |
|
|
| |
| if self.chart_config is not None: |
| result["chart_config"] = self.chart_config |
|
|
| return result |
|
|
| @classmethod |
| def from_dict(cls, data: Dict[str, Any]) -> "SlideInfo": |
| """从字典创建实例""" |
| return cls( |
| page_number=data.get("page_number", 1), |
| title=data.get("title", ""), |
| content_points=data.get("content_points", []), |
| slide_type=data.get("slide_type", "content"), |
| description=data.get("description", ""), |
| chart_config=data.get("chart_config"), |
| ) |
|
|
|
|
| class PPTState(TypedDict): |
| """PPT生成状态""" |
| document_chunks: List[str] |
| current_index: int |
| ppt_title: str |
| slides: List[Dict[str, Any]] |
| total_pages: int |
| page_count_mode: str |
| document_structure: Dict[str, Any] |
| accumulated_context: str |
| |
| project_topic: str |
| project_scenario: str |
| project_requirements: str |
| target_audience: str |
| custom_audience: str |
| ppt_style: str |
| custom_style_prompt: str |
| |
| min_pages: Optional[int] |
| max_pages: Optional[int] |
| fixed_pages: Optional[int] |
|
|
|
|
| @dataclass |
| class DocumentInfo: |
| """文档信息""" |
| title: str |
| content: str |
| file_path: str |
| file_type: str |
| encoding: str |
| size: int |
| |
| def to_dict(self) -> Dict[str, Any]: |
| """转换为字典格式""" |
| return { |
| "title": self.title, |
| "content": self.content, |
| "file_path": self.file_path, |
| "file_type": self.file_type, |
| "encoding": self.encoding, |
| "size": self.size, |
| } |
|
|
|
|
| @dataclass |
| class ProcessingConfig: |
| """处理配置""" |
| max_slides: int = 25 |
| min_slides: int = 5 |
| chunk_size: int = 3000 |
| chunk_overlap: int = 200 |
| chunk_strategy: ChunkStrategy = ChunkStrategy.PARAGRAPH |
| llm_model: str = "gpt-4o-mini" |
| llm_provider: str = "openai" |
| temperature: float = None |
| max_tokens: int = None |
| recursion_limit: Optional[int] = None |
| target_language: str = "zh" |
| |
| api_key: Optional[str] = None |
| base_url: Optional[str] = None |
| use_responses_api: bool = False |
| enable_reasoning: bool = False |
| reasoning_effort: str = "medium" |
|
|
| def __post_init__(self): |
| """后处理验证和默认值设置""" |
| |
| if self.max_tokens is None: |
| self.max_tokens = _get_default_max_tokens() |
|
|
| |
| if self.temperature is None: |
| self.temperature = _get_default_temperature() |
|
|
| |
| if self.min_slides > self.max_slides: |
| raise ValueError(f"最小页数({self.min_slides})不能大于最大页数({self.max_slides})") |
| if self.min_slides < 1: |
| raise ValueError("最小页数不能小于1") |
| if self.max_slides > 1000: |
| raise ValueError("最大页数不能超过1000") |
| if self.recursion_limit is not None and self.recursion_limit < 10: |
| raise ValueError("递归限制不能小于10") |
|
|
|
|
|
|
| @property |
| def slides_range(self) -> str: |
| """获取页数范围的字符串表示""" |
| if self.min_slides == self.max_slides: |
| return f"{self.min_slides}页" |
| return f"{self.min_slides}-{self.max_slides}页" |
| |
| def to_dict(self) -> Dict[str, Any]: |
| """转换为字典格式""" |
| return { |
| "max_slides": self.max_slides, |
| "min_slides": self.min_slides, |
| "slides_range": self.slides_range, |
| "chunk_size": self.chunk_size, |
| "chunk_overlap": self.chunk_overlap, |
| "chunk_strategy": self.chunk_strategy.value, |
| "llm_model": self.llm_model, |
| "llm_provider": self.llm_provider, |
| "temperature": self.temperature, |
| "max_tokens": self.max_tokens, |
| "recursion_limit": self.recursion_limit, |
| "target_language": self.target_language, |
| "use_responses_api": self.use_responses_api, |
| "enable_reasoning": self.enable_reasoning, |
| "reasoning_effort": self.reasoning_effort, |
| } |
|
|
|
|
| @dataclass |
| class PPTOutline: |
| """PPT大纲结果""" |
| title: str |
| total_pages: int |
| page_count_mode: str |
| slides: List[SlideInfo] |
| |
| def to_dict(self) -> Dict[str, Any]: |
| """转换为字典格式""" |
| return { |
| "title": self.title, |
| "total_pages": self.total_pages, |
| "page_count_mode": self.page_count_mode, |
| "slides": [slide.to_dict() for slide in self.slides], |
| } |
| |
| @classmethod |
| def from_dict(cls, data: Dict[str, Any]) -> "PPTOutline": |
| """从字典创建实例""" |
| slides = [SlideInfo.from_dict(slide_data) for slide_data in data.get("slides", [])] |
| return cls( |
| title=data.get("title", ""), |
| total_pages=data.get("total_pages", 0), |
| page_count_mode=data.get("page_count_mode", "final"), |
| slides=slides, |
| ) |
|
|