realtimex-deeptutor 0.5.0.post1__py3-none-any.whl → 0.5.0.post3__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-0.5.0.post1.dist-info → realtimex_deeptutor-0.5.0.post3.dist-info}/METADATA +24 -17
- {realtimex_deeptutor-0.5.0.post1.dist-info → realtimex_deeptutor-0.5.0.post3.dist-info}/RECORD +143 -123
- {realtimex_deeptutor-0.5.0.post1.dist-info → realtimex_deeptutor-0.5.0.post3.dist-info}/WHEEL +1 -1
- realtimex_deeptutor-0.5.0.post3.dist-info/entry_points.txt +4 -0
- {realtimex_deeptutor-0.5.0.post1.dist-info → realtimex_deeptutor-0.5.0.post3.dist-info}/top_level.txt +1 -0
- scripts/__init__.py +1 -0
- scripts/audit_prompts.py +179 -0
- scripts/check_install.py +460 -0
- scripts/generate_roster.py +327 -0
- scripts/install_all.py +653 -0
- scripts/migrate_kb.py +655 -0
- scripts/start.py +807 -0
- scripts/start_web.py +632 -0
- scripts/sync_prompts_from_en.py +147 -0
- src/__init__.py +2 -2
- src/agents/ideagen/material_organizer_agent.py +2 -0
- src/agents/solve/__init__.py +6 -0
- src/agents/solve/main_solver.py +9 -0
- src/agents/solve/prompts/zh/analysis_loop/investigate_agent.yaml +9 -7
- src/agents/solve/session_manager.py +345 -0
- src/api/main.py +14 -0
- src/api/routers/chat.py +3 -3
- src/api/routers/co_writer.py +12 -7
- src/api/routers/config.py +1 -0
- src/api/routers/guide.py +3 -1
- src/api/routers/ideagen.py +7 -0
- src/api/routers/knowledge.py +64 -12
- src/api/routers/question.py +2 -0
- src/api/routers/realtimex.py +137 -0
- src/api/routers/research.py +9 -0
- src/api/routers/solve.py +120 -2
- src/cli/__init__.py +13 -0
- src/cli/start.py +209 -0
- src/config/constants.py +11 -9
- src/knowledge/add_documents.py +453 -213
- src/knowledge/extract_numbered_items.py +9 -10
- src/knowledge/initializer.py +102 -101
- src/knowledge/manager.py +251 -74
- src/knowledge/progress_tracker.py +43 -2
- src/knowledge/start_kb.py +11 -2
- src/logging/__init__.py +5 -0
- src/logging/adapters/__init__.py +1 -0
- src/logging/adapters/lightrag.py +25 -18
- src/logging/adapters/llamaindex.py +1 -0
- src/logging/config.py +30 -27
- src/logging/handlers/__init__.py +1 -0
- src/logging/handlers/console.py +7 -50
- src/logging/handlers/file.py +5 -20
- src/logging/handlers/websocket.py +23 -19
- src/logging/logger.py +161 -126
- src/logging/stats/__init__.py +1 -0
- src/logging/stats/llm_stats.py +37 -17
- src/services/__init__.py +17 -1
- src/services/config/__init__.py +1 -0
- src/services/config/knowledge_base_config.py +1 -0
- src/services/config/loader.py +1 -1
- src/services/config/unified_config.py +211 -4
- src/services/embedding/__init__.py +1 -0
- src/services/embedding/adapters/__init__.py +3 -0
- src/services/embedding/adapters/base.py +1 -0
- src/services/embedding/adapters/cohere.py +1 -0
- src/services/embedding/adapters/jina.py +1 -0
- src/services/embedding/adapters/ollama.py +1 -0
- src/services/embedding/adapters/openai_compatible.py +1 -0
- src/services/embedding/adapters/realtimex.py +125 -0
- src/services/embedding/client.py +27 -0
- src/services/embedding/config.py +3 -0
- src/services/embedding/provider.py +1 -0
- src/services/llm/__init__.py +17 -3
- src/services/llm/capabilities.py +47 -0
- src/services/llm/client.py +32 -0
- src/services/llm/cloud_provider.py +21 -4
- src/services/llm/config.py +36 -2
- src/services/llm/error_mapping.py +1 -0
- src/services/llm/exceptions.py +30 -0
- src/services/llm/factory.py +55 -16
- src/services/llm/local_provider.py +1 -0
- src/services/llm/providers/anthropic.py +1 -0
- src/services/llm/providers/base_provider.py +1 -0
- src/services/llm/providers/open_ai.py +1 -0
- src/services/llm/realtimex_provider.py +240 -0
- src/services/llm/registry.py +1 -0
- src/services/llm/telemetry.py +1 -0
- src/services/llm/types.py +1 -0
- src/services/llm/utils.py +1 -0
- src/services/prompt/__init__.py +1 -0
- src/services/prompt/manager.py +3 -2
- src/services/rag/__init__.py +27 -5
- src/services/rag/components/__init__.py +1 -0
- src/services/rag/components/base.py +1 -0
- src/services/rag/components/chunkers/__init__.py +1 -0
- src/services/rag/components/chunkers/base.py +1 -0
- src/services/rag/components/chunkers/fixed.py +1 -0
- src/services/rag/components/chunkers/numbered_item.py +1 -0
- src/services/rag/components/chunkers/semantic.py +1 -0
- src/services/rag/components/embedders/__init__.py +1 -0
- src/services/rag/components/embedders/base.py +1 -0
- src/services/rag/components/embedders/openai.py +1 -0
- src/services/rag/components/indexers/__init__.py +1 -0
- src/services/rag/components/indexers/base.py +1 -0
- src/services/rag/components/indexers/graph.py +5 -44
- src/services/rag/components/indexers/lightrag.py +5 -44
- src/services/rag/components/indexers/vector.py +1 -0
- src/services/rag/components/parsers/__init__.py +1 -0
- src/services/rag/components/parsers/base.py +1 -0
- src/services/rag/components/parsers/markdown.py +1 -0
- src/services/rag/components/parsers/pdf.py +1 -0
- src/services/rag/components/parsers/text.py +1 -0
- src/services/rag/components/retrievers/__init__.py +1 -0
- src/services/rag/components/retrievers/base.py +1 -0
- src/services/rag/components/retrievers/dense.py +1 -0
- src/services/rag/components/retrievers/hybrid.py +5 -44
- src/services/rag/components/retrievers/lightrag.py +5 -44
- src/services/rag/components/routing.py +48 -0
- src/services/rag/factory.py +112 -46
- src/services/rag/pipeline.py +1 -0
- src/services/rag/pipelines/__init__.py +27 -18
- src/services/rag/pipelines/lightrag.py +1 -0
- src/services/rag/pipelines/llamaindex.py +99 -0
- src/services/rag/pipelines/raganything.py +67 -100
- src/services/rag/pipelines/raganything_docling.py +368 -0
- src/services/rag/service.py +5 -12
- src/services/rag/types.py +1 -0
- src/services/rag/utils/__init__.py +17 -0
- src/services/rag/utils/image_migration.py +279 -0
- src/services/search/__init__.py +1 -0
- src/services/search/base.py +1 -0
- src/services/search/consolidation.py +1 -0
- src/services/search/providers/__init__.py +1 -0
- src/services/search/providers/baidu.py +1 -0
- src/services/search/providers/exa.py +1 -0
- src/services/search/providers/jina.py +1 -0
- src/services/search/providers/perplexity.py +1 -0
- src/services/search/providers/serper.py +1 -0
- src/services/search/providers/tavily.py +1 -0
- src/services/search/types.py +1 -0
- src/services/settings/__init__.py +1 -0
- src/services/settings/interface_settings.py +78 -0
- src/services/setup/__init__.py +1 -0
- src/services/tts/__init__.py +1 -0
- src/services/tts/config.py +1 -0
- src/utils/realtimex.py +284 -0
- realtimex_deeptutor-0.5.0.post1.dist-info/entry_points.txt +0 -2
- src/services/rag/pipelines/academic.py +0 -44
- {realtimex_deeptutor-0.5.0.post1.dist-info → realtimex_deeptutor-0.5.0.post3.dist-info}/licenses/LICENSE +0 -0
src/logging/config.py
CHANGED
|
@@ -1,43 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
"""
|
|
2
3
|
Logging Configuration
|
|
3
4
|
=====================
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Unified logging configuration for the entire DeepTutor system.
|
|
7
|
+
A single `level` parameter controls all logging (including RAG modules).
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
10
|
from dataclasses import dataclass
|
|
9
11
|
from pathlib import Path
|
|
10
|
-
from typing import Optional
|
|
12
|
+
from typing import Dict, Optional
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
@dataclass
|
|
14
16
|
class LoggingConfig:
|
|
15
17
|
"""Configuration for the logging system."""
|
|
16
18
|
|
|
19
|
+
# Global log level (controls entire system including RAG modules)
|
|
20
|
+
level: str = "DEBUG"
|
|
21
|
+
|
|
17
22
|
# Output settings
|
|
18
23
|
console_output: bool = True
|
|
19
24
|
file_output: bool = True
|
|
20
25
|
|
|
21
|
-
# Log levels
|
|
22
|
-
console_level: str = "INFO"
|
|
23
|
-
file_level: str = "DEBUG"
|
|
24
|
-
|
|
25
26
|
# Log directory (relative to project root or absolute)
|
|
26
27
|
log_dir: Optional[str] = None
|
|
27
28
|
|
|
29
|
+
# RAG module logger name mapping
|
|
30
|
+
rag_logger_names: Optional[Dict[str, str]] = None
|
|
31
|
+
|
|
28
32
|
# File rotation settings
|
|
29
33
|
max_bytes: int = 10 * 1024 * 1024 # 10MB
|
|
30
34
|
backup_count: int = 5
|
|
31
35
|
|
|
32
|
-
# WebSocket streaming
|
|
33
|
-
websocket_enabled: bool = True
|
|
34
|
-
websocket_queue_size: int = 1000
|
|
35
|
-
|
|
36
|
-
# LightRAG forwarding
|
|
37
|
-
lightrag_forwarding_enabled: bool = True
|
|
38
|
-
lightrag_min_level: str = "INFO"
|
|
39
|
-
lightrag_add_prefix: bool = True
|
|
40
|
-
|
|
41
36
|
|
|
42
37
|
def get_default_log_dir() -> Path:
|
|
43
38
|
"""Get the default log directory."""
|
|
@@ -45,6 +40,22 @@ def get_default_log_dir() -> Path:
|
|
|
45
40
|
return project_root / "data" / "user" / "logs"
|
|
46
41
|
|
|
47
42
|
|
|
43
|
+
def get_global_log_level() -> str:
|
|
44
|
+
"""
|
|
45
|
+
Get the global log level from config/main.yaml -> logging.level
|
|
46
|
+
Default: DEBUG
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
from src.services.config import load_config_with_main
|
|
50
|
+
|
|
51
|
+
project_root = Path(__file__).resolve().parent.parent.parent
|
|
52
|
+
config = load_config_with_main("solve_config.yaml", project_root)
|
|
53
|
+
logging_config = config.get("logging", {})
|
|
54
|
+
return logging_config.get("level", "DEBUG").upper()
|
|
55
|
+
except Exception:
|
|
56
|
+
return "DEBUG"
|
|
57
|
+
|
|
58
|
+
|
|
48
59
|
def load_logging_config() -> LoggingConfig:
|
|
49
60
|
"""
|
|
50
61
|
Load logging configuration from config files.
|
|
@@ -59,22 +70,14 @@ def load_logging_config() -> LoggingConfig:
|
|
|
59
70
|
config = load_config_with_main("solve_config.yaml", project_root)
|
|
60
71
|
|
|
61
72
|
logging_config = config.get("logging", {})
|
|
73
|
+
level = get_global_log_level()
|
|
62
74
|
|
|
63
75
|
return LoggingConfig(
|
|
76
|
+
level=level,
|
|
64
77
|
console_output=logging_config.get("console_output", True),
|
|
65
|
-
file_output=logging_config.get("
|
|
66
|
-
console_level=logging_config.get("console_level", "INFO"),
|
|
67
|
-
file_level=logging_config.get("file_level", "DEBUG"),
|
|
78
|
+
file_output=logging_config.get("save_to_file", True),
|
|
68
79
|
log_dir=get_path_from_config(config, "user_log_dir"),
|
|
69
|
-
|
|
70
|
-
"enabled", True
|
|
71
|
-
),
|
|
72
|
-
lightrag_min_level=logging_config.get("lightrag_forwarding", {}).get(
|
|
73
|
-
"min_level", "INFO"
|
|
74
|
-
),
|
|
75
|
-
lightrag_add_prefix=logging_config.get("lightrag_forwarding", {}).get(
|
|
76
|
-
"add_prefix", True
|
|
77
|
-
),
|
|
80
|
+
rag_logger_names=logging_config.get("rag_logger_names"),
|
|
78
81
|
)
|
|
79
82
|
except Exception:
|
|
80
83
|
return LoggingConfig()
|
src/logging/handlers/__init__.py
CHANGED
src/logging/handlers/console.py
CHANGED
|
@@ -3,59 +3,15 @@
|
|
|
3
3
|
Console Log Handler
|
|
4
4
|
===================
|
|
5
5
|
|
|
6
|
-
Color-coded console output with
|
|
6
|
+
Color-coded console output with standard level tags.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
import sys
|
|
11
|
+
from typing import Optional
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"""
|
|
15
|
-
Clean console formatter with colors and symbols.
|
|
16
|
-
Format: [Module] Symbol Message
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
# ANSI color codes
|
|
20
|
-
COLORS = {
|
|
21
|
-
"DEBUG": "\033[90m", # Gray
|
|
22
|
-
"INFO": "\033[37m", # White
|
|
23
|
-
"SUCCESS": "\033[32m", # Green
|
|
24
|
-
"WARNING": "\033[33m", # Yellow
|
|
25
|
-
"ERROR": "\033[31m", # Red
|
|
26
|
-
"CRITICAL": "\033[35m", # Magenta
|
|
27
|
-
}
|
|
28
|
-
RESET = "\033[0m"
|
|
29
|
-
BOLD = "\033[1m"
|
|
30
|
-
DIM = "\033[2m"
|
|
31
|
-
|
|
32
|
-
# Symbols for different log types
|
|
33
|
-
SYMBOLS = {
|
|
34
|
-
"DEBUG": "·",
|
|
35
|
-
"INFO": "●",
|
|
36
|
-
"SUCCESS": "✓",
|
|
37
|
-
"WARNING": "⚠",
|
|
38
|
-
"ERROR": "✗",
|
|
39
|
-
"CRITICAL": "✗",
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
def format(self, record: logging.LogRecord) -> str:
|
|
43
|
-
# Get module name (padded to 12 chars for alignment)
|
|
44
|
-
module = getattr(record, "module_name", record.name)
|
|
45
|
-
module_padded = f"[{module}]".ljust(14)
|
|
46
|
-
|
|
47
|
-
# Get symbol (can be overridden via record.symbol)
|
|
48
|
-
symbol = getattr(record, "symbol", self.SYMBOLS.get(record.levelname, "●"))
|
|
49
|
-
|
|
50
|
-
# Get color
|
|
51
|
-
level = getattr(record, "display_level", record.levelname)
|
|
52
|
-
color = self.COLORS.get(level, self.COLORS["INFO"])
|
|
53
|
-
|
|
54
|
-
# Format message
|
|
55
|
-
message = record.getMessage()
|
|
56
|
-
|
|
57
|
-
# Build output: [Module] ● Message
|
|
58
|
-
return f"{self.DIM}{module_padded}{self.RESET} {color}{symbol}{self.RESET} {message}"
|
|
13
|
+
# Import ConsoleFormatter from the main logger module to avoid duplication
|
|
14
|
+
from ..logger import ConsoleFormatter
|
|
59
15
|
|
|
60
16
|
|
|
61
17
|
class ConsoleHandler(logging.StreamHandler):
|
|
@@ -63,13 +19,14 @@ class ConsoleHandler(logging.StreamHandler):
|
|
|
63
19
|
Console handler with color-coded output.
|
|
64
20
|
"""
|
|
65
21
|
|
|
66
|
-
def __init__(self, level: int = logging.INFO):
|
|
22
|
+
def __init__(self, level: int = logging.INFO, service_prefix: Optional[str] = None):
|
|
67
23
|
"""
|
|
68
24
|
Initialize console handler.
|
|
69
25
|
|
|
70
26
|
Args:
|
|
71
27
|
level: Minimum log level to display
|
|
28
|
+
service_prefix: Optional service layer prefix (e.g., "Backend", "Frontend")
|
|
72
29
|
"""
|
|
73
30
|
super().__init__(sys.stdout)
|
|
74
31
|
self.setLevel(level)
|
|
75
|
-
self.setFormatter(ConsoleFormatter())
|
|
32
|
+
self.setFormatter(ConsoleFormatter(service_prefix=service_prefix))
|
src/logging/handlers/file.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
"""
|
|
2
3
|
File Log Handlers
|
|
3
4
|
=================
|
|
@@ -13,24 +14,8 @@ from logging.handlers import RotatingFileHandler as BaseRotatingFileHandler
|
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from typing import Optional
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
Detailed file formatter for log files.
|
|
20
|
-
Format: TIMESTAMP [LEVEL] [Module] Message
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(self):
|
|
24
|
-
super().__init__(
|
|
25
|
-
fmt="%(asctime)s [%(levelname)-8s] [%(module_name)-12s] %(message)s",
|
|
26
|
-
datefmt="%Y-%m-%d %H:%M:%S",
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
def format(self, record: logging.LogRecord) -> str:
|
|
30
|
-
# Ensure module_name exists
|
|
31
|
-
if not hasattr(record, "module_name"):
|
|
32
|
-
record.module_name = record.name
|
|
33
|
-
return super().format(record)
|
|
17
|
+
# Import FileFormatter from the main logger module to avoid duplication
|
|
18
|
+
from ..logger import FileFormatter
|
|
34
19
|
|
|
35
20
|
|
|
36
21
|
class FileHandler(logging.FileHandler):
|
|
@@ -143,7 +128,7 @@ class JSONFileHandler(logging.Handler):
|
|
|
143
128
|
}
|
|
144
129
|
|
|
145
130
|
# Add extra fields if present
|
|
146
|
-
for key in ["
|
|
131
|
+
for key in ["display_level", "tool_name", "elapsed_ms", "tokens"]:
|
|
147
132
|
if hasattr(record, key):
|
|
148
133
|
entry[key] = getattr(record, key)
|
|
149
134
|
|
|
@@ -180,7 +165,7 @@ def create_task_logger(
|
|
|
180
165
|
log_path.mkdir(parents=True, exist_ok=True)
|
|
181
166
|
|
|
182
167
|
# Create logger
|
|
183
|
-
logger = logging.getLogger(f"
|
|
168
|
+
logger = logging.getLogger(f"deeptutor.{module_name}.{task_id}")
|
|
184
169
|
logger.setLevel(logging.DEBUG)
|
|
185
170
|
logger.handlers.clear()
|
|
186
171
|
logger.propagate = False
|
|
@@ -8,6 +8,7 @@ Handlers for streaming logs to WebSocket clients.
|
|
|
8
8
|
|
|
9
9
|
import asyncio
|
|
10
10
|
import logging
|
|
11
|
+
from typing import Optional
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class WebSocketLogHandler(logging.Handler):
|
|
@@ -25,27 +26,24 @@ class WebSocketLogHandler(logging.Handler):
|
|
|
25
26
|
await websocket.send_json(log_entry)
|
|
26
27
|
"""
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"ERROR": "✗",
|
|
35
|
-
"CRITICAL": "✗",
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
def __init__(self, queue: asyncio.Queue, include_module: bool = True):
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
queue: asyncio.Queue,
|
|
32
|
+
include_module: bool = True,
|
|
33
|
+
service_prefix: Optional[str] = None,
|
|
34
|
+
):
|
|
39
35
|
"""
|
|
40
36
|
Initialize WebSocket log handler.
|
|
41
37
|
|
|
42
38
|
Args:
|
|
43
39
|
queue: asyncio.Queue to put log entries into
|
|
44
40
|
include_module: Whether to include module name in output
|
|
41
|
+
service_prefix: Optional service layer prefix (e.g., "Backend")
|
|
45
42
|
"""
|
|
46
43
|
super().__init__()
|
|
47
44
|
self.queue = queue
|
|
48
45
|
self.include_module = include_module
|
|
46
|
+
self.service_prefix = service_prefix
|
|
49
47
|
self.setFormatter(logging.Formatter("%(message)s"))
|
|
50
48
|
|
|
51
49
|
def emit(self, record: logging.LogRecord):
|
|
@@ -53,25 +51,31 @@ class WebSocketLogHandler(logging.Handler):
|
|
|
53
51
|
try:
|
|
54
52
|
msg = self.format(record)
|
|
55
53
|
|
|
56
|
-
# Get
|
|
54
|
+
# Get display level
|
|
57
55
|
display_level = getattr(record, "display_level", record.levelname)
|
|
58
|
-
symbol = getattr(record, "symbol", self.SYMBOLS.get(display_level, "●"))
|
|
59
56
|
|
|
60
57
|
# Get module name
|
|
61
58
|
module_name = getattr(record, "module_name", record.name)
|
|
62
59
|
|
|
63
|
-
# Build formatted content
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
# Build formatted content with standard level tags (compact format)
|
|
61
|
+
level_tag = display_level
|
|
62
|
+
if self.service_prefix:
|
|
63
|
+
service_tag = f"[{self.service_prefix}]"
|
|
64
|
+
if self.include_module:
|
|
65
|
+
content = f"{service_tag} {level_tag} [{module_name}] {msg}"
|
|
66
|
+
else:
|
|
67
|
+
content = f"{service_tag} {level_tag} {msg}"
|
|
66
68
|
else:
|
|
67
|
-
|
|
69
|
+
if self.include_module:
|
|
70
|
+
content = f"{level_tag} [{module_name}] {msg}"
|
|
71
|
+
else:
|
|
72
|
+
content = f"{level_tag} {msg}"
|
|
68
73
|
|
|
69
74
|
# Construct structured message
|
|
70
75
|
log_entry = {
|
|
71
76
|
"type": "log",
|
|
72
77
|
"level": display_level,
|
|
73
78
|
"module": module_name,
|
|
74
|
-
"symbol": symbol,
|
|
75
79
|
"content": content,
|
|
76
80
|
"message": msg,
|
|
77
81
|
"timestamp": record.created,
|
|
@@ -93,7 +97,7 @@ class LogInterceptor:
|
|
|
93
97
|
|
|
94
98
|
Usage:
|
|
95
99
|
queue = asyncio.Queue()
|
|
96
|
-
logger = logging.getLogger("
|
|
100
|
+
logger = logging.getLogger("deeptutor.Solver")
|
|
97
101
|
|
|
98
102
|
with LogInterceptor(logger, queue):
|
|
99
103
|
# All logs from this logger will be streamed to queue
|