realtimex-deeptutor 0.5.0.post1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- realtimex_deeptutor/__init__.py +67 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/METADATA +1612 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/RECORD +276 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/WHEEL +5 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/entry_points.txt +2 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/licenses/LICENSE +661 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/top_level.txt +2 -0
- src/__init__.py +40 -0
- src/agents/__init__.py +24 -0
- src/agents/base_agent.py +657 -0
- src/agents/chat/__init__.py +24 -0
- src/agents/chat/chat_agent.py +435 -0
- src/agents/chat/prompts/en/chat_agent.yaml +35 -0
- src/agents/chat/prompts/zh/chat_agent.yaml +35 -0
- src/agents/chat/session_manager.py +311 -0
- src/agents/co_writer/__init__.py +0 -0
- src/agents/co_writer/edit_agent.py +260 -0
- src/agents/co_writer/narrator_agent.py +423 -0
- src/agents/co_writer/prompts/en/edit_agent.yaml +113 -0
- src/agents/co_writer/prompts/en/narrator_agent.yaml +88 -0
- src/agents/co_writer/prompts/zh/edit_agent.yaml +113 -0
- src/agents/co_writer/prompts/zh/narrator_agent.yaml +88 -0
- src/agents/guide/__init__.py +16 -0
- src/agents/guide/agents/__init__.py +11 -0
- src/agents/guide/agents/chat_agent.py +104 -0
- src/agents/guide/agents/interactive_agent.py +223 -0
- src/agents/guide/agents/locate_agent.py +149 -0
- src/agents/guide/agents/summary_agent.py +150 -0
- src/agents/guide/guide_manager.py +500 -0
- src/agents/guide/prompts/en/chat_agent.yaml +41 -0
- src/agents/guide/prompts/en/interactive_agent.yaml +202 -0
- src/agents/guide/prompts/en/locate_agent.yaml +68 -0
- src/agents/guide/prompts/en/summary_agent.yaml +157 -0
- src/agents/guide/prompts/zh/chat_agent.yaml +41 -0
- src/agents/guide/prompts/zh/interactive_agent.yaml +626 -0
- src/agents/guide/prompts/zh/locate_agent.yaml +68 -0
- src/agents/guide/prompts/zh/summary_agent.yaml +157 -0
- src/agents/ideagen/__init__.py +12 -0
- src/agents/ideagen/idea_generation_workflow.py +426 -0
- src/agents/ideagen/material_organizer_agent.py +173 -0
- src/agents/ideagen/prompts/en/idea_generation.yaml +187 -0
- src/agents/ideagen/prompts/en/material_organizer.yaml +69 -0
- src/agents/ideagen/prompts/zh/idea_generation.yaml +187 -0
- src/agents/ideagen/prompts/zh/material_organizer.yaml +69 -0
- src/agents/question/__init__.py +24 -0
- src/agents/question/agents/__init__.py +18 -0
- src/agents/question/agents/generate_agent.py +381 -0
- src/agents/question/agents/relevance_analyzer.py +207 -0
- src/agents/question/agents/retrieve_agent.py +239 -0
- src/agents/question/coordinator.py +718 -0
- src/agents/question/example.py +109 -0
- src/agents/question/prompts/en/coordinator.yaml +75 -0
- src/agents/question/prompts/en/generate_agent.yaml +77 -0
- src/agents/question/prompts/en/relevance_analyzer.yaml +41 -0
- src/agents/question/prompts/en/retrieve_agent.yaml +32 -0
- src/agents/question/prompts/zh/coordinator.yaml +75 -0
- src/agents/question/prompts/zh/generate_agent.yaml +77 -0
- src/agents/question/prompts/zh/relevance_analyzer.yaml +39 -0
- src/agents/question/prompts/zh/retrieve_agent.yaml +30 -0
- src/agents/research/agents/__init__.py +23 -0
- src/agents/research/agents/decompose_agent.py +507 -0
- src/agents/research/agents/manager_agent.py +228 -0
- src/agents/research/agents/note_agent.py +180 -0
- src/agents/research/agents/rephrase_agent.py +263 -0
- src/agents/research/agents/reporting_agent.py +1333 -0
- src/agents/research/agents/research_agent.py +714 -0
- src/agents/research/data_structures.py +451 -0
- src/agents/research/main.py +188 -0
- src/agents/research/prompts/en/decompose_agent.yaml +89 -0
- src/agents/research/prompts/en/manager_agent.yaml +24 -0
- src/agents/research/prompts/en/note_agent.yaml +121 -0
- src/agents/research/prompts/en/rephrase_agent.yaml +58 -0
- src/agents/research/prompts/en/reporting_agent.yaml +380 -0
- src/agents/research/prompts/en/research_agent.yaml +173 -0
- src/agents/research/prompts/zh/decompose_agent.yaml +89 -0
- src/agents/research/prompts/zh/manager_agent.yaml +24 -0
- src/agents/research/prompts/zh/note_agent.yaml +121 -0
- src/agents/research/prompts/zh/rephrase_agent.yaml +58 -0
- src/agents/research/prompts/zh/reporting_agent.yaml +380 -0
- src/agents/research/prompts/zh/research_agent.yaml +173 -0
- src/agents/research/research_pipeline.py +1309 -0
- src/agents/research/utils/__init__.py +60 -0
- src/agents/research/utils/citation_manager.py +799 -0
- src/agents/research/utils/json_utils.py +98 -0
- src/agents/research/utils/token_tracker.py +297 -0
- src/agents/solve/__init__.py +80 -0
- src/agents/solve/analysis_loop/__init__.py +14 -0
- src/agents/solve/analysis_loop/investigate_agent.py +414 -0
- src/agents/solve/analysis_loop/note_agent.py +190 -0
- src/agents/solve/main_solver.py +862 -0
- src/agents/solve/memory/__init__.py +34 -0
- src/agents/solve/memory/citation_memory.py +353 -0
- src/agents/solve/memory/investigate_memory.py +226 -0
- src/agents/solve/memory/solve_memory.py +340 -0
- src/agents/solve/prompts/en/analysis_loop/investigate_agent.yaml +55 -0
- src/agents/solve/prompts/en/analysis_loop/note_agent.yaml +54 -0
- src/agents/solve/prompts/en/solve_loop/manager_agent.yaml +67 -0
- src/agents/solve/prompts/en/solve_loop/precision_answer_agent.yaml +62 -0
- src/agents/solve/prompts/en/solve_loop/response_agent.yaml +90 -0
- src/agents/solve/prompts/en/solve_loop/solve_agent.yaml +75 -0
- src/agents/solve/prompts/en/solve_loop/tool_agent.yaml +38 -0
- src/agents/solve/prompts/zh/analysis_loop/investigate_agent.yaml +53 -0
- src/agents/solve/prompts/zh/analysis_loop/note_agent.yaml +54 -0
- src/agents/solve/prompts/zh/solve_loop/manager_agent.yaml +66 -0
- src/agents/solve/prompts/zh/solve_loop/precision_answer_agent.yaml +62 -0
- src/agents/solve/prompts/zh/solve_loop/response_agent.yaml +90 -0
- src/agents/solve/prompts/zh/solve_loop/solve_agent.yaml +76 -0
- src/agents/solve/prompts/zh/solve_loop/tool_agent.yaml +41 -0
- src/agents/solve/solve_loop/__init__.py +22 -0
- src/agents/solve/solve_loop/citation_manager.py +74 -0
- src/agents/solve/solve_loop/manager_agent.py +274 -0
- src/agents/solve/solve_loop/precision_answer_agent.py +96 -0
- src/agents/solve/solve_loop/response_agent.py +301 -0
- src/agents/solve/solve_loop/solve_agent.py +325 -0
- src/agents/solve/solve_loop/tool_agent.py +470 -0
- src/agents/solve/utils/__init__.py +64 -0
- src/agents/solve/utils/config_validator.py +313 -0
- src/agents/solve/utils/display_manager.py +223 -0
- src/agents/solve/utils/error_handler.py +363 -0
- src/agents/solve/utils/json_utils.py +98 -0
- src/agents/solve/utils/performance_monitor.py +407 -0
- src/agents/solve/utils/token_tracker.py +541 -0
- src/api/__init__.py +0 -0
- src/api/main.py +240 -0
- src/api/routers/__init__.py +1 -0
- src/api/routers/agent_config.py +69 -0
- src/api/routers/chat.py +296 -0
- src/api/routers/co_writer.py +337 -0
- src/api/routers/config.py +627 -0
- src/api/routers/dashboard.py +18 -0
- src/api/routers/guide.py +337 -0
- src/api/routers/ideagen.py +436 -0
- src/api/routers/knowledge.py +821 -0
- src/api/routers/notebook.py +247 -0
- src/api/routers/question.py +537 -0
- src/api/routers/research.py +394 -0
- src/api/routers/settings.py +164 -0
- src/api/routers/solve.py +305 -0
- src/api/routers/system.py +252 -0
- src/api/run_server.py +61 -0
- src/api/utils/history.py +172 -0
- src/api/utils/log_interceptor.py +21 -0
- src/api/utils/notebook_manager.py +415 -0
- src/api/utils/progress_broadcaster.py +72 -0
- src/api/utils/task_id_manager.py +100 -0
- src/config/__init__.py +0 -0
- src/config/accessors.py +18 -0
- src/config/constants.py +34 -0
- src/config/defaults.py +18 -0
- src/config/schema.py +38 -0
- src/config/settings.py +50 -0
- src/core/errors.py +62 -0
- src/knowledge/__init__.py +23 -0
- src/knowledge/add_documents.py +606 -0
- src/knowledge/config.py +65 -0
- src/knowledge/example_add_documents.py +236 -0
- src/knowledge/extract_numbered_items.py +1039 -0
- src/knowledge/initializer.py +621 -0
- src/knowledge/kb.py +22 -0
- src/knowledge/manager.py +782 -0
- src/knowledge/progress_tracker.py +182 -0
- src/knowledge/start_kb.py +535 -0
- src/logging/__init__.py +103 -0
- src/logging/adapters/__init__.py +17 -0
- src/logging/adapters/lightrag.py +184 -0
- src/logging/adapters/llamaindex.py +141 -0
- src/logging/config.py +80 -0
- src/logging/handlers/__init__.py +20 -0
- src/logging/handlers/console.py +75 -0
- src/logging/handlers/file.py +201 -0
- src/logging/handlers/websocket.py +127 -0
- src/logging/logger.py +709 -0
- src/logging/stats/__init__.py +16 -0
- src/logging/stats/llm_stats.py +179 -0
- src/services/__init__.py +56 -0
- src/services/config/__init__.py +61 -0
- src/services/config/knowledge_base_config.py +210 -0
- src/services/config/loader.py +260 -0
- src/services/config/unified_config.py +603 -0
- src/services/embedding/__init__.py +45 -0
- src/services/embedding/adapters/__init__.py +22 -0
- src/services/embedding/adapters/base.py +106 -0
- src/services/embedding/adapters/cohere.py +127 -0
- src/services/embedding/adapters/jina.py +99 -0
- src/services/embedding/adapters/ollama.py +116 -0
- src/services/embedding/adapters/openai_compatible.py +96 -0
- src/services/embedding/client.py +159 -0
- src/services/embedding/config.py +156 -0
- src/services/embedding/provider.py +119 -0
- src/services/llm/__init__.py +152 -0
- src/services/llm/capabilities.py +313 -0
- src/services/llm/client.py +302 -0
- src/services/llm/cloud_provider.py +530 -0
- src/services/llm/config.py +200 -0
- src/services/llm/error_mapping.py +103 -0
- src/services/llm/exceptions.py +152 -0
- src/services/llm/factory.py +450 -0
- src/services/llm/local_provider.py +347 -0
- src/services/llm/providers/anthropic.py +95 -0
- src/services/llm/providers/base_provider.py +93 -0
- src/services/llm/providers/open_ai.py +83 -0
- src/services/llm/registry.py +71 -0
- src/services/llm/telemetry.py +40 -0
- src/services/llm/types.py +27 -0
- src/services/llm/utils.py +333 -0
- src/services/prompt/__init__.py +25 -0
- src/services/prompt/manager.py +206 -0
- src/services/rag/__init__.py +64 -0
- src/services/rag/components/__init__.py +29 -0
- src/services/rag/components/base.py +59 -0
- src/services/rag/components/chunkers/__init__.py +18 -0
- src/services/rag/components/chunkers/base.py +34 -0
- src/services/rag/components/chunkers/fixed.py +71 -0
- src/services/rag/components/chunkers/numbered_item.py +94 -0
- src/services/rag/components/chunkers/semantic.py +97 -0
- src/services/rag/components/embedders/__init__.py +14 -0
- src/services/rag/components/embedders/base.py +32 -0
- src/services/rag/components/embedders/openai.py +63 -0
- src/services/rag/components/indexers/__init__.py +18 -0
- src/services/rag/components/indexers/base.py +35 -0
- src/services/rag/components/indexers/graph.py +172 -0
- src/services/rag/components/indexers/lightrag.py +156 -0
- src/services/rag/components/indexers/vector.py +146 -0
- src/services/rag/components/parsers/__init__.py +18 -0
- src/services/rag/components/parsers/base.py +35 -0
- src/services/rag/components/parsers/markdown.py +52 -0
- src/services/rag/components/parsers/pdf.py +115 -0
- src/services/rag/components/parsers/text.py +86 -0
- src/services/rag/components/retrievers/__init__.py +18 -0
- src/services/rag/components/retrievers/base.py +34 -0
- src/services/rag/components/retrievers/dense.py +200 -0
- src/services/rag/components/retrievers/hybrid.py +164 -0
- src/services/rag/components/retrievers/lightrag.py +169 -0
- src/services/rag/components/routing.py +286 -0
- src/services/rag/factory.py +234 -0
- src/services/rag/pipeline.py +215 -0
- src/services/rag/pipelines/__init__.py +32 -0
- src/services/rag/pipelines/academic.py +44 -0
- src/services/rag/pipelines/lightrag.py +43 -0
- src/services/rag/pipelines/llamaindex.py +313 -0
- src/services/rag/pipelines/raganything.py +384 -0
- src/services/rag/service.py +244 -0
- src/services/rag/types.py +73 -0
- src/services/search/__init__.py +284 -0
- src/services/search/base.py +87 -0
- src/services/search/consolidation.py +398 -0
- src/services/search/providers/__init__.py +128 -0
- src/services/search/providers/baidu.py +188 -0
- src/services/search/providers/exa.py +194 -0
- src/services/search/providers/jina.py +161 -0
- src/services/search/providers/perplexity.py +153 -0
- src/services/search/providers/serper.py +209 -0
- src/services/search/providers/tavily.py +161 -0
- src/services/search/types.py +114 -0
- src/services/setup/__init__.py +34 -0
- src/services/setup/init.py +285 -0
- src/services/tts/__init__.py +16 -0
- src/services/tts/config.py +99 -0
- src/tools/__init__.py +91 -0
- src/tools/code_executor.py +536 -0
- src/tools/paper_search_tool.py +171 -0
- src/tools/query_item_tool.py +310 -0
- src/tools/question/__init__.py +15 -0
- src/tools/question/exam_mimic.py +616 -0
- src/tools/question/pdf_parser.py +211 -0
- src/tools/question/question_extractor.py +397 -0
- src/tools/rag_tool.py +173 -0
- src/tools/tex_chunker.py +339 -0
- src/tools/tex_downloader.py +253 -0
- src/tools/web_search.py +71 -0
- src/utils/config_manager.py +206 -0
- src/utils/document_validator.py +168 -0
- src/utils/error_rate_tracker.py +111 -0
- src/utils/error_utils.py +82 -0
- src/utils/json_parser.py +110 -0
- src/utils/network/circuit_breaker.py +79 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
System Setup and Initialization
|
|
5
|
+
Combines user directory initialization and port configuration management.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from src.logging import get_logger
|
|
13
|
+
from src.services.config import load_config_with_main
|
|
14
|
+
|
|
15
|
+
# Initialize logger for setup operations
|
|
16
|
+
_setup_logger = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_setup_logger():
|
|
20
|
+
"""Get logger for setup operations"""
|
|
21
|
+
global _setup_logger
|
|
22
|
+
if _setup_logger is None:
|
|
23
|
+
_setup_logger = get_logger("Setup")
|
|
24
|
+
return _setup_logger
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ============================================================================
|
|
28
|
+
# User Directory Initialization (from user_dir_init.py)
|
|
29
|
+
# ============================================================================
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def init_user_directories(project_root: Path | None = None) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Initialize user data directories if they don't exist.
|
|
35
|
+
|
|
36
|
+
Creates the following directory structure:
|
|
37
|
+
data/user/
|
|
38
|
+
├── solve/ # Problem solving outputs
|
|
39
|
+
├── question/ # Question generation outputs
|
|
40
|
+
├── research/ # Research outputs
|
|
41
|
+
│ ├── cache/ # Research cache
|
|
42
|
+
│ └── reports/ # Research reports
|
|
43
|
+
├── guide/ # Guided learning outputs
|
|
44
|
+
├── notebook/ # Notebook data
|
|
45
|
+
├── co-writer/ # Co-writer outputs
|
|
46
|
+
│ ├── audio/ # TTS audio files
|
|
47
|
+
│ └── tool_calls/ # Tool call history
|
|
48
|
+
├── logs/ # User logs
|
|
49
|
+
├── run_code_workspace/ # Code execution workspace
|
|
50
|
+
└── user_history.json # User history file
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
project_root: Project root directory (if None, will try to detect)
|
|
54
|
+
"""
|
|
55
|
+
if project_root is None:
|
|
56
|
+
# Path(__file__) = src/services/setup/init.py
|
|
57
|
+
# .parent = src/services/setup/
|
|
58
|
+
# .parent.parent = src/services/
|
|
59
|
+
# .parent.parent.parent = src/
|
|
60
|
+
# .parent.parent.parent.parent = DeepTutor/ (project root)
|
|
61
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
62
|
+
|
|
63
|
+
# Get user data directory from config
|
|
64
|
+
try:
|
|
65
|
+
config = load_config_with_main("solve_config.yaml", project_root)
|
|
66
|
+
user_data_dir = config.get("paths", {}).get("user_data_dir", "./data/user")
|
|
67
|
+
|
|
68
|
+
# Convert relative path to absolute
|
|
69
|
+
if not Path(user_data_dir).is_absolute():
|
|
70
|
+
user_data_dir = project_root / user_data_dir
|
|
71
|
+
else:
|
|
72
|
+
user_data_dir = Path(user_data_dir)
|
|
73
|
+
except Exception:
|
|
74
|
+
# Fallback to default
|
|
75
|
+
user_data_dir = project_root / "data" / "user"
|
|
76
|
+
|
|
77
|
+
# Required subdirectories (based on actual usage in the codebase)
|
|
78
|
+
required_dirs = [
|
|
79
|
+
"solve", # Problem solving outputs
|
|
80
|
+
"question", # Question generation outputs
|
|
81
|
+
"research", # Research outputs (will have cache/ and reports/ subdirs)
|
|
82
|
+
"guide", # Guided learning outputs
|
|
83
|
+
"notebook", # Notebook data
|
|
84
|
+
"co-writer", # Co-writer outputs
|
|
85
|
+
"logs", # User logs
|
|
86
|
+
"run_code_workspace", # Code execution workspace
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
# Additional subdirectories for specific modules
|
|
90
|
+
co_writer_subdirs = [
|
|
91
|
+
"audio", # TTS audio files
|
|
92
|
+
"tool_calls", # Tool call history
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
research_subdirs = [
|
|
96
|
+
"cache", # Research cache
|
|
97
|
+
"reports", # Research reports
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
# Check if user directory exists and is empty
|
|
101
|
+
user_dir_exists = user_data_dir.exists()
|
|
102
|
+
user_dir_empty = False
|
|
103
|
+
if user_dir_exists:
|
|
104
|
+
try:
|
|
105
|
+
# Check if directory is empty (no files or subdirectories)
|
|
106
|
+
user_dir_empty = not any(user_data_dir.iterdir())
|
|
107
|
+
except (OSError, PermissionError) as e:
|
|
108
|
+
# If we can't check directory contents, assume it's not empty
|
|
109
|
+
logger = _get_setup_logger()
|
|
110
|
+
logger.warning(f"Cannot check if user directory is empty: {e}")
|
|
111
|
+
user_dir_empty = False
|
|
112
|
+
|
|
113
|
+
if not user_dir_exists or user_dir_empty:
|
|
114
|
+
logger = _get_setup_logger()
|
|
115
|
+
logger.info("\n" + "=" * 80)
|
|
116
|
+
logger.info("INITIALIZING USER DATA DIRECTORY")
|
|
117
|
+
logger.info("=" * 80)
|
|
118
|
+
|
|
119
|
+
if not user_dir_exists:
|
|
120
|
+
logger.info(f"Creating user data directory: {user_data_dir}")
|
|
121
|
+
else:
|
|
122
|
+
logger.info(f"User data directory is empty, initializing: {user_data_dir}")
|
|
123
|
+
|
|
124
|
+
# Create main user directory
|
|
125
|
+
user_data_dir.mkdir(parents=True, exist_ok=True)
|
|
126
|
+
|
|
127
|
+
# Create all required subdirectories
|
|
128
|
+
for dir_name in required_dirs:
|
|
129
|
+
dir_path = user_data_dir / dir_name
|
|
130
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
logger.success(f"Created: {dir_name}/")
|
|
132
|
+
|
|
133
|
+
# Create co-writer subdirectories
|
|
134
|
+
co_writer_dir = user_data_dir / "co-writer"
|
|
135
|
+
for subdir_name in co_writer_subdirs:
|
|
136
|
+
subdir_path = co_writer_dir / subdir_name
|
|
137
|
+
subdir_path.mkdir(parents=True, exist_ok=True)
|
|
138
|
+
logger.success(f"Created: co-writer/{subdir_name}/")
|
|
139
|
+
|
|
140
|
+
# Create research subdirectories
|
|
141
|
+
research_dir = user_data_dir / "research"
|
|
142
|
+
for subdir_name in research_subdirs:
|
|
143
|
+
subdir_path = research_dir / subdir_name
|
|
144
|
+
subdir_path.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
logger.success(f"Created: research/{subdir_name}/")
|
|
146
|
+
|
|
147
|
+
# Create user_history.json if it doesn't exist
|
|
148
|
+
user_history_file = user_data_dir / "user_history.json"
|
|
149
|
+
if not user_history_file.exists():
|
|
150
|
+
initial_history = {"version": "1.0", "created_at": None, "sessions": []}
|
|
151
|
+
try:
|
|
152
|
+
with open(user_history_file, "w", encoding="utf-8") as f:
|
|
153
|
+
json.dump(initial_history, f, indent=2, ensure_ascii=False)
|
|
154
|
+
logger.success("Created: user_history.json")
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logger.warning(f"Failed to create user_history.json: {e}")
|
|
157
|
+
|
|
158
|
+
# Create interface.json in settings folder if it doesn't exist
|
|
159
|
+
settings_dir = user_data_dir / "settings"
|
|
160
|
+
settings_dir.mkdir(parents=True, exist_ok=True)
|
|
161
|
+
interface_file = settings_dir / "interface.json"
|
|
162
|
+
if not interface_file.exists():
|
|
163
|
+
initial_settings = {"theme": "light", "language": "en", "output_language": "en"}
|
|
164
|
+
try:
|
|
165
|
+
with open(interface_file, "w", encoding="utf-8") as f:
|
|
166
|
+
json.dump(initial_settings, f, indent=2, ensure_ascii=False)
|
|
167
|
+
logger.success("Created: settings/interface.json")
|
|
168
|
+
except Exception as e:
|
|
169
|
+
logger.warning(f"Failed to create settings/interface.json: {e}")
|
|
170
|
+
|
|
171
|
+
logger.info("=" * 80)
|
|
172
|
+
logger.success("User data directory initialization complete!")
|
|
173
|
+
logger.info("=" * 80 + "\n")
|
|
174
|
+
else:
|
|
175
|
+
# Directory exists and is not empty, just ensure all subdirectories exist
|
|
176
|
+
for dir_name in required_dirs:
|
|
177
|
+
dir_path = user_data_dir / dir_name
|
|
178
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
179
|
+
|
|
180
|
+
# Ensure co-writer subdirectories exist
|
|
181
|
+
co_writer_dir = user_data_dir / "co-writer"
|
|
182
|
+
for subdir_name in co_writer_subdirs:
|
|
183
|
+
subdir_path = co_writer_dir / subdir_name
|
|
184
|
+
subdir_path.mkdir(parents=True, exist_ok=True)
|
|
185
|
+
|
|
186
|
+
# Ensure research subdirectories exist
|
|
187
|
+
research_dir = user_data_dir / "research"
|
|
188
|
+
for subdir_name in research_subdirs:
|
|
189
|
+
subdir_path = research_dir / subdir_name
|
|
190
|
+
subdir_path.mkdir(parents=True, exist_ok=True)
|
|
191
|
+
|
|
192
|
+
# Ensure user_history.json exists
|
|
193
|
+
user_history_file = user_data_dir / "user_history.json"
|
|
194
|
+
if not user_history_file.exists():
|
|
195
|
+
initial_history = {"version": "1.0", "created_at": None, "sessions": []}
|
|
196
|
+
try:
|
|
197
|
+
with open(user_history_file, "w", encoding="utf-8") as f:
|
|
198
|
+
json.dump(initial_history, f, indent=2, ensure_ascii=False)
|
|
199
|
+
except Exception:
|
|
200
|
+
pass # Silent fail if file creation fails but directory exists
|
|
201
|
+
|
|
202
|
+
# Ensure interface.json exists in settings folder
|
|
203
|
+
settings_dir = user_data_dir / "settings"
|
|
204
|
+
settings_dir.mkdir(parents=True, exist_ok=True)
|
|
205
|
+
interface_file = settings_dir / "interface.json"
|
|
206
|
+
if not interface_file.exists():
|
|
207
|
+
initial_settings = {"theme": "light", "language": "en", "output_language": "en"}
|
|
208
|
+
try:
|
|
209
|
+
with open(interface_file, "w", encoding="utf-8") as f:
|
|
210
|
+
json.dump(initial_settings, f, indent=2, ensure_ascii=False)
|
|
211
|
+
except Exception:
|
|
212
|
+
pass # Silent fail if file creation fails but directory exists
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ============================================================================
|
|
216
|
+
# Port Configuration Management
|
|
217
|
+
# ============================================================================
|
|
218
|
+
# Ports are configured via environment variables in .env file:
|
|
219
|
+
# BACKEND_PORT=8001 (default: 8001)
|
|
220
|
+
# FRONTEND_PORT=3782 (default: 3782)
|
|
221
|
+
# ============================================================================
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_backend_port(project_root: Path | None = None) -> int:
|
|
225
|
+
"""
|
|
226
|
+
Get backend port from environment variable.
|
|
227
|
+
|
|
228
|
+
Configure in .env file: BACKEND_PORT=8001
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Backend port number (default: 8001)
|
|
232
|
+
"""
|
|
233
|
+
env_port = os.environ.get("BACKEND_PORT", "8001")
|
|
234
|
+
try:
|
|
235
|
+
return int(env_port)
|
|
236
|
+
except ValueError:
|
|
237
|
+
logger = _get_setup_logger()
|
|
238
|
+
logger.warning(f"Invalid BACKEND_PORT: {env_port}, using default 8001")
|
|
239
|
+
return 8001
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_frontend_port(project_root: Path | None = None) -> int:
|
|
243
|
+
"""
|
|
244
|
+
Get frontend port from environment variable.
|
|
245
|
+
|
|
246
|
+
Configure in .env file: FRONTEND_PORT=3782
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Frontend port number (default: 3782)
|
|
250
|
+
"""
|
|
251
|
+
env_port = os.environ.get("FRONTEND_PORT", "3782")
|
|
252
|
+
try:
|
|
253
|
+
return int(env_port)
|
|
254
|
+
except ValueError:
|
|
255
|
+
logger = _get_setup_logger()
|
|
256
|
+
logger.warning(f"Invalid FRONTEND_PORT: {env_port}, using default 3782")
|
|
257
|
+
return 3782
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_ports(project_root: Path | None = None) -> tuple[int, int]:
|
|
261
|
+
"""
|
|
262
|
+
Get both backend and frontend ports from configuration.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
project_root: Project root directory (if None, will try to detect)
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Tuple of (backend_port, frontend_port)
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
SystemExit: If ports are not configured
|
|
272
|
+
"""
|
|
273
|
+
backend_port = get_backend_port(project_root)
|
|
274
|
+
frontend_port = get_frontend_port(project_root)
|
|
275
|
+
return (backend_port, frontend_port)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
__all__ = [
|
|
279
|
+
# User directory initialization
|
|
280
|
+
"init_user_directories",
|
|
281
|
+
# Port configuration (from .env)
|
|
282
|
+
"get_backend_port",
|
|
283
|
+
"get_frontend_port",
|
|
284
|
+
"get_ports",
|
|
285
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TTS Service
|
|
3
|
+
===========
|
|
4
|
+
|
|
5
|
+
Text-to-Speech configuration for DeepTutor.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from src.services.tts import get_tts_config
|
|
9
|
+
|
|
10
|
+
config = get_tts_config()
|
|
11
|
+
# config = {"model": "tts-1", "api_key": "...", "base_url": "...", "voice": "alloy"}
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .config import get_tts_config
|
|
15
|
+
|
|
16
|
+
__all__ = ["get_tts_config"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TTS Configuration
|
|
3
|
+
=================
|
|
4
|
+
|
|
5
|
+
Configuration management for Text-to-Speech services.
|
|
6
|
+
Simplified version - loads from unified config service or falls back to .env.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from dotenv import load_dotenv
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# Load environment variables
|
|
19
|
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
|
20
|
+
load_dotenv(PROJECT_ROOT / "DeepTutor.env", override=False)
|
|
21
|
+
load_dotenv(PROJECT_ROOT / ".env", override=False)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _strip_value(value: Optional[str]) -> Optional[str]:
|
|
25
|
+
"""Remove leading/trailing whitespace and quotes from string."""
|
|
26
|
+
if value is None:
|
|
27
|
+
return None
|
|
28
|
+
return value.strip().strip("\"'")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_tts_config() -> dict:
|
|
32
|
+
"""
|
|
33
|
+
Return complete configuration for TTS (Text-to-Speech).
|
|
34
|
+
|
|
35
|
+
Priority:
|
|
36
|
+
1. Active configuration from unified config service
|
|
37
|
+
2. Environment variables (.env)
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
dict: Dictionary containing the following keys:
|
|
41
|
+
- model: TTS model name
|
|
42
|
+
- api_key: TTS API key
|
|
43
|
+
- base_url: TTS API endpoint URL
|
|
44
|
+
- api_version: TTS API version (for Azure OpenAI)
|
|
45
|
+
- voice: Default voice character
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ValueError: If required configuration is missing
|
|
49
|
+
"""
|
|
50
|
+
# 1. Try to get active config from unified config service
|
|
51
|
+
try:
|
|
52
|
+
from src.services.config import get_active_tts_config
|
|
53
|
+
|
|
54
|
+
config = get_active_tts_config()
|
|
55
|
+
if config and config.get("model"):
|
|
56
|
+
return {
|
|
57
|
+
"model": config["model"],
|
|
58
|
+
"api_key": config.get("api_key", ""),
|
|
59
|
+
"base_url": config.get("base_url", ""),
|
|
60
|
+
"api_version": config.get("api_version"),
|
|
61
|
+
"voice": config.get("voice", "alloy"),
|
|
62
|
+
}
|
|
63
|
+
except ImportError:
|
|
64
|
+
# Unified config service not yet available, fall back to env
|
|
65
|
+
pass
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.warning(f"Failed to load from unified config: {e}")
|
|
68
|
+
|
|
69
|
+
# 2. Fallback to environment variables
|
|
70
|
+
model = _strip_value(os.getenv("TTS_MODEL"))
|
|
71
|
+
api_key = _strip_value(os.getenv("TTS_API_KEY"))
|
|
72
|
+
base_url = _strip_value(os.getenv("TTS_URL"))
|
|
73
|
+
api_version = _strip_value(os.getenv("TTS_BINDING_API_VERSION"))
|
|
74
|
+
voice = _strip_value(os.getenv("TTS_VOICE", "alloy"))
|
|
75
|
+
|
|
76
|
+
# Validate required configuration
|
|
77
|
+
if not model:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
"TTS_MODEL not set. Please configure it in .env file or add a configuration in Settings"
|
|
80
|
+
)
|
|
81
|
+
if not api_key:
|
|
82
|
+
raise ValueError(
|
|
83
|
+
"TTS_API_KEY not set. Please configure it in .env file or add a configuration in Settings"
|
|
84
|
+
)
|
|
85
|
+
if not base_url:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
"TTS_URL not set. Please configure it in .env file or add a configuration in Settings"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
"model": model,
|
|
92
|
+
"api_key": api_key,
|
|
93
|
+
"base_url": base_url,
|
|
94
|
+
"api_version": api_version,
|
|
95
|
+
"voice": voice,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = ["get_tts_config"]
|
src/tools/__init__.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Tools Package - Unified tool collection
|
|
5
|
+
|
|
6
|
+
Includes:
|
|
7
|
+
- rag_tool: RAG retrieval tool
|
|
8
|
+
- web_search: Web search tool
|
|
9
|
+
- query_item_tool: Query item tool
|
|
10
|
+
- paper_search_tool: Paper search tool
|
|
11
|
+
- tex_downloader: LaTeX source download tool
|
|
12
|
+
- tex_chunker: LaTeX text chunking tool
|
|
13
|
+
- question: Question generation tools (pdf_parser, question_extractor, exam_mimic)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# Patch lightrag.utils BEFORE any imports that use lightrag
|
|
17
|
+
import importlib.util
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
# Directly load lightrag.utils module without triggering lightrag/__init__.py
|
|
22
|
+
_spec = importlib.util.find_spec("lightrag.utils")
|
|
23
|
+
if _spec and _spec.origin:
|
|
24
|
+
_utils = importlib.util.module_from_spec(_spec)
|
|
25
|
+
sys.modules["lightrag.utils"] = _utils
|
|
26
|
+
_spec.loader.exec_module(_utils)
|
|
27
|
+
|
|
28
|
+
# Apply patches
|
|
29
|
+
for _k, _v in {
|
|
30
|
+
"verbose_debug": lambda *args, **kwargs: None,
|
|
31
|
+
"VERBOSE_DEBUG": False,
|
|
32
|
+
"get_env_value": lambda key, default=None: default,
|
|
33
|
+
"safe_unicode_decode": lambda t: (
|
|
34
|
+
t.decode("utf-8", errors="ignore") if isinstance(t, bytes) else t
|
|
35
|
+
),
|
|
36
|
+
}.items():
|
|
37
|
+
if not hasattr(_utils, _k):
|
|
38
|
+
setattr(_utils, _k, _v)
|
|
39
|
+
|
|
40
|
+
if not hasattr(_utils, "wrap_embedding_func_with_attrs"):
|
|
41
|
+
|
|
42
|
+
def _wrap(**attrs):
|
|
43
|
+
def dec(f):
|
|
44
|
+
for k, v in attrs.items():
|
|
45
|
+
setattr(f, k, v)
|
|
46
|
+
return f
|
|
47
|
+
|
|
48
|
+
return dec
|
|
49
|
+
|
|
50
|
+
_utils.wrap_embedding_func_with_attrs = _wrap
|
|
51
|
+
except Exception as e:
|
|
52
|
+
import traceback
|
|
53
|
+
|
|
54
|
+
print(f"Warning: Failed to patch lightrag.utils: {e}")
|
|
55
|
+
traceback.print_exc()
|
|
56
|
+
|
|
57
|
+
from .code_executor import run_code, run_code_sync
|
|
58
|
+
from .query_item_tool import query_numbered_item
|
|
59
|
+
from .rag_tool import rag_search
|
|
60
|
+
from .web_search import web_search
|
|
61
|
+
|
|
62
|
+
# Paper research related tools
|
|
63
|
+
try:
|
|
64
|
+
from .paper_search_tool import PaperSearchTool
|
|
65
|
+
from .tex_chunker import TexChunker
|
|
66
|
+
from .tex_downloader import TexDownloader, read_tex_file
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"PaperSearchTool",
|
|
70
|
+
"TexChunker",
|
|
71
|
+
"TexDownloader",
|
|
72
|
+
"query_numbered_item",
|
|
73
|
+
"rag_search",
|
|
74
|
+
"read_tex_file",
|
|
75
|
+
"run_code",
|
|
76
|
+
"run_code_sync",
|
|
77
|
+
"web_search",
|
|
78
|
+
]
|
|
79
|
+
except ImportError as e:
|
|
80
|
+
# If import fails (e.g., missing tiktoken), only export basic tools
|
|
81
|
+
print(f"⚠️ Some paper tools import failed: {e}")
|
|
82
|
+
__all__ = [
|
|
83
|
+
"query_numbered_item",
|
|
84
|
+
"rag_search",
|
|
85
|
+
"run_code",
|
|
86
|
+
"run_code_sync",
|
|
87
|
+
"web_search",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# Question generation tools (lazy import to avoid circular dependencies)
|
|
91
|
+
# Access via: from src.tools.question import parse_pdf_with_mineru, etc.
|