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,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task ID Manager - Assigns unique IDs to each background task
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
import threading
|
|
7
|
+
from typing import Optional
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TaskIDManager:
|
|
12
|
+
"""Singleton class for managing task IDs"""
|
|
13
|
+
|
|
14
|
+
_instance: Optional["TaskIDManager"] = None
|
|
15
|
+
_lock = threading.Lock()
|
|
16
|
+
_task_ids: dict[str, str] = {} # task_key -> task_id
|
|
17
|
+
_task_metadata: dict[str, dict] = {} # task_id -> metadata
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_instance(cls) -> "TaskIDManager":
|
|
21
|
+
"""Get singleton instance"""
|
|
22
|
+
if cls._instance is None:
|
|
23
|
+
with cls._lock:
|
|
24
|
+
if cls._instance is None:
|
|
25
|
+
cls._instance = cls()
|
|
26
|
+
return cls._instance
|
|
27
|
+
|
|
28
|
+
def generate_task_id(self, task_type: str, task_key: str) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Generate unique ID for task
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
task_type: Task type (e.g., 'kb_init', 'kb_upload', 'question_gen', 'solve', 'research')
|
|
34
|
+
task_key: Task unique identifier (e.g., knowledge base name, question ID, etc.)
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Task ID (format: {task_type}_{timestamp}_{uuid})
|
|
38
|
+
"""
|
|
39
|
+
with self._lock:
|
|
40
|
+
# If task already exists, return existing ID
|
|
41
|
+
if task_key in self._task_ids:
|
|
42
|
+
return self._task_ids[task_key]
|
|
43
|
+
|
|
44
|
+
# Generate new ID
|
|
45
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
46
|
+
unique_id = str(uuid.uuid4())[:8]
|
|
47
|
+
task_id = f"{task_type}_{timestamp}_{unique_id}"
|
|
48
|
+
|
|
49
|
+
# Save mapping and metadata
|
|
50
|
+
self._task_ids[task_key] = task_id
|
|
51
|
+
self._task_metadata[task_id] = {
|
|
52
|
+
"task_type": task_type,
|
|
53
|
+
"task_key": task_key,
|
|
54
|
+
"created_at": datetime.now().isoformat(),
|
|
55
|
+
"status": "running",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return task_id
|
|
59
|
+
|
|
60
|
+
def get_task_id(self, task_key: str) -> str | None:
|
|
61
|
+
"""Get task ID"""
|
|
62
|
+
with self._lock:
|
|
63
|
+
return self._task_ids.get(task_key)
|
|
64
|
+
|
|
65
|
+
def update_task_status(self, task_id: str, status: str, **kwargs):
|
|
66
|
+
"""Update task status"""
|
|
67
|
+
with self._lock:
|
|
68
|
+
if task_id in self._task_metadata:
|
|
69
|
+
self._task_metadata[task_id]["status"] = status
|
|
70
|
+
self._task_metadata[task_id].update(kwargs)
|
|
71
|
+
if status in ["completed", "error", "cancelled"]:
|
|
72
|
+
self._task_metadata[task_id]["finished_at"] = datetime.now().isoformat()
|
|
73
|
+
|
|
74
|
+
def get_task_metadata(self, task_id: str) -> dict | None:
|
|
75
|
+
"""Get task metadata"""
|
|
76
|
+
with self._lock:
|
|
77
|
+
return self._task_metadata.get(task_id, {}).copy()
|
|
78
|
+
|
|
79
|
+
def cleanup_old_tasks(self, max_age_hours: int = 24):
|
|
80
|
+
"""Clean up old tasks (completed tasks older than specified hours)"""
|
|
81
|
+
with self._lock:
|
|
82
|
+
cutoff = datetime.now() - timedelta(hours=max_age_hours)
|
|
83
|
+
|
|
84
|
+
to_remove = []
|
|
85
|
+
for task_id, metadata in self._task_metadata.items():
|
|
86
|
+
if metadata.get("status") in ["completed", "error", "cancelled"]:
|
|
87
|
+
finished_at = metadata.get("finished_at")
|
|
88
|
+
if finished_at:
|
|
89
|
+
try:
|
|
90
|
+
finished_time = datetime.fromisoformat(finished_at)
|
|
91
|
+
if finished_time < cutoff:
|
|
92
|
+
to_remove.append(task_id)
|
|
93
|
+
except:
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
for task_id in to_remove:
|
|
97
|
+
metadata = self._task_metadata.pop(task_id, {})
|
|
98
|
+
task_key = metadata.get("task_key")
|
|
99
|
+
if task_key:
|
|
100
|
+
self._task_ids.pop(task_key, None)
|
src/config/__init__.py
ADDED
|
File without changes
|
src/config/accessors.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConfigAccessor:
|
|
5
|
+
def __init__(self, loader: Callable[[], dict]):
|
|
6
|
+
self._loader = loader
|
|
7
|
+
|
|
8
|
+
def llm_model(self) -> str:
|
|
9
|
+
cfg = self._loader()
|
|
10
|
+
return str(cfg.get("llm", {}).get("model", "Pro/Flash"))
|
|
11
|
+
|
|
12
|
+
def llm_provider(self) -> str:
|
|
13
|
+
cfg = self._loader()
|
|
14
|
+
return str(cfg.get("llm", {}).get("provider", "openai"))
|
|
15
|
+
|
|
16
|
+
def user_data_dir(self) -> str:
|
|
17
|
+
cfg = self._loader()
|
|
18
|
+
return str(cfg.get("paths", {}).get("user_data_dir", "./data/user"))
|
src/config/constants.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Constants for DeepTutor
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
# Project root directory - central location for all path calculations
|
|
10
|
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|
11
|
+
|
|
12
|
+
# Valid tools for investigate agent
|
|
13
|
+
VALID_INVESTIGATE_TOOLS = ["rag_naive", "rag_hybrid", "web_search", "query_item", "none"]
|
|
14
|
+
|
|
15
|
+
# Valid tools for solve agent
|
|
16
|
+
VALID_SOLVE_TOOLS = [
|
|
17
|
+
"web_search",
|
|
18
|
+
"code_execution",
|
|
19
|
+
"rag_naive",
|
|
20
|
+
"rag_hybrid",
|
|
21
|
+
"query_item",
|
|
22
|
+
"none",
|
|
23
|
+
"finish",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
# Logging symbols for different log levels
|
|
27
|
+
LOG_SYMBOLS = {
|
|
28
|
+
"DEBUG": "·",
|
|
29
|
+
"INFO": "●",
|
|
30
|
+
"SUCCESS": "✓",
|
|
31
|
+
"WARNING": "⚠",
|
|
32
|
+
"ERROR": "✗",
|
|
33
|
+
"CRITICAL": "✗",
|
|
34
|
+
}
|
src/config/defaults.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Default configuration values for DeepTutor.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# Get project root
|
|
8
|
+
_project_root = Path(__file__).parent.parent.parent
|
|
9
|
+
|
|
10
|
+
# Default configuration
|
|
11
|
+
DEFAULTS = {
|
|
12
|
+
"llm": {"model": "gpt-4o-mini", "provider": "openai"},
|
|
13
|
+
"paths": {
|
|
14
|
+
"user_data_dir": str(_project_root / "data" / "user"),
|
|
15
|
+
"knowledge_bases_dir": str(_project_root / "data" / "knowledge_bases"),
|
|
16
|
+
"user_log_dir": str(_project_root / "logs"),
|
|
17
|
+
},
|
|
18
|
+
}
|
src/config/schema.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, field_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LLMConfig(BaseModel):
|
|
7
|
+
model: str
|
|
8
|
+
provider: str = "openai"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PathsConfig(BaseModel):
|
|
12
|
+
user_data_dir: str
|
|
13
|
+
knowledge_bases_dir: str
|
|
14
|
+
user_log_dir: str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AppConfig(BaseModel):
|
|
18
|
+
llm: LLMConfig
|
|
19
|
+
paths: PathsConfig
|
|
20
|
+
|
|
21
|
+
@field_validator("llm", mode="before")
|
|
22
|
+
@classmethod
|
|
23
|
+
def ensure_llm(cls, v: Any) -> Dict[str, Any]:
|
|
24
|
+
if not isinstance(v, dict):
|
|
25
|
+
raise ValueError("llm section must be a mapping")
|
|
26
|
+
if "model" not in v:
|
|
27
|
+
raise ValueError("llm.model is required")
|
|
28
|
+
return v
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
CURRENT_SCHEMA_VERSION = 1
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def migrate_config(cfg: Dict[str, Any]) -> Dict[str, Any]:
|
|
35
|
+
"""
|
|
36
|
+
No-op migration for now; placeholder for future versioned changes.
|
|
37
|
+
"""
|
|
38
|
+
return cfg
|
src/config/settings.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration Settings for DeepTutor
|
|
3
|
+
|
|
4
|
+
Environment Variables:
|
|
5
|
+
LLM_RETRY__MAX_RETRIES: Maximum retry attempts for LLM calls (default: 3)
|
|
6
|
+
LLM_RETRY__BASE_DELAY: Base delay between retries in seconds (default: 1.0)
|
|
7
|
+
LLM_RETRY__EXPONENTIAL_BACKOFF: Whether to use exponential backoff (default: True)
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
export LLM_RETRY__MAX_RETRIES=5
|
|
11
|
+
export LLM_RETRY__BASE_DELAY=2.0
|
|
12
|
+
export LLM_RETRY__EXPONENTIAL_BACKOFF=false
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, Field
|
|
16
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LLMRetryConfig(BaseModel):
|
|
20
|
+
max_retries: int = Field(default=3, description="Maximum retry attempts for LLM calls")
|
|
21
|
+
base_delay: float = Field(default=1.0, description="Base delay between retries in seconds")
|
|
22
|
+
exponential_backoff: bool = Field(
|
|
23
|
+
default=True, description="Whether to use exponential backoff"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Settings(BaseSettings):
|
|
28
|
+
# LLM retry configuration
|
|
29
|
+
retry: LLMRetryConfig = Field(default_factory=LLMRetryConfig)
|
|
30
|
+
|
|
31
|
+
# Deprecated: use retry instead
|
|
32
|
+
@property
|
|
33
|
+
def llm_retry(self):
|
|
34
|
+
import warnings
|
|
35
|
+
|
|
36
|
+
warnings.warn(
|
|
37
|
+
"settings.llm_retry is deprecated, use settings.retry instead",
|
|
38
|
+
DeprecationWarning,
|
|
39
|
+
stacklevel=2,
|
|
40
|
+
)
|
|
41
|
+
return self.retry
|
|
42
|
+
|
|
43
|
+
model_config = SettingsConfigDict(
|
|
44
|
+
env_prefix="LLM_",
|
|
45
|
+
env_nested_delimiter="__",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Global settings instance
|
|
50
|
+
settings = Settings()
|
src/core/errors.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base exception classes for consistent error handling across the application.
|
|
3
|
+
Provides a standardized way to distinguish between bugs, recoverable errors,
|
|
4
|
+
and configuration issues.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DeepTutorError(Exception):
|
|
11
|
+
"""Base class for all application errors in DeepTutor."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
|
|
14
|
+
super().__init__(message)
|
|
15
|
+
self.message = message
|
|
16
|
+
self.details = details or {}
|
|
17
|
+
|
|
18
|
+
def __str__(self) -> str:
|
|
19
|
+
if self.details:
|
|
20
|
+
return f"{self.message} (details: {self.details})"
|
|
21
|
+
return self.message
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ConfigurationError(DeepTutorError):
|
|
25
|
+
"""Raised when there's a configuration-related error."""
|
|
26
|
+
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ValidationError(DeepTutorError):
|
|
31
|
+
"""Raised when input validation fails."""
|
|
32
|
+
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ServiceError(DeepTutorError):
|
|
37
|
+
"""Base class for service layer errors."""
|
|
38
|
+
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class LLMServiceError(ServiceError):
|
|
43
|
+
"""Base class for LLM service-related errors."""
|
|
44
|
+
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class LLMContextError(LLMServiceError):
|
|
49
|
+
"""Raised when prompt exceeds model context window."""
|
|
50
|
+
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class EnvironmentConfigError(ConfigurationError):
|
|
55
|
+
"""Raised when there's an environment-related configuration error."""
|
|
56
|
+
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Aliases for backward compatibility
|
|
61
|
+
ConfigError = ConfigurationError
|
|
62
|
+
EnvError = EnvironmentConfigError
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Knowledge Base Initialization Module
|
|
4
|
+
|
|
5
|
+
Includes:
|
|
6
|
+
- init_knowledge_base: Knowledge base initializer
|
|
7
|
+
- add_documents: Incremental document addition (new feature)
|
|
8
|
+
- kb_manager: Knowledge base manager
|
|
9
|
+
- extract_numbered_items: Extract numbered items
|
|
10
|
+
- config: Path configuration
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from . import config
|
|
14
|
+
from .add_documents import DocumentAdder
|
|
15
|
+
from .initializer import KnowledgeBaseInitializer
|
|
16
|
+
from .manager import KnowledgeBaseManager
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"DocumentAdder",
|
|
20
|
+
"KnowledgeBaseInitializer",
|
|
21
|
+
"KnowledgeBaseManager",
|
|
22
|
+
"config",
|
|
23
|
+
]
|