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.
Files changed (276) hide show
  1. realtimex_deeptutor/__init__.py +67 -0
  2. realtimex_deeptutor-0.5.0.post1.dist-info/METADATA +1612 -0
  3. realtimex_deeptutor-0.5.0.post1.dist-info/RECORD +276 -0
  4. realtimex_deeptutor-0.5.0.post1.dist-info/WHEEL +5 -0
  5. realtimex_deeptutor-0.5.0.post1.dist-info/entry_points.txt +2 -0
  6. realtimex_deeptutor-0.5.0.post1.dist-info/licenses/LICENSE +661 -0
  7. realtimex_deeptutor-0.5.0.post1.dist-info/top_level.txt +2 -0
  8. src/__init__.py +40 -0
  9. src/agents/__init__.py +24 -0
  10. src/agents/base_agent.py +657 -0
  11. src/agents/chat/__init__.py +24 -0
  12. src/agents/chat/chat_agent.py +435 -0
  13. src/agents/chat/prompts/en/chat_agent.yaml +35 -0
  14. src/agents/chat/prompts/zh/chat_agent.yaml +35 -0
  15. src/agents/chat/session_manager.py +311 -0
  16. src/agents/co_writer/__init__.py +0 -0
  17. src/agents/co_writer/edit_agent.py +260 -0
  18. src/agents/co_writer/narrator_agent.py +423 -0
  19. src/agents/co_writer/prompts/en/edit_agent.yaml +113 -0
  20. src/agents/co_writer/prompts/en/narrator_agent.yaml +88 -0
  21. src/agents/co_writer/prompts/zh/edit_agent.yaml +113 -0
  22. src/agents/co_writer/prompts/zh/narrator_agent.yaml +88 -0
  23. src/agents/guide/__init__.py +16 -0
  24. src/agents/guide/agents/__init__.py +11 -0
  25. src/agents/guide/agents/chat_agent.py +104 -0
  26. src/agents/guide/agents/interactive_agent.py +223 -0
  27. src/agents/guide/agents/locate_agent.py +149 -0
  28. src/agents/guide/agents/summary_agent.py +150 -0
  29. src/agents/guide/guide_manager.py +500 -0
  30. src/agents/guide/prompts/en/chat_agent.yaml +41 -0
  31. src/agents/guide/prompts/en/interactive_agent.yaml +202 -0
  32. src/agents/guide/prompts/en/locate_agent.yaml +68 -0
  33. src/agents/guide/prompts/en/summary_agent.yaml +157 -0
  34. src/agents/guide/prompts/zh/chat_agent.yaml +41 -0
  35. src/agents/guide/prompts/zh/interactive_agent.yaml +626 -0
  36. src/agents/guide/prompts/zh/locate_agent.yaml +68 -0
  37. src/agents/guide/prompts/zh/summary_agent.yaml +157 -0
  38. src/agents/ideagen/__init__.py +12 -0
  39. src/agents/ideagen/idea_generation_workflow.py +426 -0
  40. src/agents/ideagen/material_organizer_agent.py +173 -0
  41. src/agents/ideagen/prompts/en/idea_generation.yaml +187 -0
  42. src/agents/ideagen/prompts/en/material_organizer.yaml +69 -0
  43. src/agents/ideagen/prompts/zh/idea_generation.yaml +187 -0
  44. src/agents/ideagen/prompts/zh/material_organizer.yaml +69 -0
  45. src/agents/question/__init__.py +24 -0
  46. src/agents/question/agents/__init__.py +18 -0
  47. src/agents/question/agents/generate_agent.py +381 -0
  48. src/agents/question/agents/relevance_analyzer.py +207 -0
  49. src/agents/question/agents/retrieve_agent.py +239 -0
  50. src/agents/question/coordinator.py +718 -0
  51. src/agents/question/example.py +109 -0
  52. src/agents/question/prompts/en/coordinator.yaml +75 -0
  53. src/agents/question/prompts/en/generate_agent.yaml +77 -0
  54. src/agents/question/prompts/en/relevance_analyzer.yaml +41 -0
  55. src/agents/question/prompts/en/retrieve_agent.yaml +32 -0
  56. src/agents/question/prompts/zh/coordinator.yaml +75 -0
  57. src/agents/question/prompts/zh/generate_agent.yaml +77 -0
  58. src/agents/question/prompts/zh/relevance_analyzer.yaml +39 -0
  59. src/agents/question/prompts/zh/retrieve_agent.yaml +30 -0
  60. src/agents/research/agents/__init__.py +23 -0
  61. src/agents/research/agents/decompose_agent.py +507 -0
  62. src/agents/research/agents/manager_agent.py +228 -0
  63. src/agents/research/agents/note_agent.py +180 -0
  64. src/agents/research/agents/rephrase_agent.py +263 -0
  65. src/agents/research/agents/reporting_agent.py +1333 -0
  66. src/agents/research/agents/research_agent.py +714 -0
  67. src/agents/research/data_structures.py +451 -0
  68. src/agents/research/main.py +188 -0
  69. src/agents/research/prompts/en/decompose_agent.yaml +89 -0
  70. src/agents/research/prompts/en/manager_agent.yaml +24 -0
  71. src/agents/research/prompts/en/note_agent.yaml +121 -0
  72. src/agents/research/prompts/en/rephrase_agent.yaml +58 -0
  73. src/agents/research/prompts/en/reporting_agent.yaml +380 -0
  74. src/agents/research/prompts/en/research_agent.yaml +173 -0
  75. src/agents/research/prompts/zh/decompose_agent.yaml +89 -0
  76. src/agents/research/prompts/zh/manager_agent.yaml +24 -0
  77. src/agents/research/prompts/zh/note_agent.yaml +121 -0
  78. src/agents/research/prompts/zh/rephrase_agent.yaml +58 -0
  79. src/agents/research/prompts/zh/reporting_agent.yaml +380 -0
  80. src/agents/research/prompts/zh/research_agent.yaml +173 -0
  81. src/agents/research/research_pipeline.py +1309 -0
  82. src/agents/research/utils/__init__.py +60 -0
  83. src/agents/research/utils/citation_manager.py +799 -0
  84. src/agents/research/utils/json_utils.py +98 -0
  85. src/agents/research/utils/token_tracker.py +297 -0
  86. src/agents/solve/__init__.py +80 -0
  87. src/agents/solve/analysis_loop/__init__.py +14 -0
  88. src/agents/solve/analysis_loop/investigate_agent.py +414 -0
  89. src/agents/solve/analysis_loop/note_agent.py +190 -0
  90. src/agents/solve/main_solver.py +862 -0
  91. src/agents/solve/memory/__init__.py +34 -0
  92. src/agents/solve/memory/citation_memory.py +353 -0
  93. src/agents/solve/memory/investigate_memory.py +226 -0
  94. src/agents/solve/memory/solve_memory.py +340 -0
  95. src/agents/solve/prompts/en/analysis_loop/investigate_agent.yaml +55 -0
  96. src/agents/solve/prompts/en/analysis_loop/note_agent.yaml +54 -0
  97. src/agents/solve/prompts/en/solve_loop/manager_agent.yaml +67 -0
  98. src/agents/solve/prompts/en/solve_loop/precision_answer_agent.yaml +62 -0
  99. src/agents/solve/prompts/en/solve_loop/response_agent.yaml +90 -0
  100. src/agents/solve/prompts/en/solve_loop/solve_agent.yaml +75 -0
  101. src/agents/solve/prompts/en/solve_loop/tool_agent.yaml +38 -0
  102. src/agents/solve/prompts/zh/analysis_loop/investigate_agent.yaml +53 -0
  103. src/agents/solve/prompts/zh/analysis_loop/note_agent.yaml +54 -0
  104. src/agents/solve/prompts/zh/solve_loop/manager_agent.yaml +66 -0
  105. src/agents/solve/prompts/zh/solve_loop/precision_answer_agent.yaml +62 -0
  106. src/agents/solve/prompts/zh/solve_loop/response_agent.yaml +90 -0
  107. src/agents/solve/prompts/zh/solve_loop/solve_agent.yaml +76 -0
  108. src/agents/solve/prompts/zh/solve_loop/tool_agent.yaml +41 -0
  109. src/agents/solve/solve_loop/__init__.py +22 -0
  110. src/agents/solve/solve_loop/citation_manager.py +74 -0
  111. src/agents/solve/solve_loop/manager_agent.py +274 -0
  112. src/agents/solve/solve_loop/precision_answer_agent.py +96 -0
  113. src/agents/solve/solve_loop/response_agent.py +301 -0
  114. src/agents/solve/solve_loop/solve_agent.py +325 -0
  115. src/agents/solve/solve_loop/tool_agent.py +470 -0
  116. src/agents/solve/utils/__init__.py +64 -0
  117. src/agents/solve/utils/config_validator.py +313 -0
  118. src/agents/solve/utils/display_manager.py +223 -0
  119. src/agents/solve/utils/error_handler.py +363 -0
  120. src/agents/solve/utils/json_utils.py +98 -0
  121. src/agents/solve/utils/performance_monitor.py +407 -0
  122. src/agents/solve/utils/token_tracker.py +541 -0
  123. src/api/__init__.py +0 -0
  124. src/api/main.py +240 -0
  125. src/api/routers/__init__.py +1 -0
  126. src/api/routers/agent_config.py +69 -0
  127. src/api/routers/chat.py +296 -0
  128. src/api/routers/co_writer.py +337 -0
  129. src/api/routers/config.py +627 -0
  130. src/api/routers/dashboard.py +18 -0
  131. src/api/routers/guide.py +337 -0
  132. src/api/routers/ideagen.py +436 -0
  133. src/api/routers/knowledge.py +821 -0
  134. src/api/routers/notebook.py +247 -0
  135. src/api/routers/question.py +537 -0
  136. src/api/routers/research.py +394 -0
  137. src/api/routers/settings.py +164 -0
  138. src/api/routers/solve.py +305 -0
  139. src/api/routers/system.py +252 -0
  140. src/api/run_server.py +61 -0
  141. src/api/utils/history.py +172 -0
  142. src/api/utils/log_interceptor.py +21 -0
  143. src/api/utils/notebook_manager.py +415 -0
  144. src/api/utils/progress_broadcaster.py +72 -0
  145. src/api/utils/task_id_manager.py +100 -0
  146. src/config/__init__.py +0 -0
  147. src/config/accessors.py +18 -0
  148. src/config/constants.py +34 -0
  149. src/config/defaults.py +18 -0
  150. src/config/schema.py +38 -0
  151. src/config/settings.py +50 -0
  152. src/core/errors.py +62 -0
  153. src/knowledge/__init__.py +23 -0
  154. src/knowledge/add_documents.py +606 -0
  155. src/knowledge/config.py +65 -0
  156. src/knowledge/example_add_documents.py +236 -0
  157. src/knowledge/extract_numbered_items.py +1039 -0
  158. src/knowledge/initializer.py +621 -0
  159. src/knowledge/kb.py +22 -0
  160. src/knowledge/manager.py +782 -0
  161. src/knowledge/progress_tracker.py +182 -0
  162. src/knowledge/start_kb.py +535 -0
  163. src/logging/__init__.py +103 -0
  164. src/logging/adapters/__init__.py +17 -0
  165. src/logging/adapters/lightrag.py +184 -0
  166. src/logging/adapters/llamaindex.py +141 -0
  167. src/logging/config.py +80 -0
  168. src/logging/handlers/__init__.py +20 -0
  169. src/logging/handlers/console.py +75 -0
  170. src/logging/handlers/file.py +201 -0
  171. src/logging/handlers/websocket.py +127 -0
  172. src/logging/logger.py +709 -0
  173. src/logging/stats/__init__.py +16 -0
  174. src/logging/stats/llm_stats.py +179 -0
  175. src/services/__init__.py +56 -0
  176. src/services/config/__init__.py +61 -0
  177. src/services/config/knowledge_base_config.py +210 -0
  178. src/services/config/loader.py +260 -0
  179. src/services/config/unified_config.py +603 -0
  180. src/services/embedding/__init__.py +45 -0
  181. src/services/embedding/adapters/__init__.py +22 -0
  182. src/services/embedding/adapters/base.py +106 -0
  183. src/services/embedding/adapters/cohere.py +127 -0
  184. src/services/embedding/adapters/jina.py +99 -0
  185. src/services/embedding/adapters/ollama.py +116 -0
  186. src/services/embedding/adapters/openai_compatible.py +96 -0
  187. src/services/embedding/client.py +159 -0
  188. src/services/embedding/config.py +156 -0
  189. src/services/embedding/provider.py +119 -0
  190. src/services/llm/__init__.py +152 -0
  191. src/services/llm/capabilities.py +313 -0
  192. src/services/llm/client.py +302 -0
  193. src/services/llm/cloud_provider.py +530 -0
  194. src/services/llm/config.py +200 -0
  195. src/services/llm/error_mapping.py +103 -0
  196. src/services/llm/exceptions.py +152 -0
  197. src/services/llm/factory.py +450 -0
  198. src/services/llm/local_provider.py +347 -0
  199. src/services/llm/providers/anthropic.py +95 -0
  200. src/services/llm/providers/base_provider.py +93 -0
  201. src/services/llm/providers/open_ai.py +83 -0
  202. src/services/llm/registry.py +71 -0
  203. src/services/llm/telemetry.py +40 -0
  204. src/services/llm/types.py +27 -0
  205. src/services/llm/utils.py +333 -0
  206. src/services/prompt/__init__.py +25 -0
  207. src/services/prompt/manager.py +206 -0
  208. src/services/rag/__init__.py +64 -0
  209. src/services/rag/components/__init__.py +29 -0
  210. src/services/rag/components/base.py +59 -0
  211. src/services/rag/components/chunkers/__init__.py +18 -0
  212. src/services/rag/components/chunkers/base.py +34 -0
  213. src/services/rag/components/chunkers/fixed.py +71 -0
  214. src/services/rag/components/chunkers/numbered_item.py +94 -0
  215. src/services/rag/components/chunkers/semantic.py +97 -0
  216. src/services/rag/components/embedders/__init__.py +14 -0
  217. src/services/rag/components/embedders/base.py +32 -0
  218. src/services/rag/components/embedders/openai.py +63 -0
  219. src/services/rag/components/indexers/__init__.py +18 -0
  220. src/services/rag/components/indexers/base.py +35 -0
  221. src/services/rag/components/indexers/graph.py +172 -0
  222. src/services/rag/components/indexers/lightrag.py +156 -0
  223. src/services/rag/components/indexers/vector.py +146 -0
  224. src/services/rag/components/parsers/__init__.py +18 -0
  225. src/services/rag/components/parsers/base.py +35 -0
  226. src/services/rag/components/parsers/markdown.py +52 -0
  227. src/services/rag/components/parsers/pdf.py +115 -0
  228. src/services/rag/components/parsers/text.py +86 -0
  229. src/services/rag/components/retrievers/__init__.py +18 -0
  230. src/services/rag/components/retrievers/base.py +34 -0
  231. src/services/rag/components/retrievers/dense.py +200 -0
  232. src/services/rag/components/retrievers/hybrid.py +164 -0
  233. src/services/rag/components/retrievers/lightrag.py +169 -0
  234. src/services/rag/components/routing.py +286 -0
  235. src/services/rag/factory.py +234 -0
  236. src/services/rag/pipeline.py +215 -0
  237. src/services/rag/pipelines/__init__.py +32 -0
  238. src/services/rag/pipelines/academic.py +44 -0
  239. src/services/rag/pipelines/lightrag.py +43 -0
  240. src/services/rag/pipelines/llamaindex.py +313 -0
  241. src/services/rag/pipelines/raganything.py +384 -0
  242. src/services/rag/service.py +244 -0
  243. src/services/rag/types.py +73 -0
  244. src/services/search/__init__.py +284 -0
  245. src/services/search/base.py +87 -0
  246. src/services/search/consolidation.py +398 -0
  247. src/services/search/providers/__init__.py +128 -0
  248. src/services/search/providers/baidu.py +188 -0
  249. src/services/search/providers/exa.py +194 -0
  250. src/services/search/providers/jina.py +161 -0
  251. src/services/search/providers/perplexity.py +153 -0
  252. src/services/search/providers/serper.py +209 -0
  253. src/services/search/providers/tavily.py +161 -0
  254. src/services/search/types.py +114 -0
  255. src/services/setup/__init__.py +34 -0
  256. src/services/setup/init.py +285 -0
  257. src/services/tts/__init__.py +16 -0
  258. src/services/tts/config.py +99 -0
  259. src/tools/__init__.py +91 -0
  260. src/tools/code_executor.py +536 -0
  261. src/tools/paper_search_tool.py +171 -0
  262. src/tools/query_item_tool.py +310 -0
  263. src/tools/question/__init__.py +15 -0
  264. src/tools/question/exam_mimic.py +616 -0
  265. src/tools/question/pdf_parser.py +211 -0
  266. src/tools/question/question_extractor.py +397 -0
  267. src/tools/rag_tool.py +173 -0
  268. src/tools/tex_chunker.py +339 -0
  269. src/tools/tex_downloader.py +253 -0
  270. src/tools/web_search.py +71 -0
  271. src/utils/config_manager.py +206 -0
  272. src/utils/document_validator.py +168 -0
  273. src/utils/error_rate_tracker.py +111 -0
  274. src/utils/error_utils.py +82 -0
  275. src/utils/json_parser.py +110 -0
  276. src/utils/network/circuit_breaker.py +79 -0
