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
src/api/routers/guide.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Guided Learning API Router
|
|
3
|
+
==========================
|
|
4
|
+
|
|
5
|
+
Provides session creation, learning progress management, and chat interaction.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from fastapi import APIRouter, HTTPException, WebSocket, WebSocketDisconnect
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
15
|
+
if str(project_root) not in sys.path:
|
|
16
|
+
sys.path.insert(0, str(project_root))
|
|
17
|
+
|
|
18
|
+
from src.agents.base_agent import BaseAgent
|
|
19
|
+
from src.agents.guide.guide_manager import GuideManager
|
|
20
|
+
from src.api.utils.notebook_manager import notebook_manager
|
|
21
|
+
from src.api.utils.task_id_manager import TaskIDManager
|
|
22
|
+
from src.logging import get_logger
|
|
23
|
+
from src.services.config import load_config_with_main
|
|
24
|
+
from src.services.llm import get_llm_config
|
|
25
|
+
|
|
26
|
+
router = APIRouter()
|
|
27
|
+
|
|
28
|
+
# Initialize logger with config
|
|
29
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
30
|
+
config = load_config_with_main("guide_config.yaml", project_root)
|
|
31
|
+
log_dir = config.get("paths", {}).get("user_log_dir") or config.get("logging", {}).get("log_dir")
|
|
32
|
+
logger = get_logger("Guide", level="INFO", log_dir=log_dir)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# === Request/Response Models ===
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CreateSessionRequest(BaseModel):
|
|
39
|
+
"""Create session request"""
|
|
40
|
+
|
|
41
|
+
notebook_id: str | None = None # Optional, single notebook mode
|
|
42
|
+
records: list[dict] | None = None # Optional, cross-notebook mode with direct records
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ChatRequest(BaseModel):
|
|
46
|
+
"""Chat request"""
|
|
47
|
+
|
|
48
|
+
session_id: str
|
|
49
|
+
message: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class FixHtmlRequest(BaseModel):
|
|
53
|
+
"""Fix HTML request"""
|
|
54
|
+
|
|
55
|
+
session_id: str
|
|
56
|
+
bug_description: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class NextKnowledgeRequest(BaseModel):
|
|
60
|
+
"""Next knowledge point request"""
|
|
61
|
+
|
|
62
|
+
session_id: str
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# === Helper Functions ===
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_guide_manager():
|
|
69
|
+
"""Get GuideManager instance"""
|
|
70
|
+
try:
|
|
71
|
+
llm_config = get_llm_config()
|
|
72
|
+
api_key = llm_config.api_key
|
|
73
|
+
base_url = llm_config.base_url
|
|
74
|
+
api_version = getattr(llm_config, "api_version", None)
|
|
75
|
+
binding = llm_config.binding
|
|
76
|
+
except Exception as e:
|
|
77
|
+
raise HTTPException(status_code=500, detail=f"LLM config error: {e!s}")
|
|
78
|
+
|
|
79
|
+
return GuideManager(
|
|
80
|
+
api_key=api_key,
|
|
81
|
+
base_url=base_url,
|
|
82
|
+
api_version=api_version,
|
|
83
|
+
language=None,
|
|
84
|
+
binding=binding,
|
|
85
|
+
) # Read from config file
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# === REST API Endpoints ===
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@router.post("/create_session")
|
|
92
|
+
async def create_session(request: CreateSessionRequest):
|
|
93
|
+
"""
|
|
94
|
+
Create a new guided learning session.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Session creation result with knowledge point list.
|
|
98
|
+
"""
|
|
99
|
+
task_manager = TaskIDManager.get_instance()
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
records = []
|
|
103
|
+
notebook_name = "Unknown"
|
|
104
|
+
|
|
105
|
+
# Mode 1: Cross-notebook mode - use provided records directly
|
|
106
|
+
if request.records and isinstance(request.records, list):
|
|
107
|
+
records = request.records
|
|
108
|
+
notebook_name = f"Cross-notebook ({len(records)} records)"
|
|
109
|
+
# Mode 2: Single notebook mode - get records from notebook
|
|
110
|
+
elif request.notebook_id:
|
|
111
|
+
notebook = notebook_manager.get_notebook(request.notebook_id)
|
|
112
|
+
if not notebook:
|
|
113
|
+
raise HTTPException(status_code=404, detail="Notebook not found")
|
|
114
|
+
|
|
115
|
+
records = notebook.get("records", [])
|
|
116
|
+
notebook_name = notebook.get("name", "Unknown")
|
|
117
|
+
else:
|
|
118
|
+
raise HTTPException(status_code=400, detail="Must provide notebook_id or records")
|
|
119
|
+
|
|
120
|
+
if not records:
|
|
121
|
+
raise HTTPException(status_code=400, detail="No available records")
|
|
122
|
+
|
|
123
|
+
# Reset LLM stats for new session
|
|
124
|
+
BaseAgent.reset_stats("guide")
|
|
125
|
+
|
|
126
|
+
manager = get_guide_manager()
|
|
127
|
+
result = await manager.create_session(
|
|
128
|
+
notebook_id=request.notebook_id or "cross_notebook",
|
|
129
|
+
notebook_name=notebook_name,
|
|
130
|
+
records=records,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if result and "session_id" in result:
|
|
134
|
+
session_id = result["session_id"]
|
|
135
|
+
task_id = task_manager.generate_task_id("guide", session_id)
|
|
136
|
+
logger.info(f"[{task_id}] Session created: {session_id}")
|
|
137
|
+
|
|
138
|
+
return result
|
|
139
|
+
|
|
140
|
+
except HTTPException:
|
|
141
|
+
raise
|
|
142
|
+
except Exception as e:
|
|
143
|
+
logger.error(f"Create session failed: {e}")
|
|
144
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@router.post("/start")
|
|
148
|
+
async def start_learning(request: NextKnowledgeRequest):
|
|
149
|
+
"""
|
|
150
|
+
Start learning (get the first knowledge point).
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
manager = get_guide_manager()
|
|
154
|
+
result = await manager.start_learning(request.session_id)
|
|
155
|
+
return result
|
|
156
|
+
except Exception as e:
|
|
157
|
+
logger.error(f"Start learning failed: {e}")
|
|
158
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@router.post("/next")
|
|
162
|
+
async def next_knowledge(request: NextKnowledgeRequest):
|
|
163
|
+
"""
|
|
164
|
+
Move to the next knowledge point.
|
|
165
|
+
"""
|
|
166
|
+
try:
|
|
167
|
+
manager = get_guide_manager()
|
|
168
|
+
result = await manager.next_knowledge(request.session_id)
|
|
169
|
+
|
|
170
|
+
# Print stats if learning completed
|
|
171
|
+
if result.get("learning_complete", False):
|
|
172
|
+
BaseAgent.print_stats("guide")
|
|
173
|
+
|
|
174
|
+
return result
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error(f"Next knowledge failed: {e}")
|
|
177
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@router.post("/chat")
|
|
181
|
+
async def chat(request: ChatRequest):
|
|
182
|
+
"""
|
|
183
|
+
Send a chat message.
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
manager = get_guide_manager()
|
|
187
|
+
result = await manager.chat(request.session_id, request.message)
|
|
188
|
+
return result
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.error(f"Chat failed: {e}")
|
|
191
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@router.post("/fix_html")
|
|
195
|
+
async def fix_html(request: FixHtmlRequest):
|
|
196
|
+
"""
|
|
197
|
+
Fix HTML page bugs.
|
|
198
|
+
"""
|
|
199
|
+
try:
|
|
200
|
+
manager = get_guide_manager()
|
|
201
|
+
result = await manager.fix_html(request.session_id, request.bug_description)
|
|
202
|
+
return result
|
|
203
|
+
except Exception as e:
|
|
204
|
+
logger.error(f"Fix HTML failed: {e}")
|
|
205
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@router.get("/session/{session_id}")
|
|
209
|
+
async def get_session(session_id: str):
|
|
210
|
+
"""
|
|
211
|
+
Get session information.
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
manager = get_guide_manager()
|
|
215
|
+
session = manager.get_session(session_id)
|
|
216
|
+
if not session:
|
|
217
|
+
raise HTTPException(status_code=404, detail="Session not found")
|
|
218
|
+
return session
|
|
219
|
+
except HTTPException:
|
|
220
|
+
raise
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.error(f"Get session failed: {e}")
|
|
223
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@router.get("/session/{session_id}/html")
|
|
227
|
+
async def get_current_html(session_id: str):
|
|
228
|
+
"""
|
|
229
|
+
Get the current HTML page.
|
|
230
|
+
"""
|
|
231
|
+
try:
|
|
232
|
+
manager = get_guide_manager()
|
|
233
|
+
html = manager.get_current_html(session_id)
|
|
234
|
+
if html is None:
|
|
235
|
+
raise HTTPException(status_code=404, detail="Session not found or no HTML content")
|
|
236
|
+
return {"html": html}
|
|
237
|
+
except HTTPException:
|
|
238
|
+
raise
|
|
239
|
+
except Exception as e:
|
|
240
|
+
logger.error(f"Get HTML failed: {e}")
|
|
241
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# === WebSocket Endpoint ===
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@router.websocket("/ws/{session_id}")
|
|
248
|
+
async def websocket_guide(websocket: WebSocket, session_id: str):
|
|
249
|
+
"""
|
|
250
|
+
WebSocket endpoint for real-time interaction.
|
|
251
|
+
|
|
252
|
+
Message types:
|
|
253
|
+
- start: Start learning
|
|
254
|
+
- next: Next knowledge point
|
|
255
|
+
- chat: Send chat message
|
|
256
|
+
- fix_html: Fix HTML
|
|
257
|
+
- get_session: Get session state
|
|
258
|
+
"""
|
|
259
|
+
await websocket.accept()
|
|
260
|
+
|
|
261
|
+
task_manager = TaskIDManager.get_instance()
|
|
262
|
+
task_id = task_manager.generate_task_id("guide", session_id)
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
await websocket.send_json({"type": "task_id", "task_id": task_id})
|
|
266
|
+
except (RuntimeError, WebSocketDisconnect, ConnectionError) as e:
|
|
267
|
+
logger.debug(f"Failed to send task_id: {e}")
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
manager = get_guide_manager()
|
|
271
|
+
|
|
272
|
+
session = manager.get_session(session_id)
|
|
273
|
+
if not session:
|
|
274
|
+
await websocket.send_json({"type": "error", "content": "Session not found"})
|
|
275
|
+
await websocket.close()
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
logger.info(f"[{task_id}] Guide session started: {session_id}")
|
|
279
|
+
|
|
280
|
+
await websocket.send_json({"type": "session_info", "data": session})
|
|
281
|
+
|
|
282
|
+
while True:
|
|
283
|
+
try:
|
|
284
|
+
data = await websocket.receive_json()
|
|
285
|
+
msg_type = data.get("type", "")
|
|
286
|
+
|
|
287
|
+
if msg_type == "start":
|
|
288
|
+
logger.debug(f"[{task_id}] Start learning")
|
|
289
|
+
result = await manager.start_learning(session_id)
|
|
290
|
+
await websocket.send_json({"type": "start_result", "data": result})
|
|
291
|
+
|
|
292
|
+
elif msg_type == "next":
|
|
293
|
+
logger.debug(f"[{task_id}] Next knowledge point")
|
|
294
|
+
result = await manager.next_knowledge(session_id)
|
|
295
|
+
await websocket.send_json({"type": "next_result", "data": result})
|
|
296
|
+
|
|
297
|
+
elif msg_type == "chat":
|
|
298
|
+
message = data.get("message", "")
|
|
299
|
+
if message:
|
|
300
|
+
logger.debug(f"[{task_id}] User message: {message[:50]}...")
|
|
301
|
+
result = await manager.chat(session_id, message)
|
|
302
|
+
await websocket.send_json({"type": "chat_result", "data": result})
|
|
303
|
+
|
|
304
|
+
elif msg_type == "fix_html":
|
|
305
|
+
bug_desc = data.get("bug_description", "")
|
|
306
|
+
logger.debug(f"[{task_id}] Fix HTML: {bug_desc[:50]}...")
|
|
307
|
+
result = await manager.fix_html(session_id, bug_desc)
|
|
308
|
+
await websocket.send_json({"type": "fix_result", "data": result})
|
|
309
|
+
|
|
310
|
+
elif msg_type == "get_session":
|
|
311
|
+
session = manager.get_session(session_id)
|
|
312
|
+
await websocket.send_json({"type": "session_info", "data": session})
|
|
313
|
+
|
|
314
|
+
else:
|
|
315
|
+
await websocket.send_json(
|
|
316
|
+
{"type": "error", "content": f"Unknown message type: {msg_type}"}
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
except WebSocketDisconnect:
|
|
320
|
+
logger.debug(f"WebSocket disconnected: {session_id}")
|
|
321
|
+
break
|
|
322
|
+
except Exception as e:
|
|
323
|
+
logger.error(f"WebSocket error: {e}")
|
|
324
|
+
await websocket.send_json({"type": "error", "content": str(e)})
|
|
325
|
+
|
|
326
|
+
except Exception as e:
|
|
327
|
+
logger.error(f"WebSocket connection error: {e}")
|
|
328
|
+
try:
|
|
329
|
+
await websocket.close()
|
|
330
|
+
except (RuntimeError, WebSocketDisconnect, ConnectionError):
|
|
331
|
+
pass # Connection already closed
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@router.get("/health")
|
|
335
|
+
async def health_check():
|
|
336
|
+
"""Health check"""
|
|
337
|
+
return {"status": "healthy", "service": "guide"}
|