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,603 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified Configuration Manager
|
|
3
|
+
=============================
|
|
4
|
+
|
|
5
|
+
Manages configurations for LLM, Embedding, TTS, and Search services.
|
|
6
|
+
Supports both .env defaults and user-defined configurations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from enum import Enum
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
import uuid
|
|
16
|
+
|
|
17
|
+
from dotenv import load_dotenv
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Load environment variables
|
|
22
|
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
|
23
|
+
load_dotenv(PROJECT_ROOT / "DeepTutor.env", override=False)
|
|
24
|
+
load_dotenv(PROJECT_ROOT / ".env", override=False)
|
|
25
|
+
|
|
26
|
+
# Storage directory
|
|
27
|
+
SETTINGS_DIR = PROJECT_ROOT / "data" / "user" / "settings"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ConfigType(str, Enum):
|
|
31
|
+
"""Configuration types."""
|
|
32
|
+
|
|
33
|
+
LLM = "llm"
|
|
34
|
+
EMBEDDING = "embedding"
|
|
35
|
+
TTS = "tts"
|
|
36
|
+
SEARCH = "search"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Provider options for each service type
|
|
40
|
+
PROVIDER_OPTIONS = {
|
|
41
|
+
ConfigType.LLM: [
|
|
42
|
+
"openai",
|
|
43
|
+
"anthropic",
|
|
44
|
+
"azure_openai",
|
|
45
|
+
"deepseek",
|
|
46
|
+
"ollama",
|
|
47
|
+
"lm_studio",
|
|
48
|
+
"vllm",
|
|
49
|
+
],
|
|
50
|
+
ConfigType.EMBEDDING: ["openai", "azure_openai", "ollama", "jina", "cohere", "huggingface"],
|
|
51
|
+
ConfigType.TTS: ["openai", "azure_openai"],
|
|
52
|
+
ConfigType.SEARCH: ["perplexity", "tavily", "exa", "jina", "serper", "baidu"],
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Environment variable mappings for each service type
|
|
56
|
+
ENV_VAR_MAPPINGS = {
|
|
57
|
+
ConfigType.LLM: {
|
|
58
|
+
"provider": "LLM_BINDING",
|
|
59
|
+
"base_url": "LLM_HOST",
|
|
60
|
+
"api_key": "LLM_API_KEY",
|
|
61
|
+
"model": "LLM_MODEL",
|
|
62
|
+
"api_version": "LLM_API_VERSION",
|
|
63
|
+
},
|
|
64
|
+
ConfigType.EMBEDDING: {
|
|
65
|
+
"provider": "EMBEDDING_BINDING",
|
|
66
|
+
"base_url": "EMBEDDING_HOST",
|
|
67
|
+
"api_key": "EMBEDDING_API_KEY",
|
|
68
|
+
"model": "EMBEDDING_MODEL",
|
|
69
|
+
"dimensions": "EMBEDDING_DIMENSION",
|
|
70
|
+
"api_version": "EMBEDDING_API_VERSION",
|
|
71
|
+
},
|
|
72
|
+
ConfigType.TTS: {
|
|
73
|
+
"provider": "TTS_BINDING",
|
|
74
|
+
"base_url": "TTS_URL",
|
|
75
|
+
"api_key": "TTS_API_KEY",
|
|
76
|
+
"model": "TTS_MODEL",
|
|
77
|
+
"voice": "TTS_VOICE",
|
|
78
|
+
"api_version": "TTS_BINDING_API_VERSION",
|
|
79
|
+
},
|
|
80
|
+
ConfigType.SEARCH: {
|
|
81
|
+
"provider": "SEARCH_PROVIDER",
|
|
82
|
+
"api_key": "SEARCH_API_KEY", # Unified API key for all providers
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _resolve_env_value(value: Any) -> Any:
|
|
88
|
+
"""
|
|
89
|
+
Resolve a value that may reference an environment variable.
|
|
90
|
+
|
|
91
|
+
If value is {"use_env": "VAR_NAME"}, returns os.environ.get("VAR_NAME").
|
|
92
|
+
Otherwise, returns the value as-is.
|
|
93
|
+
"""
|
|
94
|
+
if isinstance(value, dict) and "use_env" in value:
|
|
95
|
+
env_var = value["use_env"]
|
|
96
|
+
return os.environ.get(env_var, "")
|
|
97
|
+
return value
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _get_env_value(env_var: str) -> Optional[str]:
|
|
101
|
+
"""Get and strip an environment variable value."""
|
|
102
|
+
value = os.environ.get(env_var)
|
|
103
|
+
if value:
|
|
104
|
+
return value.strip().strip("\"'")
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class UnifiedConfigManager:
|
|
109
|
+
"""
|
|
110
|
+
Manages configurations for all service types.
|
|
111
|
+
|
|
112
|
+
Each service type has:
|
|
113
|
+
- A "default" configuration that comes from .env (cannot be deleted)
|
|
114
|
+
- User-defined configurations that can be added/edited/deleted
|
|
115
|
+
- An "active" configuration that is currently in use
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
_instance: Optional["UnifiedConfigManager"] = None
|
|
119
|
+
|
|
120
|
+
def __new__(cls):
|
|
121
|
+
if cls._instance is None:
|
|
122
|
+
cls._instance = super(UnifiedConfigManager, cls).__new__(cls)
|
|
123
|
+
cls._instance._initialized = False
|
|
124
|
+
return cls._instance
|
|
125
|
+
|
|
126
|
+
def __init__(self):
|
|
127
|
+
if getattr(self, "_initialized", False):
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
SETTINGS_DIR.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
self._initialized = True
|
|
132
|
+
|
|
133
|
+
# Ensure default configs exist and are synced with env on startup
|
|
134
|
+
self._ensure_default_configs()
|
|
135
|
+
|
|
136
|
+
def _ensure_default_configs(self) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Ensure default configurations exist in storage files and sync with env.
|
|
139
|
+
|
|
140
|
+
This method is called on startup to:
|
|
141
|
+
1. Create a "default" config entry in each config file if it doesn't exist
|
|
142
|
+
2. Sync the model/provider fields from env variables (these may change)
|
|
143
|
+
3. Store base_url/api_key as {"use_env": "VAR_NAME"} references
|
|
144
|
+
"""
|
|
145
|
+
for config_type in ConfigType:
|
|
146
|
+
try:
|
|
147
|
+
self._ensure_default_config_for_type(config_type)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.warning(f"Failed to ensure default config for {config_type.value}: {e}")
|
|
150
|
+
|
|
151
|
+
def _ensure_default_config_for_type(self, config_type: ConfigType) -> None:
|
|
152
|
+
"""Ensure default config exists and is synced for a specific config type."""
|
|
153
|
+
env_mapping = ENV_VAR_MAPPINGS.get(config_type, {})
|
|
154
|
+
data = self._load_configs(config_type)
|
|
155
|
+
|
|
156
|
+
# Find existing default config in the configs list
|
|
157
|
+
default_config = None
|
|
158
|
+
default_index = -1
|
|
159
|
+
for i, cfg in enumerate(data.get("configs", [])):
|
|
160
|
+
if cfg.get("id") == "default":
|
|
161
|
+
default_config = cfg
|
|
162
|
+
default_index = i
|
|
163
|
+
break
|
|
164
|
+
|
|
165
|
+
# Build the default config to store
|
|
166
|
+
stored_default = self._build_stored_default_config(config_type, env_mapping)
|
|
167
|
+
|
|
168
|
+
if default_config is None:
|
|
169
|
+
# Add default config to the list
|
|
170
|
+
if "configs" not in data:
|
|
171
|
+
data["configs"] = []
|
|
172
|
+
data["configs"].insert(0, stored_default)
|
|
173
|
+
logger.info(f"Created default config for {config_type.value}")
|
|
174
|
+
else:
|
|
175
|
+
# Update only the dynamic fields (model, provider) from env
|
|
176
|
+
# Keep other fields unchanged (they reference env vars)
|
|
177
|
+
if config_type == ConfigType.LLM:
|
|
178
|
+
default_config["model"] = _get_env_value(env_mapping.get("model")) or ""
|
|
179
|
+
default_config["provider"] = _get_env_value(env_mapping.get("provider")) or "openai"
|
|
180
|
+
elif config_type == ConfigType.EMBEDDING:
|
|
181
|
+
default_config["model"] = _get_env_value(env_mapping.get("model")) or ""
|
|
182
|
+
default_config["provider"] = _get_env_value(env_mapping.get("provider")) or "openai"
|
|
183
|
+
dim_str = _get_env_value(env_mapping.get("dimensions"))
|
|
184
|
+
default_config["dimensions"] = (
|
|
185
|
+
int(dim_str) if dim_str and dim_str.isdigit() else 3072
|
|
186
|
+
)
|
|
187
|
+
elif config_type == ConfigType.TTS:
|
|
188
|
+
default_config["model"] = _get_env_value(env_mapping.get("model")) or ""
|
|
189
|
+
default_config["provider"] = _get_env_value(env_mapping.get("provider")) or "openai"
|
|
190
|
+
default_config["voice"] = _get_env_value(env_mapping.get("voice")) or "alloy"
|
|
191
|
+
elif config_type == ConfigType.SEARCH:
|
|
192
|
+
default_config["provider"] = (
|
|
193
|
+
_get_env_value(env_mapping.get("provider")) or "perplexity"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
data["configs"][default_index] = default_config
|
|
197
|
+
logger.debug(f"Updated default config for {config_type.value}")
|
|
198
|
+
|
|
199
|
+
self._save_configs(config_type, data)
|
|
200
|
+
|
|
201
|
+
def _build_stored_default_config(
|
|
202
|
+
self, config_type: ConfigType, env_mapping: Dict[str, str]
|
|
203
|
+
) -> Dict[str, Any]:
|
|
204
|
+
"""Build the default configuration to be stored in JSON (with env references)."""
|
|
205
|
+
base_config = {
|
|
206
|
+
"id": "default",
|
|
207
|
+
"name": "Default (from .env)",
|
|
208
|
+
"is_default": True,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if config_type == ConfigType.LLM:
|
|
212
|
+
return {
|
|
213
|
+
**base_config,
|
|
214
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
215
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
216
|
+
"base_url": {"use_env": "LLM_HOST"},
|
|
217
|
+
"api_key": {"use_env": "LLM_API_KEY"},
|
|
218
|
+
"api_version": {"use_env": "LLM_API_VERSION"},
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
elif config_type == ConfigType.EMBEDDING:
|
|
222
|
+
dim_str = _get_env_value(env_mapping.get("dimensions"))
|
|
223
|
+
return {
|
|
224
|
+
**base_config,
|
|
225
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
226
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
227
|
+
"dimensions": int(dim_str) if dim_str and dim_str.isdigit() else 3072,
|
|
228
|
+
"base_url": {"use_env": "EMBEDDING_HOST"},
|
|
229
|
+
"api_key": {"use_env": "EMBEDDING_API_KEY"},
|
|
230
|
+
"api_version": {"use_env": "EMBEDDING_API_VERSION"},
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
elif config_type == ConfigType.TTS:
|
|
234
|
+
return {
|
|
235
|
+
**base_config,
|
|
236
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
237
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
238
|
+
"voice": _get_env_value(env_mapping.get("voice")) or "alloy",
|
|
239
|
+
"base_url": {"use_env": "TTS_URL"},
|
|
240
|
+
"api_key": {"use_env": "TTS_API_KEY"},
|
|
241
|
+
"api_version": {"use_env": "TTS_BINDING_API_VERSION"},
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
elif config_type == ConfigType.SEARCH:
|
|
245
|
+
return {
|
|
246
|
+
**base_config,
|
|
247
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "perplexity",
|
|
248
|
+
"api_key": {"use_env": "SEARCH_API_KEY"},
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return base_config
|
|
252
|
+
|
|
253
|
+
def _get_storage_path(self, config_type: ConfigType) -> Path:
|
|
254
|
+
"""Get the storage file path for a config type."""
|
|
255
|
+
return SETTINGS_DIR / f"{config_type.value}_configs.json"
|
|
256
|
+
|
|
257
|
+
def _load_configs(self, config_type: ConfigType) -> Dict[str, Any]:
|
|
258
|
+
"""Load configurations from storage."""
|
|
259
|
+
path = self._get_storage_path(config_type)
|
|
260
|
+
if path.exists():
|
|
261
|
+
try:
|
|
262
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
263
|
+
return json.load(f)
|
|
264
|
+
except (json.JSONDecodeError, IOError) as e:
|
|
265
|
+
logger.warning(f"Failed to load {config_type.value} configs: {e}")
|
|
266
|
+
return {"configs": [], "active_id": "default"}
|
|
267
|
+
|
|
268
|
+
def _save_configs(self, config_type: ConfigType, data: Dict[str, Any]) -> bool:
|
|
269
|
+
"""Save configurations to storage."""
|
|
270
|
+
path = self._get_storage_path(config_type)
|
|
271
|
+
try:
|
|
272
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
273
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
274
|
+
return True
|
|
275
|
+
except IOError as e:
|
|
276
|
+
logger.error(f"Failed to save {config_type.value} configs: {e}")
|
|
277
|
+
return False
|
|
278
|
+
|
|
279
|
+
def _build_default_config(self, config_type: ConfigType) -> Dict[str, Any]:
|
|
280
|
+
"""Build the default configuration from environment variables."""
|
|
281
|
+
env_mapping = ENV_VAR_MAPPINGS.get(config_type, {})
|
|
282
|
+
|
|
283
|
+
if config_type == ConfigType.LLM:
|
|
284
|
+
return {
|
|
285
|
+
"id": "default",
|
|
286
|
+
"name": "Default (from .env)",
|
|
287
|
+
"is_default": True,
|
|
288
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
289
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
290
|
+
"api_key": "***", # Hidden for security
|
|
291
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
292
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
elif config_type == ConfigType.EMBEDDING:
|
|
296
|
+
dim_str = _get_env_value(env_mapping.get("dimensions"))
|
|
297
|
+
return {
|
|
298
|
+
"id": "default",
|
|
299
|
+
"name": "Default (from .env)",
|
|
300
|
+
"is_default": True,
|
|
301
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
302
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
303
|
+
"api_key": "***",
|
|
304
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
305
|
+
"dimensions": int(dim_str) if dim_str and dim_str.isdigit() else 3072,
|
|
306
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
elif config_type == ConfigType.TTS:
|
|
310
|
+
return {
|
|
311
|
+
"id": "default",
|
|
312
|
+
"name": "Default (from .env)",
|
|
313
|
+
"is_default": True,
|
|
314
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
315
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
316
|
+
"api_key": "***",
|
|
317
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
318
|
+
"voice": _get_env_value(env_mapping.get("voice")) or "alloy",
|
|
319
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
elif config_type == ConfigType.SEARCH:
|
|
323
|
+
provider = _get_env_value(env_mapping.get("provider")) or "perplexity"
|
|
324
|
+
return {
|
|
325
|
+
"id": "default",
|
|
326
|
+
"name": "Default (from .env)",
|
|
327
|
+
"is_default": True,
|
|
328
|
+
"provider": provider,
|
|
329
|
+
"api_key": "***",
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {"id": "default", "name": "Default (from .env)", "is_default": True}
|
|
333
|
+
|
|
334
|
+
def _get_default_config_resolved(self, config_type: ConfigType) -> Dict[str, Any]:
|
|
335
|
+
"""Get the default configuration with actual values resolved (for internal use)."""
|
|
336
|
+
env_mapping = ENV_VAR_MAPPINGS.get(config_type, {})
|
|
337
|
+
|
|
338
|
+
if config_type == ConfigType.LLM:
|
|
339
|
+
return {
|
|
340
|
+
"id": "default",
|
|
341
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
342
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
343
|
+
"api_key": _get_env_value(env_mapping.get("api_key")) or "",
|
|
344
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
345
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
elif config_type == ConfigType.EMBEDDING:
|
|
349
|
+
dim_str = _get_env_value(env_mapping.get("dimensions"))
|
|
350
|
+
return {
|
|
351
|
+
"id": "default",
|
|
352
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
353
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
354
|
+
"api_key": _get_env_value(env_mapping.get("api_key")) or "",
|
|
355
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
356
|
+
"dimensions": int(dim_str) if dim_str and dim_str.isdigit() else 3072,
|
|
357
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
elif config_type == ConfigType.TTS:
|
|
361
|
+
return {
|
|
362
|
+
"id": "default",
|
|
363
|
+
"provider": _get_env_value(env_mapping.get("provider")) or "openai",
|
|
364
|
+
"base_url": _get_env_value(env_mapping.get("base_url")) or "",
|
|
365
|
+
"api_key": _get_env_value(env_mapping.get("api_key")) or "",
|
|
366
|
+
"model": _get_env_value(env_mapping.get("model")) or "",
|
|
367
|
+
"voice": _get_env_value(env_mapping.get("voice")) or "alloy",
|
|
368
|
+
"api_version": _get_env_value(env_mapping.get("api_version")),
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
elif config_type == ConfigType.SEARCH:
|
|
372
|
+
provider = _get_env_value(env_mapping.get("provider")) or "perplexity"
|
|
373
|
+
return {
|
|
374
|
+
"id": "default",
|
|
375
|
+
"provider": provider,
|
|
376
|
+
"api_key": _get_env_value(env_mapping.get("api_key")) or "",
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return {"id": "default"}
|
|
380
|
+
|
|
381
|
+
def _resolve_config(self, config: Dict[str, Any], config_type: ConfigType) -> Dict[str, Any]:
|
|
382
|
+
"""Resolve all {"use_env": ...} references in a configuration."""
|
|
383
|
+
resolved = {}
|
|
384
|
+
env_mapping = ENV_VAR_MAPPINGS.get(config_type, {})
|
|
385
|
+
|
|
386
|
+
for key, value in config.items():
|
|
387
|
+
if isinstance(value, dict) and "use_env" in value:
|
|
388
|
+
env_var = value["use_env"]
|
|
389
|
+
resolved[key] = _get_env_value(env_var) or ""
|
|
390
|
+
else:
|
|
391
|
+
resolved[key] = value
|
|
392
|
+
|
|
393
|
+
return resolved
|
|
394
|
+
|
|
395
|
+
def get_provider_options(self, config_type: ConfigType) -> List[str]:
|
|
396
|
+
"""Get available provider options for a config type."""
|
|
397
|
+
return PROVIDER_OPTIONS.get(config_type, [])
|
|
398
|
+
|
|
399
|
+
def list_configs(self, config_type: ConfigType) -> List[Dict[str, Any]]:
|
|
400
|
+
"""
|
|
401
|
+
List all configurations for a service type.
|
|
402
|
+
Includes the default config (from .env) and user-defined configs.
|
|
403
|
+
|
|
404
|
+
For display purposes, the default config shows:
|
|
405
|
+
- Current model/provider from env (dynamically refreshed)
|
|
406
|
+
- base_url/api_key as "***" (hidden for security)
|
|
407
|
+
"""
|
|
408
|
+
data = self._load_configs(config_type)
|
|
409
|
+
configs = data.get("configs", [])
|
|
410
|
+
active_id = data.get("active_id", "default")
|
|
411
|
+
|
|
412
|
+
# Build a display version of the default config (with current env values)
|
|
413
|
+
display_default = self._build_default_config(config_type)
|
|
414
|
+
|
|
415
|
+
# Process all configs for display
|
|
416
|
+
result = []
|
|
417
|
+
has_default = False
|
|
418
|
+
|
|
419
|
+
for cfg in configs:
|
|
420
|
+
if cfg.get("id") == "default":
|
|
421
|
+
# Use the dynamically built display config for default
|
|
422
|
+
has_default = True
|
|
423
|
+
display_cfg = display_default.copy()
|
|
424
|
+
display_cfg["is_active"] = active_id == "default"
|
|
425
|
+
result.append(display_cfg)
|
|
426
|
+
else:
|
|
427
|
+
# For user configs, create a display copy
|
|
428
|
+
display_cfg = dict(cfg)
|
|
429
|
+
# Hide api_key if it's not an env reference
|
|
430
|
+
if "api_key" in display_cfg:
|
|
431
|
+
api_key = display_cfg["api_key"]
|
|
432
|
+
if not isinstance(api_key, dict): # Not {"use_env": ...}
|
|
433
|
+
display_cfg["api_key"] = "***"
|
|
434
|
+
display_cfg["is_active"] = cfg.get("id") == active_id
|
|
435
|
+
result.append(display_cfg)
|
|
436
|
+
|
|
437
|
+
# If no default config found in file, prepend the display default
|
|
438
|
+
if not has_default:
|
|
439
|
+
display_default["is_active"] = active_id == "default"
|
|
440
|
+
result.insert(0, display_default)
|
|
441
|
+
|
|
442
|
+
return result
|
|
443
|
+
|
|
444
|
+
def get_config(self, config_type: ConfigType, config_id: str) -> Optional[Dict[str, Any]]:
|
|
445
|
+
"""Get a specific configuration by ID."""
|
|
446
|
+
if config_id == "default":
|
|
447
|
+
return self._build_default_config(config_type)
|
|
448
|
+
|
|
449
|
+
data = self._load_configs(config_type)
|
|
450
|
+
for cfg in data.get("configs", []):
|
|
451
|
+
if cfg.get("id") == config_id:
|
|
452
|
+
return cfg
|
|
453
|
+
return None
|
|
454
|
+
|
|
455
|
+
def get_active_config(self, config_type: ConfigType) -> Optional[Dict[str, Any]]:
|
|
456
|
+
"""
|
|
457
|
+
Get the currently active configuration with all values resolved.
|
|
458
|
+
This is used internally when services need actual configuration values.
|
|
459
|
+
"""
|
|
460
|
+
data = self._load_configs(config_type)
|
|
461
|
+
active_id = data.get("active_id", "default")
|
|
462
|
+
|
|
463
|
+
if active_id == "default":
|
|
464
|
+
return self._get_default_config_resolved(config_type)
|
|
465
|
+
|
|
466
|
+
for cfg in data.get("configs", []):
|
|
467
|
+
if cfg.get("id") == active_id:
|
|
468
|
+
return self._resolve_config(cfg, config_type)
|
|
469
|
+
|
|
470
|
+
# Fallback to default if active config not found
|
|
471
|
+
return self._get_default_config_resolved(config_type)
|
|
472
|
+
|
|
473
|
+
def add_config(self, config_type: ConfigType, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
474
|
+
"""Add a new configuration."""
|
|
475
|
+
data = self._load_configs(config_type)
|
|
476
|
+
|
|
477
|
+
# Generate ID if not provided
|
|
478
|
+
if "id" not in config:
|
|
479
|
+
config["id"] = str(uuid.uuid4())[:8]
|
|
480
|
+
|
|
481
|
+
# Ensure required fields
|
|
482
|
+
config["is_default"] = False
|
|
483
|
+
|
|
484
|
+
# Add to list
|
|
485
|
+
data["configs"].append(config)
|
|
486
|
+
self._save_configs(config_type, data)
|
|
487
|
+
|
|
488
|
+
return config
|
|
489
|
+
|
|
490
|
+
def update_config(
|
|
491
|
+
self, config_type: ConfigType, config_id: str, updates: Dict[str, Any]
|
|
492
|
+
) -> Optional[Dict[str, Any]]:
|
|
493
|
+
"""Update an existing configuration."""
|
|
494
|
+
if config_id == "default":
|
|
495
|
+
return None # Cannot update default config
|
|
496
|
+
|
|
497
|
+
data = self._load_configs(config_type)
|
|
498
|
+
|
|
499
|
+
for i, cfg in enumerate(data.get("configs", [])):
|
|
500
|
+
if cfg.get("id") == config_id:
|
|
501
|
+
# Update fields
|
|
502
|
+
cfg.update(updates)
|
|
503
|
+
cfg["id"] = config_id # Preserve ID
|
|
504
|
+
cfg["is_default"] = False # Ensure it's not marked as default
|
|
505
|
+
data["configs"][i] = cfg
|
|
506
|
+
self._save_configs(config_type, data)
|
|
507
|
+
return cfg
|
|
508
|
+
|
|
509
|
+
return None
|
|
510
|
+
|
|
511
|
+
def delete_config(self, config_type: ConfigType, config_id: str) -> bool:
|
|
512
|
+
"""Delete a configuration."""
|
|
513
|
+
if config_id == "default":
|
|
514
|
+
return False # Cannot delete default config
|
|
515
|
+
|
|
516
|
+
data = self._load_configs(config_type)
|
|
517
|
+
original_len = len(data.get("configs", []))
|
|
518
|
+
data["configs"] = [c for c in data.get("configs", []) if c.get("id") != config_id]
|
|
519
|
+
|
|
520
|
+
if len(data["configs"]) < original_len:
|
|
521
|
+
# If deleted config was active, switch to default
|
|
522
|
+
if data.get("active_id") == config_id:
|
|
523
|
+
data["active_id"] = "default"
|
|
524
|
+
self._save_configs(config_type, data)
|
|
525
|
+
return True
|
|
526
|
+
|
|
527
|
+
return False
|
|
528
|
+
|
|
529
|
+
def set_active_config(self, config_type: ConfigType, config_id: str) -> bool:
|
|
530
|
+
"""Set a configuration as active."""
|
|
531
|
+
data = self._load_configs(config_type)
|
|
532
|
+
|
|
533
|
+
# Verify config exists
|
|
534
|
+
if config_id != "default":
|
|
535
|
+
found = any(c.get("id") == config_id for c in data.get("configs", []))
|
|
536
|
+
if not found:
|
|
537
|
+
return False
|
|
538
|
+
|
|
539
|
+
data["active_id"] = config_id
|
|
540
|
+
return self._save_configs(config_type, data)
|
|
541
|
+
|
|
542
|
+
def get_env_status(self, config_type: ConfigType) -> Dict[str, bool]:
|
|
543
|
+
"""Check which environment variables are configured for a service type."""
|
|
544
|
+
env_mapping = ENV_VAR_MAPPINGS.get(config_type, {})
|
|
545
|
+
status = {}
|
|
546
|
+
|
|
547
|
+
for field, env_var in env_mapping.items():
|
|
548
|
+
if not env_var.endswith("_key"): # Skip individual search provider keys
|
|
549
|
+
status[field] = bool(_get_env_value(env_var))
|
|
550
|
+
|
|
551
|
+
return status
|
|
552
|
+
|
|
553
|
+
def get_default_config(self, config_type: ConfigType) -> Dict[str, Any]:
|
|
554
|
+
"""
|
|
555
|
+
Get the default configuration with actual values resolved.
|
|
556
|
+
Used for testing the default configuration.
|
|
557
|
+
"""
|
|
558
|
+
return self._get_default_config_resolved(config_type)
|
|
559
|
+
|
|
560
|
+
def resolve_config_env_values(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
561
|
+
"""
|
|
562
|
+
Resolve all {"use_env": "VAR_NAME"} references in a user configuration.
|
|
563
|
+
Returns a copy with actual values from environment variables.
|
|
564
|
+
"""
|
|
565
|
+
resolved = dict(config)
|
|
566
|
+
for key, value in config.items():
|
|
567
|
+
if isinstance(value, dict) and "use_env" in value:
|
|
568
|
+
env_var = value["use_env"]
|
|
569
|
+
resolved[key] = _get_env_value(env_var) or ""
|
|
570
|
+
return resolved
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
# Global instance
|
|
574
|
+
_config_manager: Optional[UnifiedConfigManager] = None
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def get_config_manager() -> UnifiedConfigManager:
|
|
578
|
+
"""Get the global config manager instance."""
|
|
579
|
+
global _config_manager
|
|
580
|
+
if _config_manager is None:
|
|
581
|
+
_config_manager = UnifiedConfigManager()
|
|
582
|
+
return _config_manager
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
# Convenience functions for services
|
|
586
|
+
def get_active_llm_config() -> Optional[Dict[str, Any]]:
|
|
587
|
+
"""Get the active LLM configuration."""
|
|
588
|
+
return get_config_manager().get_active_config(ConfigType.LLM)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def get_active_embedding_config() -> Optional[Dict[str, Any]]:
|
|
592
|
+
"""Get the active embedding configuration."""
|
|
593
|
+
return get_config_manager().get_active_config(ConfigType.EMBEDDING)
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
def get_active_tts_config() -> Optional[Dict[str, Any]]:
|
|
597
|
+
"""Get the active TTS configuration."""
|
|
598
|
+
return get_config_manager().get_active_config(ConfigType.TTS)
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def get_active_search_config() -> Optional[Dict[str, Any]]:
|
|
602
|
+
"""Get the active search configuration."""
|
|
603
|
+
return get_config_manager().get_active_config(ConfigType.SEARCH)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Embedding Service
|
|
3
|
+
=================
|
|
4
|
+
|
|
5
|
+
Unified embedding client for all DeepTutor modules.
|
|
6
|
+
Supports multiple providers: OpenAI, Azure, Google, Cohere, Ollama, Jina, HuggingFace.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from src.services.embedding import get_embedding_client, EmbeddingClient, EmbeddingConfig
|
|
10
|
+
|
|
11
|
+
# Get singleton client
|
|
12
|
+
client = get_embedding_client()
|
|
13
|
+
vectors = await client.embed(["text1", "text2"])
|
|
14
|
+
|
|
15
|
+
# Get LightRAG-compatible EmbeddingFunc
|
|
16
|
+
embed_func = client.get_embedding_func()
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .adapters import (
|
|
20
|
+
BaseEmbeddingAdapter,
|
|
21
|
+
CohereEmbeddingAdapter,
|
|
22
|
+
EmbeddingRequest,
|
|
23
|
+
EmbeddingResponse,
|
|
24
|
+
OllamaEmbeddingAdapter,
|
|
25
|
+
OpenAICompatibleEmbeddingAdapter,
|
|
26
|
+
)
|
|
27
|
+
from .client import EmbeddingClient, get_embedding_client, reset_embedding_client
|
|
28
|
+
from .config import EmbeddingConfig, get_embedding_config
|
|
29
|
+
from .provider import get_embedding_provider_manager, reset_embedding_provider_manager
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"EmbeddingClient",
|
|
33
|
+
"EmbeddingConfig",
|
|
34
|
+
"get_embedding_client",
|
|
35
|
+
"get_embedding_config",
|
|
36
|
+
"reset_embedding_client",
|
|
37
|
+
"get_embedding_provider_manager",
|
|
38
|
+
"reset_embedding_provider_manager",
|
|
39
|
+
"BaseEmbeddingAdapter",
|
|
40
|
+
"EmbeddingRequest",
|
|
41
|
+
"EmbeddingResponse",
|
|
42
|
+
"OpenAICompatibleEmbeddingAdapter",
|
|
43
|
+
"CohereEmbeddingAdapter",
|
|
44
|
+
"OllamaEmbeddingAdapter",
|
|
45
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Adapters Package
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
Embedding adapters for different providers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .base import BaseEmbeddingAdapter, EmbeddingRequest, EmbeddingResponse
|
|
9
|
+
from .cohere import CohereEmbeddingAdapter
|
|
10
|
+
from .jina import JinaEmbeddingAdapter
|
|
11
|
+
from .ollama import OllamaEmbeddingAdapter
|
|
12
|
+
from .openai_compatible import OpenAICompatibleEmbeddingAdapter
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BaseEmbeddingAdapter",
|
|
16
|
+
"EmbeddingRequest",
|
|
17
|
+
"EmbeddingResponse",
|
|
18
|
+
"OpenAICompatibleEmbeddingAdapter",
|
|
19
|
+
"JinaEmbeddingAdapter",
|
|
20
|
+
"CohereEmbeddingAdapter",
|
|
21
|
+
"OllamaEmbeddingAdapter",
|
|
22
|
+
]
|