@@ -0,0 +1,500 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ GuideManager - Guided Learning Session Manager
5
+ Manages the complete lifecycle of learning sessions
6
+ """
7
+
8
+ from dataclasses import asdict, dataclass, field
9
+ import json
10
+ from pathlib import Path
11
+ import time
12
+ from typing import Any
13
+ import uuid
14
+
15
+ import yaml
16
+
17
+ from src.logging import get_logger
18
+ from src.services.config import load_config_with_main, parse_language
19
+
20
+ from .agents import ChatAgent, InteractiveAgent, LocateAgent, SummaryAgent
21
+
22
+
23
+ @dataclass
24
+ class GuidedSession:
25
+ """Guided learning session"""
26
+
27
+ session_id: str
28
+ notebook_id: str
29
+ notebook_name: str
30
+ created_at: float
31
+ knowledge_points: list[dict[str, Any]] = field(default_factory=list)
32
+ current_index: int = 0
33
+ chat_history: list[dict[str, Any]] = field(default_factory=list)
34
+ status: str = "initialized" # initialized, learning, completed
35
+ current_html: str = ""
36
+ summary: str = ""
37
+
38
+ def to_dict(self) -> dict[str, Any]:
39
+ return asdict(self)
40
+
41
+ @classmethod
42
+ def from_dict(cls, data: dict[str, Any]) -> "GuidedSession":
43
+ return cls(**data)
44
+
45
+
46
+ class GuideManager:
47
+ """Guided learning manager"""
48
+
49
+ def __init__(
50
+ self,
51
+ api_key: str,
52
+ base_url: str,
53
+ api_version: str | None = None,
54
+ language: str | None = None,
55
+ output_dir: str | None = None,
56
+ config_path: str | None = None,
57
+ binding: str = "openai",
58
+ ):
59
+ """
60
+ Initialize manager
61
+
62
+ Args:
63
+ api_key: API key
64
+ base_url: API endpoint
65
+ api_version: API version (for Azure OpenAI)
66
+ language: Language setting (if None, read from config file)
67
+ output_dir: Output directory
68
+ config_path: Configuration file path (if None, use default path)
69
+ binding: LLM provider binding
70
+ """
71
+ self.api_key = api_key
72
+ self.base_url = base_url
73
+ self.api_version = api_version
74
+ self.binding = binding
75
+
76
+ if config_path is None:
77
+ project_root = Path(__file__).parent.parent.parent.parent
78
+ config = load_config_with_main("guide_config.yaml", project_root)
79
+ else:
80
+ config_path = Path(config_path)
81
+ if config_path.exists():
82
+ try:
83
+ with open(config_path, encoding="utf-8") as f:
84
+ config = yaml.safe_load(f) or {}
85
+ except Exception:
86
+ config = {}
87
+ else:
88
+ config = {}
89
+
90
+ # Initialize logger (from config)
91
+ log_dir = config.get("paths", {}).get("user_log_dir") or config.get("logging", {}).get(
92
+ "log_dir"
93
+ )
94
+ self.logger = get_logger("Guide", log_dir=log_dir)
95
+
96
+ if language is None:
97
+ # Get language config (unified in config/main.yaml system.language)
98
+ lang_config = config.get("system", {}).get("language", "zh")
99
+ self.language = parse_language(lang_config)
100
+ self.logger.info(f"Language setting loaded from config: {self.language}")
101
+ else:
102
+ # If explicitly specified, also parse it to ensure consistency
103
+ self.language = parse_language(language)
104
+ self.logger.info(f"Using explicitly specified language setting: {self.language}")
105
+
106
+ if output_dir:
107
+ self.output_dir = Path(output_dir)
108
+ else:
109
+ # Get output_dir from config (already loaded above)
110
+ output_dir_from_config = config.get("system", {}).get("output_dir")
111
+ if output_dir_from_config:
112
+ self.output_dir = Path(output_dir_from_config)
113
+ else:
114
+ # Fallback to default path
115
+ project_root = Path(__file__).parent.parent.parent.parent
116
+ self.output_dir = project_root / "data" / "user" / "guide"
117
+ self.output_dir.mkdir(parents=True, exist_ok=True)
118
+
119
+ self.locate_agent = LocateAgent(
120
+ api_key,
121
+ base_url,
122
+ language=self.language,
123
+ api_version=self.api_version,
124
+ binding=self.binding,
125
+ )
126
+ self.interactive_agent = InteractiveAgent(
127
+ api_key,
128
+ base_url,
129
+ language=self.language,
130
+ api_version=self.api_version,
131
+ binding=self.binding,
132
+ )
133
+ self.chat_agent = ChatAgent(
134
+ api_key,
135
+ base_url,
136
+ language=self.language,
137
+ api_version=self.api_version,
138
+ binding=self.binding,
139
+ )
140
+ self.summary_agent = SummaryAgent(
141
+ api_key,
142
+ base_url,
143
+ language=self.language,
144
+ api_version=self.api_version,
145
+ binding=self.binding,
146
+ )
147
+
148
+ self._sessions: dict[str, GuidedSession] = {}
149
+
150
+ def _get_session_file(self, session_id: str) -> Path:
151
+ """Get session file path"""
152
+ return self.output_dir / f"session_{session_id}.json"
153
+
154
+ def _save_session(self, session: GuidedSession):
155
+ """Save session to file"""
156
+ filepath = self._get_session_file(session.session_id)
157
+ with open(filepath, "w", encoding="utf-8") as f:
158
+ json.dump(session.to_dict(), f, indent=2, ensure_ascii=False)
159
+ self._sessions[session.session_id] = session
160
+
161
+ def _load_session(self, session_id: str) -> GuidedSession | None:
162
+ """Load session from file"""
163
+ if session_id in self._sessions:
164
+ return self._sessions[session_id]
165
+
166
+ filepath = self._get_session_file(session_id)
167
+ if filepath.exists():
168
+ with open(filepath, encoding="utf-8") as f:
169
+ data = json.load(f)
170
+ session = GuidedSession.from_dict(data)
171
+ self._sessions[session_id] = session
172
+ return session
173
+ return None
174
+
175
+ async def create_session(
176
+ self, notebook_id: str, notebook_name: str, records: list[dict[str, Any]]
177
+ ) -> dict[str, Any]:
178
+ """
179
+ Create new learning session
180
+
181
+ Args:
182
+ notebook_id: Notebook ID
183
+ notebook_name: Notebook name
184
+ records: Notebook records
185
+
186
+ Returns:
187
+ Session creation result
188
+ """
189
+ session_id = str(uuid.uuid4())[:8]
190
+
191
+ locate_result = await self.locate_agent.process(
192
+ notebook_id=notebook_id, notebook_name=notebook_name, records=records
193
+ )
194
+
195
+ if not locate_result.get("success"):
196
+ return {
197
+ "success": False,
198
+ "error": locate_result.get("error", "Failed to analyze knowledge points"),
199
+ "session_id": None,
200
+ }
201
+
202
+ knowledge_points = locate_result.get("knowledge_points", [])
203
+
204
+ if not knowledge_points:
205
+ return {
206
+ "success": False,
207
+ "error": "No knowledge points identified from notebook",
208
+ "session_id": None,
209
+ }
210
+
211
+ session = GuidedSession(
212
+ session_id=session_id,
213
+ notebook_id=notebook_id,
214
+ notebook_name=notebook_name,
215
+ created_at=time.time(),
216
+ knowledge_points=knowledge_points,
217
+ current_index=0,
218
+ status="initialized",
219
+ )
220
+
221
+ self._save_session(session)
222
+
223
+ return {
224
+ "success": True,
225
+ "session_id": session_id,
226
+ "knowledge_points": knowledge_points,
227
+ "total_points": len(knowledge_points),
228
+ "message": f"Learning plan created with {len(knowledge_points)} knowledge points",
229
+ }
230
+
231
+ def _get_learning_state(
232
+ self, knowledge_points: list[dict[str, Any]], current_index: int
233
+ ) -> dict[str, Any]:
234
+ """
235
+ Get learning state information (internal helper method)
236
+
237
+ Args:
238
+ knowledge_points: Knowledge point list
239
+ current_index: Current knowledge point index
240
+
241
+ Returns:
242
+ Learning state information
243
+ """
244
+ total_points = len(knowledge_points)
245
+
246
+ if total_points == 0:
247
+ return {"success": False, "error": "No knowledge points to learn", "status": "empty"}
248
+
249
+ if current_index >= total_points:
250
+ return {
251
+ "success": True,
252
+ "current_index": current_index,
253
+ "current_knowledge": None,
254
+ "status": "completed",
255
+ "progress_percentage": 100,
256
+ "total_points": total_points,
257
+ "message": "🎉 Congratulations! You have completed learning all knowledge points!",
258
+ }
259
+
260
+ current_knowledge = knowledge_points[current_index]
261
+ progress = int((current_index / total_points) * 100)
262
+
263
+ message = f"📚 Starting to learn knowledge point {current_index + 1}: {current_knowledge.get('knowledge_title', '')}"
264
+
265
+ return {
266
+ "success": True,
267
+ "current_index": current_index,
268
+ "current_knowledge": current_knowledge,
269
+ "status": "learning",
270
+ "progress_percentage": progress,
271
+ "total_points": total_points,
272
+ "remaining_points": total_points - current_index - 1,
273
+ "message": message,
274
+ }
275
+
276
+ async def start_learning(self, session_id: str) -> dict[str, Any]:
277
+ """
278
+ Start learning the first knowledge point
279
+
280
+ Args:
281
+ session_id: Session ID
282
+
283
+ Returns:
284
+ First knowledge point information and interactive page
285
+ """
286
+ session = self._load_session(session_id)
287
+ if not session:
288
+ return {"success": False, "error": "Session does not exist"}
289
+
290
+ state = self._get_learning_state(session.knowledge_points, 0)
291
+
292
+ if not state.get("success"):
293
+ return state
294
+
295
+ current_knowledge = state.get("current_knowledge")
296
+
297
+ interactive_result = await self.interactive_agent.process(knowledge=current_knowledge)
298
+
299
+ session.current_index = 0
300
+ session.status = "learning"
301
+ session.current_html = interactive_result.get("html", "")
302
+
303
+ session.chat_history.append(
304
+ {
305
+ "role": "system",
306
+ "content": state.get("message", ""),
307
+ "knowledge_index": 0,
308
+ "timestamp": time.time(),
309
+ }
310
+ )
311
+
312
+ self._save_session(session)
313
+
314
+ return {
315
+ "success": True,
316
+ "current_index": 0,
317
+ "current_knowledge": current_knowledge,
318
+ "html": interactive_result.get("html", ""),
319
+ "progress": state.get("progress_percentage", 0),
320
+ "total_points": len(session.knowledge_points),
321
+ "message": state.get("message", ""),
322
+ }
323
+
324
+ async def next_knowledge(self, session_id: str) -> dict[str, Any]:
325
+ """
326
+ Move to next knowledge point
327
+
328
+ Args:
329
+ session_id: Session ID
330
+
331
+ Returns:
332
+ Next knowledge point information and interactive page, or completion summary
333
+ """
334
+ session = self._load_session(session_id)
335
+ if not session:
336
+ return {"success": False, "error": "Session does not exist"}
337
+
338
+ new_index = session.current_index + 1
339
+
340
+ state = self._get_learning_state(session.knowledge_points, new_index)
341
+
342
+ if not state.get("success"):
343
+ return state
344
+
345
+ if state.get("status") == "completed":
346
+ summary_result = await self.summary_agent.process(
347
+ notebook_name=session.notebook_name,
348
+ knowledge_points=session.knowledge_points,
349
+ chat_history=session.chat_history,
350
+ )
351
+
352
+ session.status = "completed"
353
+ session.summary = summary_result.get("summary", "")
354
+ session.current_index = new_index
355
+
356
+ session.chat_history.append(
357
+ {
358
+ "role": "system",
359
+ "content": state.get(
360
+ "message", "Congratulations on completing all knowledge points!"
361
+ ),
362
+ "timestamp": time.time(),
363
+ }
364
+ )
365
+
366
+ self._save_session(session)
367
+
368
+ return {
369
+ "success": True,
370
+ "status": "completed",
371
+ "summary": session.summary,
372
+ "progress": 100,
373
+ "message": state.get("message", ""),
374
+ }
375
+
376
+ current_knowledge = state.get("current_knowledge")
377
+
378
+ interactive_result = await self.interactive_agent.process(knowledge=current_knowledge)
379
+
380
+ session.current_index = new_index
381
+ session.current_html = interactive_result.get("html", "")
382
+
383
+ message = f"→ Entering knowledge point {new_index + 1}: {current_knowledge.get('knowledge_title', '')}"
384
+
385
+ session.chat_history.append(
386
+ {
387
+ "role": "system",
388
+ "content": message,
389
+ "knowledge_index": new_index,
390
+ "timestamp": time.time(),
391
+ }
392
+ )
393
+
394
+ self._save_session(session)
395
+
396
+ return {
397
+ "success": True,
398
+ "current_index": new_index,
399
+ "current_knowledge": current_knowledge,
400
+ "html": interactive_result.get("html", ""),
401
+ "progress": state.get("progress_percentage", 0),
402
+ "total_points": len(session.knowledge_points),
403
+ "remaining_points": state.get("remaining_points", 0),
404
+ "message": message,
405
+ }
406
+
407
+ async def chat(self, session_id: str, user_message: str) -> dict[str, Any]:
408
+ """
409
+ Process user chat message
410
+
411
+ Args:
412
+ session_id: Session ID
413
+ user_message: User message
414
+
415
+ Returns:
416
+ Assistant's answer
417
+ """
418
+ session = self._load_session(session_id)
419
+ if not session:
420
+ return {"success": False, "error": "Session does not exist"}
421
+
422
+ if session.status != "learning":
423
+ return {"success": False, "error": "Not currently in learning state"}
424
+
425
+ current_knowledge = session.knowledge_points[session.current_index]
426
+
427
+ current_history = [
428
+ msg
429
+ for msg in session.chat_history
430
+ if msg.get("knowledge_index") == session.current_index
431
+ ]
432
+
433
+ user_msg = {
434
+ "role": "user",
435
+ "content": user_message,
436
+ "knowledge_index": session.current_index,
437
+ "timestamp": time.time(),
438
+ }
439
+ session.chat_history.append(user_msg)
440
+
441
+ chat_result = await self.chat_agent.process(
442
+ knowledge=current_knowledge, chat_history=current_history, user_question=user_message
443
+ )
444
+
445
+ assistant_msg = {
446
+ "role": "assistant",
447
+ "content": chat_result.get("answer", ""),
448
+ "knowledge_index": session.current_index,
449
+ "timestamp": time.time(),
450
+ }
451
+ session.chat_history.append(assistant_msg)
452
+
453
+ self._save_session(session)
454
+
455
+ return {
456
+ "success": True,
457
+ "answer": chat_result.get("answer", ""),
458
+ "knowledge_index": session.current_index,
459
+ }
460
+
461
+ async def fix_html(self, session_id: str, bug_description: str) -> dict[str, Any]:
462
+ """
463
+ Fix HTML page bug
464
+
465
+ Args:
466
+ session_id: Session ID
467
+ bug_description: Bug description
468
+
469
+ Returns:
470
+ Fixed HTML
471
+ """
472
+ session = self._load_session(session_id)
473
+ if not session:
474
+ return {"success": False, "error": "Session does not exist"}
475
+
476
+ current_knowledge = session.knowledge_points[session.current_index]
477
+
478
+ result = await self.interactive_agent.process(
479
+ knowledge=current_knowledge, retry_with_bug=bug_description
480
+ )
481
+
482
+ if result.get("success"):
483
+ session.current_html = result.get("html", "")
484
+ self._save_session(session)
485
+
486
+ return result
487
+
488
+ def get_session(self, session_id: str) -> dict[str, Any] | None:
489
+ """Get session information"""
490
+ session = self._load_session(session_id)
491
+ if session:
492
+ return session.to_dict()
493
+ return None
494
+
495
+ def get_current_html(self, session_id: str) -> str | None:
496
+ """Get current HTML page"""
497
+ session = self._load_session(session_id)
498
+ if session:
499
+ return session.current_html
500
+ return None
@@ -0,0 +1,41 @@
1
+ system: |
2
+ # Role Positioning
3
+ You are an **Intelligent Learning Assistant**. Your responsibility is to answer users' questions, resolve their doubts, and provide additional explanations and examples while they are learning specific knowledge points.
4
+
5
+ # Core Principles
6
+ 1. **Focus on Current Knowledge Point**: Answers should revolve around the knowledge point the user is currently learning
7
+ 2. **Progressive**: Provide explanations at an appropriate level based on the depth of the user's questions
8
+ 3. **Encourage Thinking**: While directly providing answers, guide users to think
9
+ 4. **Address Difficulties**: Consider potential difficulties users may have and proactively provide relevant clarifications
10
+
11
+ # Answer Style
12
+ - Use clear, easy-to-understand language
13
+ - Use examples and analogies appropriately
14
+ - For complex concepts, explain step by step
15
+ - Use Markdown format to enhance readability
16
+ - Maintain a friendly, encouraging tone
17
+
18
+ # Output Format
19
+ Directly output answers in Markdown format, with clear structure and highlighted key points.
20
+
21
+ user_template: |
22
+ ## Currently Learning Knowledge Point
23
+ **Title**: {knowledge_title}
24
+
25
+ **Content Summary**:
26
+ {knowledge_summary}
27
+
28
+ **User's Potential Difficulties**:
29
+ {user_difficulty}
30
+
31
+ ## Conversation History
32
+ {chat_history}
33
+
34
+ ## User's Current Question
35
+ {user_question}
36
+
37
+ ## Task
38
+ Please answer the user's question based on the content of the current knowledge point and context.
39
+ - Ensure the answer is relevant to the current knowledge point
40
+ - If the question involves the user's potential difficulties, give special attention
41
+ - The answer should be clear and well-organized