| from dataclasses import dataclass, field |
| import os |
| from pathlib import Path |
| from typing import Any, Dict, List, Optional |
| current_file = Path(__file__).resolve() |
| PROJDIR = current_file.parent.parent |
|
|
| BASE_DIR = PROJDIR |
| DATAFLOW_DIR = PROJDIR |
| STATICS_DIR = PROJDIR / "static" |
|
|
| |
| |
| |
| if os.getenv("DF_USE_OPEN_DATAFLOW_PATHS", "").strip().lower() in {"1", "true", "yes"}: |
| try: |
| from dataflow.cli_funcs.paths import DataFlowPath |
|
|
| BASE_DIR = DataFlowPath.get_dataflow_dir() |
| DATAFLOW_DIR = BASE_DIR.parent |
| STATICS_DIR = DataFlowPath.get_dataflow_statics_dir() |
| except Exception: |
| BASE_DIR = PROJDIR |
| DATAFLOW_DIR = PROJDIR |
| STATICS_DIR = PROJDIR / "static" |
|
|
| from typing_extensions import TypedDict, Annotated |
| from langgraph.graph.message import add_messages |
| from langchain_core.messages import BaseMessage |
|
|
|
|
| |
| @dataclass |
| class MainRequest: |
| """所有Request的基类,只包含核心字段""" |
| |
| language: str = "en" |
|
|
| |
| chat_api_url: str = os.getenv("DF_API_URL", "test") |
| api_key: str = os.getenv("DF_API_KEY", "test") |
| chat_api_key: str = os.getenv("DF_API_KEY", "test") |
|
|
| |
| model: str = "gpt-4o" |
|
|
| |
| target: str = "" |
|
|
| def get(self, key, default=None): |
| return getattr(self, key, default) |
| |
| def __setitem__(self, key, value): |
| setattr(self, key, value) |
|
|
|
|
| |
| @dataclass |
| class MainState: |
| """所有State的基类,只包含核心字段""" |
| request: MainRequest = field(default_factory=MainRequest) |
| messages: Annotated[list[BaseMessage], add_messages] = field(default_factory=list) |
| |
| agent_results: Dict[str, Any] = field(default_factory=dict) |
| temp_data: Dict[str, Any] = field(default_factory=dict) |
|
|
| def get(self, key, default=None): |
| return getattr(self, key, default) |
|
|
| def __setitem__(self, key, value): |
| setattr(self, key, value) |
|
|
|
|
| |
| @dataclass |
| class DFRequest(MainRequest): |
| """主流程的Request,继承自MainRequest""" |
| |
| json_file: str = "" |
|
|
| |
| python_file_path: str = "" |
|
|
| |
| need_debug: bool = False |
| max_debug_rounds: int = 3 |
|
|
| |
| use_local_model: bool = False |
| local_model_path: str = "" |
|
|
| |
| cache_dir: str = f"{PROJDIR}/cache_dir" |
| session_id: str = "default_session" |
|
|
| |
| chat_api_url_for_embeddings : str = "" |
| embedding_model_name: str = "text-embedding-3-small" |
| update_rag_content: bool = True |
|
|
| |
| @dataclass |
| class DFState(MainState): |
| """主流程的State,继承自MainState""" |
| |
| request: DFRequest = field(default_factory=DFRequest) |
|
|
| |
| |
| category: Dict[str, Any] = field(default_factory=dict) |
| recommendation: Dict[str, Any] = field(default_factory=dict) |
| matched_ops: list[str] = field(default_factory=list) |
| debug_mode: bool = False |
| pipeline_structure_code: Dict[str, Any] = field(default_factory=dict) |
| execution_result: Dict[str, Any] = field(default_factory=dict) |
| code_debug_result: Dict[str, Any] = field(default_factory=dict) |
| debug_history: Dict[Any, Dict[str, Any]] = field(default_factory=dict) |
| opname_and_params: List[Dict[str, Dict[str, Any]]] = field(default_factory=list) |
|
|
|
|
|
|
| |
| @dataclass |
| class DataCollectionRequest(MainRequest): |
| """数据采集任务的Request,继承自MainRequest""" |
| |
| language: str = "English" |
| |
| |
| download_dir: str = os.path.join(STATICS_DIR, "data_collection") |
| dataset_size_category: str = '1K<n<10K' |
| dataset_num_limit: int = 5 |
| category: str = "PT" |
| max_dataset_size: int = None |
| max_download_subtasks: Optional[int] = None |
| rag_api_url: Optional[str] = None |
| rag_api_key: Optional[str] = None |
| rag_embed_model: Optional[str] = None |
| tavily_api_key: Optional[str] = None |
|
|
|
|
| |
| @dataclass |
| class DataCollectionState(MainState): |
| """数据采集任务的State,继承自MainState""" |
| |
| request: DataCollectionRequest = field(default_factory=DataCollectionRequest) |
| |
| |
| keywords: list[str] = field(default_factory=list) |
| datasets: Dict[str, list] = field(default_factory=dict) |
| downloads: Dict[str, list] = field(default_factory=dict) |
| sources: Dict[str, Dict] = field(default_factory=dict) |
|
|
| |
| |
| @dataclass |
| class IconGenRequest(MainRequest): |
| keywords: str = "" |
| style: str = "" |
| prev_image: str = "" |
| edit_prompt: str = "" |
|
|
| |
| @dataclass |
| class IconGenState(MainState): |
| request: IconGenRequest = field(default_factory=IconGenRequest) |
|
|
| |
| icon_prompt: str = "" |
| img_save_path: str = "" |
|
|
|
|
| |
| @dataclass |
| class WebCrawlRequest(MainRequest): |
| """Web 爬取任务的 Request,继承自 MainRequest""" |
| |
| initial_request: str = "" |
| download_dir: str = os.path.join(STATICS_DIR, "web_crawl") |
|
|
| |
| search_engine: str = "tavily" |
| use_jina_reader: bool = False |
| enable_rag: bool = True |
| max_download_subtasks: Optional[int] = None |
|
|
|
|
| |
| @dataclass |
| class WebCrawlState(MainState): |
| """管理网络爬取与研究过程的状态""" |
| |
| request: WebCrawlRequest = field(default_factory=WebCrawlRequest) |
|
|
| |
| initial_request: str = "" |
| download_dir: str = os.path.join(STATICS_DIR, "web_crawl") |
| search_engine: str = "tavily" |
| use_jina_reader: bool = False |
| enable_rag: bool = True |
| rag_manager: Any = None |
| max_download_subtasks: Optional[int] = None |
|
|
| |
| sub_tasks: list[Dict[str, Any]] = field(default_factory=list) |
| completed_sub_tasks: list[Dict[str, Any]] = field(default_factory=list) |
| research_summary: Dict[str, Any] = field(default_factory=dict) |
| search_results_text: str = "" |
| filtered_urls: list[str] = field(default_factory=list) |
| crawled_data: list[Dict[str, Any]] = field(default_factory=list) |
| visited_urls: set[str] = field(default_factory=set) |
| url_queue: list[str] = field(default_factory=list) |
| is_finished: bool = False |
| supervisor_feedback: str = "Process has not started." |
| |
| max_crawl_cycles_per_task: int = 5 |
| max_crawl_cycles_for_research: int = 15 |
| max_dataset_size: Optional[int] = None |
| current_cycle: int = 0 |
| download_successful_for_current_task: bool = False |
| completed_download_tasks: int = 0 |
|
|
| def reset_for_new_task(self): |
| self.search_results_text = "" |
| self.filtered_urls = [] |
| self.visited_urls = set() |
| self.url_queue = [] |
| self.current_cycle = 0 |
| self.download_successful_for_current_task = False |
| |
|
|
| |
| @dataclass |
| class PromptWritingState(MainState): |
| """提示词生成任务的State,继承自MainState""" |
| request: DFRequest = field(default_factory=DFRequest) |
| |
| |
| prompt_op_name: str = "" |
| prompt_args: Dict[str, Any] = field(default_factory=dict) |
| prompt_output_format: Dict[str, Any] = field(default_factory=dict) |
| delete_test_files: bool = True |
|
|
| |
| |
|
|
| @dataclass |
| class Paper2VideoRequest(MainRequest): |
| paper_pdf_path: str = "" |
| user_imgs_path: str = "" |
| |
| ref_audio_path: str = "" |
|
|
| |
| @dataclass |
| class Paper2VideoState(MainState): |
| |
| request: Paper2VideoRequest = field(default_factory=Paper2VideoRequest) |
| |
| |
| beamer_code_path: str = "" |
| is_beamer_wrong: bool = False |
| is_beamer_warning: bool = False |
| code_debug_result: str = "" |
| ppt_path: str = "" |
| |
| |
| slide_img_dir: str = "" |
| subtitle_and_cursor: List[str] = field(default_factory=list) |
| subtitle_and_cursor_path: str = "" |
| |
| |
| speech_save_dir: str = "" |
|
|
|
|
|
|
| |
| @dataclass |
| class PlanningRequest(MainRequest): |
| """Planning Agent 的 Request""" |
| |
| planner_model: Optional[str] = None |
| planner_temperature: float = 0.0 |
| |
| |
| executor_model: Optional[str] = None |
| executor_as_react: bool = True |
| |
| |
| replanner_model: Optional[str] = None |
| max_replanning_rounds: int = 3 |
| |
| |
| require_plan_approval: bool = True |
| interrupt_before_step: bool = True |
| interrupt_after_step: bool = False |
| |
| |
| max_plan_steps: int = 10 |
| planning_mode: str = "plan_solve" |
|
|
|
|
| @dataclass |
| class PlanStep: |
| """单个计划步骤""" |
| index: int |
| description: str |
| status: str = "pending" |
| result: Optional[str] = None |
| error: Optional[str] = None |
| started_at: Optional[str] = None |
| completed_at: Optional[str] = None |
|
|
|
|
| @dataclass |
| class PlanningState(MainState): |
| """ |
| Planning Agent 的状态类 |
| |
| 支持两种模式: |
| - Plan-and-Solve: 一次性生成计划,按顺序执行 |
| - Plan-and-Execute (Replanning): 动态调整计划 |
| """ |
| request: PlanningRequest = field(default_factory=PlanningRequest) |
| |
| |
| plan: List[str] = field(default_factory=list) |
| plan_steps: List[Dict[str, Any]] = field(default_factory=list) |
| current_step_index: int = 0 |
| past_steps: List[tuple] = field(default_factory=list) |
| |
| |
| plan_approved: bool = False |
| is_replanning_needed: bool = False |
| replanning_count: int = 0 |
| final_response: str = "" |
| is_finished: bool = False |
| |
| |
| awaiting_human_input: bool = False |
| human_feedback: Optional[str] = None |
| interrupt_reason: Optional[str] = None |
| |
| |
| original_task: str = "" |
| executor_tools: List[str] = field(default_factory=list) |
| |
| def get_current_step(self) -> Optional[str]: |
| """获取当前待执行的步骤""" |
| if 0 <= self.current_step_index < len(self.plan): |
| return self.plan[self.current_step_index] |
| return None |
| |
| def get_remaining_steps(self) -> List[str]: |
| """获取剩余未执行的步骤""" |
| return self.plan[self.current_step_index:] |
| |
| def get_completed_steps(self) -> List[tuple]: |
| """获取已完成的步骤及结果""" |
| return self.past_steps |
| |
| def mark_step_complete(self, result: str): |
| """标记当前步骤完成""" |
| if self.current_step_index < len(self.plan): |
| step = self.plan[self.current_step_index] |
| self.past_steps.append((step, result)) |
| self.current_step_index += 1 |
| |
| def reset_plan(self): |
| """重置计划状态(用于重规划)""" |
| self.plan = [] |
| self.plan_steps = [] |
| self.current_step_index = 0 |
| self.is_replanning_needed = False |
| |
| |
| def to_planning_context(self) -> Dict[str, Any]: |
| """生成规划上下文(供 LLM 使用)""" |
| return { |
| "original_task": self.original_task or self.request.target, |
| "past_steps": [ |
| {"step": step, "result": result} |
| for step, result in self.past_steps |
| ], |
| "remaining_steps": self.get_remaining_steps(), |
| "replanning_count": self.replanning_count, |
| "available_tools": self.executor_tools, |
| } |
|
|
| @dataclass |
| class Paper2FigureRequest(MainRequest): |
| gen_fig_model: str = "gemini-2.5-flash-image-preview" |
| |
| sam2_model: str = "models/facebook/sam2.1-hiera-tiny" |
| bg_rm_model: str = "models/RMBG-2.0" |
| input_type: str = "PDF" |
| |
| figure_complex: str = "hard" |
| style: str = "kartoon" |
|
|
| |
| page_count: int = 10 |
| |
| all_edited_down: bool = False |
|
|
| |
| use_ai_edit: bool = False |
|
|
| @dataclass |
| class Paper2FigureState(MainState): |
| request: Paper2FigureRequest = field(default_factory=Paper2FigureRequest) |
| fig_desc: str = '' |
| aspect_ratio: str = '16:9' |
| paper_file: str = '' |
| |
| fig_draft_path: str = '' |
| |
| fig_mask: List[Dict[str, Any]] = field(default_factory=list) |
| |
| fig_layout_path: str = '' |
| |
| layout_items: List[Dict[str, Any]] = field(default_factory=list) |
| result_path: str = '' |
| ppt_path: str = '' |
| mask_detail_level: int = 2 |
| paper_idea: str = '' |
| input_type: str = 'PDF' |
|
|
| |
| figure_tec_svg_content: str = "" |
| svg_img_path: str = "" |
| mineru_port: int = 8010 |
| svg_file_path: str = "" |
| svg_bg_file_path: str = "" |
| |
| svg_full_img_path: str = "" |
| |
| svg_bg_code : str = "" |
| |
| |
| |
| pre_tool_results: Dict[str, Any] = field(default_factory=dict) |
|
|
| |
| paper_idea: str = '' |
| extracted_tables: List[Dict[str, Any]] = field(default_factory=list) |
| |
|
|
| chart_configs: Dict[str, Dict[str, Any]] = field(default_factory=dict) |
| |
|
|
| generated_codes: Dict[str, Dict[str, Any]] = field(default_factory=dict) |
| |
|
|
| |
| generated_charts: Dict[str, str] = field(default_factory=dict) |
| stylize_results: Dict[str, list] = field(default_factory=dict) |
|
|
| svg_bg_code: str = "" |
|
|
| |
| |
| gen_down: bool = False |
| |
| edit_page_num: int = -1 |
| |
| edit_page_prompt: str = "" |
| |
| generated_pages: List[str] = field(default_factory=list) |
| table_img_path: str = "" |
|
|
| |
| pagecontent: list[dict] = field(default_factory=list) |
| minueru_output: str = "" |
| mineru_root: str = "" |
| text_content: str = "" |
| |
| ppt_pdf_path: str = "" |
| ppt_pptx_path: str = "" |
|
|
| |
| long_text: str = "" |
| target_pages: int = 60 |
| pages_per_batch: int = 10 |
| pages_to_generate: int = 12 |
| max_rounds: int = 1 |
| current_chunk: str = "" |
| current_text: str = "" |
|
|
| |
| pdf_file: str = "" |
| slide_images: List[str] = field(default_factory=list) |
| ocr_pages: List[str] = field(default_factory=list) |
| sam_pages: List[str] = field(default_factory=list) |
| mineru_pages: List[Dict[str, Any]] = field(default_factory=list) |
| |
| use_ai_edit: bool = False |
| use_global_font_clustering: bool = False |
|
|