From dbdc4c98ad3421ebf7bffa005fa8d5eda8a87243 Mon Sep 17 00:00:00 2001 From: 13315423919 <13315423919@qq.com> Date: Fri, 7 Nov 2025 09:05:07 +0800 Subject: [PATCH] Add File --- src/landppt/api/models.py | 285 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/landppt/api/models.py diff --git a/src/landppt/api/models.py b/src/landppt/api/models.py new file mode 100644 index 0000000..93706b4 --- /dev/null +++ b/src/landppt/api/models.py @@ -0,0 +1,285 @@ +""" +Pydantic models for API requests and responses +""" + +from typing import List, Optional, Dict, Any, Union, Literal +from pydantic import BaseModel, Field +import time +import uuid + +# OpenAI Compatible Models + +class ChatMessage(BaseModel): + role: Literal["system", "user", "assistant"] = Field(..., description="The role of the message author") + content: str = Field(..., description="The content of the message") + name: Optional[str] = Field(None, description="The name of the author of this message") + +class ChatCompletionRequest(BaseModel): + model: str = Field(..., description="ID of the model to use") + messages: List[ChatMessage] = Field(..., description="A list of messages comprising the conversation so far") + temperature: Optional[float] = Field(1.0, ge=0, le=2, description="Sampling temperature") + max_tokens: Optional[int] = Field(None, gt=0, description="Maximum number of tokens to generate") + top_p: Optional[float] = Field(1.0, ge=0, le=1, description="Nucleus sampling parameter") + n: Optional[int] = Field(1, ge=1, le=128, description="Number of chat completion choices to generate") + stream: Optional[bool] = Field(False, description="Whether to stream back partial progress") + stop: Optional[Union[str, List[str]]] = Field(None, description="Up to 4 sequences where the API will stop generating") + presence_penalty: Optional[float] = Field(0, ge=-2, le=2, description="Presence penalty parameter") + frequency_penalty: Optional[float] = Field(0, ge=-2, le=2, description="Frequency penalty parameter") + user: Optional[str] = Field(None, description="A unique identifier representing your end-user") + +class CompletionRequest(BaseModel): + model: str = Field(..., description="ID of the model to use") + prompt: Union[str, List[str]] = Field(..., description="The prompt(s) to generate completions for") + temperature: Optional[float] = Field(1.0, ge=0, le=2, description="Sampling temperature") + max_tokens: Optional[int] = Field(16, gt=0, description="Maximum number of tokens to generate") + top_p: Optional[float] = Field(1.0, ge=0, le=1, description="Nucleus sampling parameter") + n: Optional[int] = Field(1, ge=1, le=128, description="Number of completions to generate") + stream: Optional[bool] = Field(False, description="Whether to stream back partial progress") + stop: Optional[Union[str, List[str]]] = Field(None, description="Up to 4 sequences where the API will stop generating") + presence_penalty: Optional[float] = Field(0, ge=-2, le=2, description="Presence penalty parameter") + frequency_penalty: Optional[float] = Field(0, ge=-2, le=2, description="Frequency penalty parameter") + user: Optional[str] = Field(None, description="A unique identifier representing your end-user") + +class Usage(BaseModel): + prompt_tokens: int + completion_tokens: int + total_tokens: int + +class ChatCompletionChoice(BaseModel): + index: int + message: ChatMessage + finish_reason: Optional[str] = None + +class CompletionChoice(BaseModel): + text: str + index: int + finish_reason: Optional[str] = None + +class ChatCompletionResponse(BaseModel): + id: str = Field(default_factory=lambda: f"chatcmpl-{uuid.uuid4().hex[:29]}") + object: str = "chat.completion" + created: int = Field(default_factory=lambda: int(time.time())) + model: str + choices: List[ChatCompletionChoice] + usage: Usage + +class CompletionResponse(BaseModel): + id: str = Field(default_factory=lambda: f"cmpl-{uuid.uuid4().hex[:29]}") + object: str = "text_completion" + created: int = Field(default_factory=lambda: int(time.time())) + model: str + choices: List[CompletionChoice] + usage: Usage + +# LandPPT Specific Models + +class PPTScenario(BaseModel): + id: str + name: str + description: str + icon: str + template_config: Dict[str, Any] + +class PPTGenerationRequest(BaseModel): + scenario: str = Field(..., description="PPT scenario type") + topic: str = Field(..., description="PPT topic/theme") + requirements: Optional[str] = Field(None, description="Additional requirements") + network_mode: bool = Field(False, description="Whether to use network mode for enhanced generation") + language: str = Field("zh", description="Language for the PPT content") + uploaded_content: Optional[str] = Field(None, description="Content from uploaded files") + # 目标受众和风格相关参数 + target_audience: Optional[str] = Field(None, description="Target audience for the PPT") + ppt_style: str = Field("general", description="PPT style: 'general', 'conference', 'custom'") + custom_style_prompt: Optional[str] = Field(None, description="Custom style prompt") + description: Optional[str] = Field(None, description="Additional description or requirements") + # 文件生成相关参数 + use_file_content: bool = Field(False, description="Whether to use uploaded file content for generation") + file_processing_mode: str = Field("markitdown", description="File processing mode: 'markitdown' or 'magic_pdf'") + content_analysis_depth: str = Field("standard", description="Content analysis depth: 'fast', 'standard', 'deep'") + +class PPTOutline(BaseModel): + title: str + slides: List[Dict[str, Any]] + metadata: Dict[str, Any] + +class PPTGenerationResponse(BaseModel): + task_id: str + status: str + outline: Optional[PPTOutline] = None + slides_html: Optional[str] = None + error: Optional[str] = None + +# Enhanced Task Management Models +class TodoStage(BaseModel): + id: str + name: str + description: str + status: Literal["pending", "running", "completed", "failed"] = "pending" + progress: float = 0.0 + subtasks: List[str] = [] + result: Optional[Dict[str, Any]] = None + created_at: float = Field(default_factory=time.time) + updated_at: float = Field(default_factory=time.time) + +class TodoBoard(BaseModel): + task_id: str + title: str + stages: List[TodoStage] + current_stage_index: int = 0 + overall_progress: float = 0.0 + created_at: float = Field(default_factory=time.time) + updated_at: float = Field(default_factory=time.time) + +# Project Management Models +class PPTProject(BaseModel): + project_id: str + title: str + scenario: str + topic: str + requirements: Optional[str] = None + status: Literal["draft", "in_progress", "completed", "archived"] = "draft" + outline: Optional[Dict[str, Any]] = None # Changed to Dict for flexibility + slides_html: Optional[str] = None + slides_data: Optional[List[Dict[str, Any]]] = None # Individual slide data + confirmed_requirements: Optional[Dict[str, Any]] = None # Confirmed requirements from step 1 + project_metadata: Optional[Dict[str, Any]] = None # 项目元数据,包括选择的模板ID等 + todo_board: Optional[TodoBoard] = None + version: int = 1 + versions: List[Dict[str, Any]] = [] + created_at: float = Field(default_factory=time.time) + updated_at: float = Field(default_factory=time.time) + +class ProjectListResponse(BaseModel): + projects: List[PPTProject] + total: int + page: int + page_size: int + +# Enhanced Slide Models +class SlideContent(BaseModel): + type: Literal["title", "content", "image", "chart", "list", "thankyou", "agenda", "section", "conclusion"] + title: str + subtitle: Optional[str] = None + content: Optional[str] = None + bullet_points: Optional[List[str]] = None + image_suggestions: Optional[List[str]] = None + chart_data: Optional[Dict[str, Any]] = None + layout: str = "default" + locked: bool = False + +class EnhancedPPTOutline(BaseModel): + title: str + slides: List[SlideContent] + metadata: Dict[str, Any] + theme_config: Dict[str, Any] = {} + +# File Upload Models +class FileUploadResponse(BaseModel): + filename: str + size: int + type: str + processed_content: str + extracted_topics: List[str] = [] + suggested_scenarios: List[str] = [] + message: str + +class FileOutlineGenerationRequest(BaseModel): + """从文件生成PPT大纲的请求模型""" + file_path: str = Field(..., description="Uploaded file path") + filename: str = Field(..., description="Original filename") + topic: Optional[str] = Field(None, description="Custom topic override") + scenario: str = Field("general", description="PPT scenario type") + requirements: Optional[str] = Field(None, description="Specific requirements from user") + target_audience: Optional[str] = Field(None, description="Target audience for the PPT") + language: str = Field("zh", description="Language for the PPT content: 'zh' for Chinese, 'en' for English") + page_count_mode: str = Field("ai_decide", description="Page count mode: 'ai_decide', 'custom_range', 'fixed'") + min_pages: Optional[int] = Field(8, description="Minimum pages for custom_range mode") + max_pages: Optional[int] = Field(15, description="Maximum pages for custom_range mode") + fixed_pages: Optional[int] = Field(10, description="Fixed page count") + ppt_style: str = Field("general", description="PPT style: 'general', 'conference', 'custom'") + custom_style_prompt: Optional[str] = Field(None, description="Custom style prompt") + file_processing_mode: str = Field("markitdown", description="File processing mode") + content_analysis_depth: str = Field("standard", description="Content analysis depth") + +class FileOutlineGenerationResponse(BaseModel): + """从文件生成PPT大纲的响应模型""" + success: bool + outline: Optional[Dict[str, Any]] = None + file_info: Optional[Dict[str, Any]] = None + processing_stats: Optional[Dict[str, Any]] = None + error: Optional[str] = None + message: str + +# TaskStatus model removed - now using project-based workflow with TodoBoard + +# Global Master Template Models +class GlobalMasterTemplateCreate(BaseModel): + """Request model for creating a global master template""" + template_name: str = Field(..., description="Template name (must be unique)") + description: Optional[str] = Field("", description="Template description") + html_template: str = Field(..., description="HTML template content") + tags: Optional[List[str]] = Field([], description="Template tags for categorization") + is_default: Optional[bool] = Field(False, description="Whether this is the default template") + created_by: Optional[str] = Field("user", description="Creator identifier") + + +class GlobalMasterTemplateUpdate(BaseModel): + """Request model for updating a global master template""" + template_name: Optional[str] = Field(None, description="Template name (must be unique)") + description: Optional[str] = Field(None, description="Template description") + html_template: Optional[str] = Field(None, description="HTML template content") + tags: Optional[List[str]] = Field(None, description="Template tags for categorization") + is_default: Optional[bool] = Field(None, description="Whether this is the default template") + is_active: Optional[bool] = Field(None, description="Whether the template is active") + + +class GlobalMasterTemplateResponse(BaseModel): + """Response model for global master template""" + id: int + template_name: str + description: str + preview_image: Optional[str] = None + tags: List[str] + is_default: bool + is_active: bool + usage_count: int + created_by: str + created_at: float + updated_at: float + + +class GlobalMasterTemplateDetailResponse(GlobalMasterTemplateResponse): + """Detailed response model for global master template""" + html_template: str + style_config: Optional[Dict[str, Any]] = None + + +class ReferenceImageData(BaseModel): + """Reference image data for AI generation""" + filename: str = Field(..., description="Image filename") + data: str = Field(..., description="Base64 encoded image data") + size: int = Field(..., description="File size in bytes") + type: str = Field(..., description="MIME type") + + +class GlobalMasterTemplateGenerateRequest(BaseModel): + """Request model for AI-generated global master template""" + prompt: str = Field(..., description="AI generation prompt") + template_name: str = Field(..., description="Template name (must be unique)") + description: Optional[str] = Field("", description="Template description") + tags: Optional[List[str]] = Field([], description="Template tags") + generation_mode: str = Field("text_only", description="Generation mode: text_only, reference_style, exact_replica") + reference_image: Optional[ReferenceImageData] = Field(None, description="Reference image for multimodal generation") + + +class TemplateSelectionRequest(BaseModel): + """Request model for template selection during PPT generation""" + project_id: str = Field(..., description="Project ID") + selected_template_id: Optional[int] = Field(None, description="Selected template ID (None for default)") + + +class TemplateSelectionResponse(BaseModel): + """Response model for template selection""" + success: bool + message: str + selected_template: Optional[GlobalMasterTemplateResponse] = None