local-deep-research 0.1.26__py3-none-any.whl → 0.2.0__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.
- local_deep_research/__init__.py +23 -22
- local_deep_research/__main__.py +16 -0
- local_deep_research/advanced_search_system/__init__.py +7 -0
- local_deep_research/advanced_search_system/filters/__init__.py +8 -0
- local_deep_research/advanced_search_system/filters/base_filter.py +38 -0
- local_deep_research/advanced_search_system/filters/cross_engine_filter.py +200 -0
- local_deep_research/advanced_search_system/findings/base_findings.py +81 -0
- local_deep_research/advanced_search_system/findings/repository.py +452 -0
- local_deep_research/advanced_search_system/knowledge/__init__.py +1 -0
- local_deep_research/advanced_search_system/knowledge/base_knowledge.py +151 -0
- local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +159 -0
- local_deep_research/advanced_search_system/questions/__init__.py +1 -0
- local_deep_research/advanced_search_system/questions/base_question.py +64 -0
- local_deep_research/advanced_search_system/questions/decomposition_question.py +445 -0
- local_deep_research/advanced_search_system/questions/standard_question.py +119 -0
- local_deep_research/advanced_search_system/repositories/__init__.py +7 -0
- local_deep_research/advanced_search_system/strategies/__init__.py +1 -0
- local_deep_research/advanced_search_system/strategies/base_strategy.py +118 -0
- local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +450 -0
- local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +312 -0
- local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +270 -0
- local_deep_research/advanced_search_system/strategies/standard_strategy.py +300 -0
- local_deep_research/advanced_search_system/tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/base_tool.py +100 -0
- local_deep_research/advanced_search_system/tools/knowledge_tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/question_tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/search_tools/__init__.py +1 -0
- local_deep_research/api/__init__.py +5 -5
- local_deep_research/api/research_functions.py +96 -84
- local_deep_research/app.py +8 -0
- local_deep_research/citation_handler.py +25 -16
- local_deep_research/{config.py → config/config_files.py} +102 -110
- local_deep_research/config/llm_config.py +472 -0
- local_deep_research/config/search_config.py +77 -0
- local_deep_research/defaults/__init__.py +10 -5
- local_deep_research/defaults/main.toml +2 -2
- local_deep_research/defaults/search_engines.toml +60 -34
- local_deep_research/main.py +121 -19
- local_deep_research/migrate_db.py +147 -0
- local_deep_research/report_generator.py +72 -44
- local_deep_research/search_system.py +147 -283
- local_deep_research/setup_data_dir.py +35 -0
- local_deep_research/test_migration.py +178 -0
- local_deep_research/utilities/__init__.py +0 -0
- local_deep_research/utilities/db_utils.py +49 -0
- local_deep_research/{utilties → utilities}/enums.py +2 -2
- local_deep_research/{utilties → utilities}/llm_utils.py +63 -29
- local_deep_research/utilities/search_utilities.py +242 -0
- local_deep_research/{utilties → utilities}/setup_utils.py +4 -2
- local_deep_research/web/__init__.py +0 -1
- local_deep_research/web/app.py +86 -1709
- local_deep_research/web/app_factory.py +289 -0
- local_deep_research/web/database/README.md +70 -0
- local_deep_research/web/database/migrate_to_ldr_db.py +289 -0
- local_deep_research/web/database/migrations.py +447 -0
- local_deep_research/web/database/models.py +117 -0
- local_deep_research/web/database/schema_upgrade.py +107 -0
- local_deep_research/web/models/database.py +294 -0
- local_deep_research/web/models/settings.py +94 -0
- local_deep_research/web/routes/api_routes.py +559 -0
- local_deep_research/web/routes/history_routes.py +354 -0
- local_deep_research/web/routes/research_routes.py +715 -0
- local_deep_research/web/routes/settings_routes.py +1592 -0
- local_deep_research/web/services/research_service.py +947 -0
- local_deep_research/web/services/resource_service.py +149 -0
- local_deep_research/web/services/settings_manager.py +669 -0
- local_deep_research/web/services/settings_service.py +187 -0
- local_deep_research/web/services/socket_service.py +210 -0
- local_deep_research/web/static/css/custom_dropdown.css +277 -0
- local_deep_research/web/static/css/settings.css +1223 -0
- local_deep_research/web/static/css/styles.css +525 -48
- local_deep_research/web/static/js/components/custom_dropdown.js +428 -0
- local_deep_research/web/static/js/components/detail.js +348 -0
- local_deep_research/web/static/js/components/fallback/formatting.js +122 -0
- local_deep_research/web/static/js/components/fallback/ui.js +215 -0
- local_deep_research/web/static/js/components/history.js +487 -0
- local_deep_research/web/static/js/components/logpanel.js +949 -0
- local_deep_research/web/static/js/components/progress.js +1107 -0
- local_deep_research/web/static/js/components/research.js +1865 -0
- local_deep_research/web/static/js/components/results.js +766 -0
- local_deep_research/web/static/js/components/settings.js +3981 -0
- local_deep_research/web/static/js/components/settings_sync.js +106 -0
- local_deep_research/web/static/js/main.js +226 -0
- local_deep_research/web/static/js/services/api.js +253 -0
- local_deep_research/web/static/js/services/audio.js +31 -0
- local_deep_research/web/static/js/services/formatting.js +119 -0
- local_deep_research/web/static/js/services/pdf.js +622 -0
- local_deep_research/web/static/js/services/socket.js +882 -0
- local_deep_research/web/static/js/services/ui.js +546 -0
- local_deep_research/web/templates/base.html +72 -0
- local_deep_research/web/templates/components/custom_dropdown.html +47 -0
- local_deep_research/web/templates/components/log_panel.html +32 -0
- local_deep_research/web/templates/components/mobile_nav.html +22 -0
- local_deep_research/web/templates/components/settings_form.html +299 -0
- local_deep_research/web/templates/components/sidebar.html +21 -0
- local_deep_research/web/templates/pages/details.html +73 -0
- local_deep_research/web/templates/pages/history.html +51 -0
- local_deep_research/web/templates/pages/progress.html +57 -0
- local_deep_research/web/templates/pages/research.html +139 -0
- local_deep_research/web/templates/pages/results.html +59 -0
- local_deep_research/web/templates/settings_dashboard.html +78 -192
- local_deep_research/web/utils/__init__.py +0 -0
- local_deep_research/web/utils/formatters.py +76 -0
- local_deep_research/web_search_engines/engines/full_search.py +18 -16
- local_deep_research/web_search_engines/engines/meta_search_engine.py +182 -131
- local_deep_research/web_search_engines/engines/search_engine_arxiv.py +224 -139
- local_deep_research/web_search_engines/engines/search_engine_brave.py +88 -71
- local_deep_research/web_search_engines/engines/search_engine_ddg.py +48 -39
- local_deep_research/web_search_engines/engines/search_engine_github.py +415 -204
- local_deep_research/web_search_engines/engines/search_engine_google_pse.py +123 -90
- local_deep_research/web_search_engines/engines/search_engine_guardian.py +210 -157
- local_deep_research/web_search_engines/engines/search_engine_local.py +532 -369
- local_deep_research/web_search_engines/engines/search_engine_local_all.py +42 -36
- local_deep_research/web_search_engines/engines/search_engine_pubmed.py +358 -266
- local_deep_research/web_search_engines/engines/search_engine_searxng.py +211 -159
- local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +213 -170
- local_deep_research/web_search_engines/engines/search_engine_serpapi.py +84 -68
- local_deep_research/web_search_engines/engines/search_engine_wayback.py +186 -154
- local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +115 -77
- local_deep_research/web_search_engines/search_engine_base.py +174 -99
- local_deep_research/web_search_engines/search_engine_factory.py +192 -102
- local_deep_research/web_search_engines/search_engines_config.py +22 -15
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/METADATA +177 -97
- local_deep_research-0.2.0.dist-info/RECORD +135 -0
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/WHEEL +1 -2
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/entry_points.txt +3 -0
- local_deep_research/defaults/llm_config.py +0 -338
- local_deep_research/utilties/search_utilities.py +0 -114
- local_deep_research/web/static/js/app.js +0 -3763
- local_deep_research/web/templates/api_keys_config.html +0 -82
- local_deep_research/web/templates/collections_config.html +0 -90
- local_deep_research/web/templates/index.html +0 -348
- local_deep_research/web/templates/llm_config.html +0 -120
- local_deep_research/web/templates/main_config.html +0 -89
- local_deep_research/web/templates/search_engines_config.html +0 -154
- local_deep_research/web/templates/settings.html +0 -519
- local_deep_research-0.1.26.dist-info/RECORD +0 -61
- local_deep_research-0.1.26.dist-info/top_level.txt +0 -1
- /local_deep_research/{utilties → config}/__init__.py +0 -0
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
"""
|
3
|
+
Data directory setup script for Local Deep Research.
|
4
|
+
Creates the data directory for the application database if it doesn't exist.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
|
9
|
+
|
10
|
+
def setup_data_dir():
|
11
|
+
"""Set up the data directory for the application."""
|
12
|
+
# Get the project root directory (3 levels up from this file)
|
13
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
14
|
+
project_root = os.path.abspath(os.path.join(current_dir, "..", ".."))
|
15
|
+
|
16
|
+
# Define the data directory path
|
17
|
+
data_dir = os.path.join(project_root, "data")
|
18
|
+
|
19
|
+
# Create the data directory if it doesn't exist
|
20
|
+
if not os.path.exists(data_dir):
|
21
|
+
os.makedirs(data_dir)
|
22
|
+
print(f"Created data directory at: {data_dir}")
|
23
|
+
else:
|
24
|
+
print(f"Data directory already exists at: {data_dir}")
|
25
|
+
|
26
|
+
# Return the path to the data directory
|
27
|
+
return data_dir
|
28
|
+
|
29
|
+
|
30
|
+
if __name__ == "__main__":
|
31
|
+
data_dir = setup_data_dir()
|
32
|
+
db_path = os.path.join(data_dir, "ldr.db")
|
33
|
+
print(f"Database path: {db_path}")
|
34
|
+
print("Run the following command to migrate your database:")
|
35
|
+
print("python -m src.local_deep_research.migrate_db --backup")
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
"""
|
3
|
+
Migration test script for Local Deep Research.
|
4
|
+
This script checks the contents of both the legacy and new databases to diagnose migration issues.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import sqlite3
|
9
|
+
import sys
|
10
|
+
import time
|
11
|
+
|
12
|
+
|
13
|
+
def check_db_content(db_path, description):
|
14
|
+
"""Check what tables and how many rows are in a database."""
|
15
|
+
if not os.path.exists(db_path):
|
16
|
+
print(f"❌ {description} database not found at: {db_path}")
|
17
|
+
return False
|
18
|
+
|
19
|
+
print(f"📊 Examining {description} database at: {db_path}")
|
20
|
+
try:
|
21
|
+
conn = sqlite3.connect(db_path)
|
22
|
+
cursor = conn.cursor()
|
23
|
+
|
24
|
+
# Get list of tables
|
25
|
+
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
26
|
+
tables = [
|
27
|
+
row[0] for row in cursor.fetchall() if not row[0].startswith("sqlite_")
|
28
|
+
]
|
29
|
+
|
30
|
+
if not tables:
|
31
|
+
print(" ℹ️ No user tables found in database")
|
32
|
+
conn.close()
|
33
|
+
return False
|
34
|
+
|
35
|
+
print(f" 📋 Tables found: {', '.join(tables)}")
|
36
|
+
|
37
|
+
# For each table, count rows
|
38
|
+
for table in tables:
|
39
|
+
cursor.execute(f"SELECT COUNT(*) FROM {table}")
|
40
|
+
count = cursor.fetchone()[0]
|
41
|
+
print(f" 📝 Table '{table}' has {count} rows")
|
42
|
+
|
43
|
+
# If table has rows, show sample
|
44
|
+
if count > 0:
|
45
|
+
cursor.execute(f"SELECT * FROM {table} LIMIT 1")
|
46
|
+
columns = [description[0] for description in cursor.description]
|
47
|
+
print(f" Columns: {', '.join(columns)}")
|
48
|
+
|
49
|
+
# For specific tables, get key columns
|
50
|
+
if table in [
|
51
|
+
"research_history",
|
52
|
+
"research_logs",
|
53
|
+
"research",
|
54
|
+
"settings",
|
55
|
+
]:
|
56
|
+
key_cols = (
|
57
|
+
"id, query, status"
|
58
|
+
if table == "research_history"
|
59
|
+
else "id, key, value" if table == "settings" else "id, message"
|
60
|
+
)
|
61
|
+
cursor.execute(f"SELECT {key_cols} FROM {table} LIMIT 3")
|
62
|
+
sample = cursor.fetchall()
|
63
|
+
for row in sample:
|
64
|
+
print(f" Sample data: {row}")
|
65
|
+
|
66
|
+
conn.close()
|
67
|
+
return True
|
68
|
+
except Exception as e:
|
69
|
+
print(f"❌ Error examining database: {e}")
|
70
|
+
return False
|
71
|
+
|
72
|
+
|
73
|
+
def main():
|
74
|
+
"""Main function to test the migration."""
|
75
|
+
# Import necessary constants
|
76
|
+
try:
|
77
|
+
# Set up paths
|
78
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
79
|
+
project_root = os.path.abspath(os.path.join(current_dir, "..", ".."))
|
80
|
+
|
81
|
+
# Determine paths
|
82
|
+
data_dir = os.path.join(project_root, "data")
|
83
|
+
new_db_path = os.path.join(data_dir, "ldr.db")
|
84
|
+
|
85
|
+
legacy_research_history_db = os.path.join(
|
86
|
+
project_root, "src", "local_deep_research", "research_history.db"
|
87
|
+
)
|
88
|
+
legacy_deep_research_db = os.path.join(data_dir, "deep_research.db")
|
89
|
+
|
90
|
+
# Print paths for verification
|
91
|
+
print("=" * 60)
|
92
|
+
print("DATABASE PATHS")
|
93
|
+
print("=" * 60)
|
94
|
+
print(f"New database path: {new_db_path}")
|
95
|
+
print(f"Legacy research history DB: {legacy_research_history_db}")
|
96
|
+
print(f"Legacy deep research DB: {legacy_deep_research_db}")
|
97
|
+
print("=" * 60)
|
98
|
+
|
99
|
+
# Check all databases
|
100
|
+
check_db_content(legacy_research_history_db, "Legacy research_history")
|
101
|
+
check_db_content(legacy_deep_research_db, "Legacy deep_research")
|
102
|
+
|
103
|
+
# Now check for the new database or create it if needed
|
104
|
+
if os.path.exists(new_db_path):
|
105
|
+
check_db_content(new_db_path, "New ldr")
|
106
|
+
else:
|
107
|
+
print(f"ℹ️ New database doesn't exist yet at: {new_db_path}")
|
108
|
+
print("Would you like to run a test migration? (y/n)")
|
109
|
+
choice = input("> ").lower()
|
110
|
+
if choice == "y":
|
111
|
+
# Run the migration script directly
|
112
|
+
try:
|
113
|
+
from src.local_deep_research.setup_data_dir import setup_data_dir
|
114
|
+
except ImportError:
|
115
|
+
# If that fails, try with the direct import
|
116
|
+
sys.path.append(
|
117
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
118
|
+
)
|
119
|
+
from local_deep_research.setup_data_dir import setup_data_dir
|
120
|
+
|
121
|
+
setup_data_dir()
|
122
|
+
|
123
|
+
# Import migration function
|
124
|
+
try:
|
125
|
+
from src.local_deep_research.web.database.migrate_to_ldr_db import (
|
126
|
+
migrate_to_ldr_db,
|
127
|
+
)
|
128
|
+
except ImportError:
|
129
|
+
# If that fails, try with the direct import
|
130
|
+
from local_deep_research.web.database.migrate_to_ldr_db import (
|
131
|
+
migrate_to_ldr_db,
|
132
|
+
)
|
133
|
+
|
134
|
+
print("Running migration...")
|
135
|
+
success = migrate_to_ldr_db()
|
136
|
+
|
137
|
+
# Wait briefly to ensure file system has time to update
|
138
|
+
time.sleep(1)
|
139
|
+
|
140
|
+
if success:
|
141
|
+
print("\n✅ Migration completed. Checking new database:")
|
142
|
+
check_db_content(new_db_path, "New ldr")
|
143
|
+
else:
|
144
|
+
print("❌ Migration failed")
|
145
|
+
|
146
|
+
# Get the paths from the migration script to verify
|
147
|
+
try:
|
148
|
+
try:
|
149
|
+
from src.local_deep_research.web.models.database import (
|
150
|
+
DB_PATH,
|
151
|
+
LEGACY_DEEP_RESEARCH_DB,
|
152
|
+
LEGACY_RESEARCH_HISTORY_DB,
|
153
|
+
)
|
154
|
+
except ImportError:
|
155
|
+
from local_deep_research.web.models.database import (
|
156
|
+
DB_PATH,
|
157
|
+
LEGACY_DEEP_RESEARCH_DB,
|
158
|
+
LEGACY_RESEARCH_HISTORY_DB,
|
159
|
+
)
|
160
|
+
|
161
|
+
print("\n" + "=" * 60)
|
162
|
+
print("PATHS FROM DATABASE MODULE")
|
163
|
+
print("=" * 60)
|
164
|
+
print(f"DB_PATH: {DB_PATH}")
|
165
|
+
print(f"LEGACY_RESEARCH_HISTORY_DB: {LEGACY_RESEARCH_HISTORY_DB}")
|
166
|
+
print(f"LEGACY_DEEP_RESEARCH_DB: {LEGACY_DEEP_RESEARCH_DB}")
|
167
|
+
except ImportError as e:
|
168
|
+
print(f"Could not import paths from database module: {e}")
|
169
|
+
|
170
|
+
except Exception as e:
|
171
|
+
print(f"Error in test script: {e}")
|
172
|
+
return 1
|
173
|
+
|
174
|
+
return 0
|
175
|
+
|
176
|
+
|
177
|
+
if __name__ == "__main__":
|
178
|
+
sys.exit(main())
|
File without changes
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
from functools import cache
|
4
|
+
|
5
|
+
from sqlalchemy import create_engine
|
6
|
+
from sqlalchemy.orm import Session, sessionmaker
|
7
|
+
|
8
|
+
from ..web.services.settings_manager import SettingsManager
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
# Database path.
|
14
|
+
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "data"))
|
15
|
+
DB_PATH = os.path.join(DATA_DIR, "ldr.db")
|
16
|
+
|
17
|
+
|
18
|
+
@cache
|
19
|
+
def get_db_session() -> Session:
|
20
|
+
"""
|
21
|
+
Returns:
|
22
|
+
The singleton DB session.
|
23
|
+
"""
|
24
|
+
engine = create_engine(f"sqlite:///{DB_PATH}")
|
25
|
+
session_class = sessionmaker(bind=engine)
|
26
|
+
return session_class()
|
27
|
+
|
28
|
+
|
29
|
+
@cache
|
30
|
+
def get_settings_manager() -> SettingsManager:
|
31
|
+
"""
|
32
|
+
Returns:
|
33
|
+
The singleton settings manager.
|
34
|
+
|
35
|
+
"""
|
36
|
+
return SettingsManager(db_session=get_db_session())
|
37
|
+
|
38
|
+
|
39
|
+
def get_db_setting(key, default_value=None):
|
40
|
+
"""Get a setting from the database with fallback to default value"""
|
41
|
+
try:
|
42
|
+
# Get settings manager which handles database access
|
43
|
+
value = get_settings_manager().get_setting(key)
|
44
|
+
|
45
|
+
if value is not None:
|
46
|
+
return value
|
47
|
+
except Exception as e:
|
48
|
+
logger.error(f"Error getting setting {key} from database: {e}")
|
49
|
+
return default_value
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# utilities/llm_utils.py
|
2
2
|
"""
|
3
3
|
LLM utilities for Local Deep Research.
|
4
4
|
|
@@ -6,64 +6,75 @@ This module provides utility functions for working with language models
|
|
6
6
|
when the user's llm_config.py is missing or incomplete.
|
7
7
|
"""
|
8
8
|
|
9
|
-
import os
|
10
9
|
import logging
|
11
|
-
|
10
|
+
import os
|
11
|
+
from typing import Any, Optional
|
12
12
|
|
13
13
|
# Setup logging
|
14
14
|
logger = logging.getLogger(__name__)
|
15
15
|
|
16
|
+
|
16
17
|
def get_model(
|
17
18
|
model_name: Optional[str] = None,
|
18
19
|
model_type: Optional[str] = None,
|
19
20
|
temperature: Optional[float] = None,
|
20
|
-
**kwargs
|
21
|
+
**kwargs,
|
21
22
|
) -> Any:
|
22
23
|
"""
|
23
24
|
Get a language model instance as fallback when llm_config.get_llm is not available.
|
24
|
-
|
25
|
+
|
25
26
|
Args:
|
26
27
|
model_name: Name of the model to use
|
27
28
|
model_type: Type of the model provider
|
28
29
|
temperature: Model temperature
|
29
30
|
**kwargs: Additional parameters
|
30
|
-
|
31
|
+
|
31
32
|
Returns:
|
32
33
|
LangChain language model instance
|
33
34
|
"""
|
34
35
|
# Get default values from kwargs or use reasonable defaults
|
35
|
-
model_name = model_name or kwargs.get(
|
36
|
-
model_type = model_type or kwargs.get(
|
37
|
-
temperature = temperature or kwargs.get(
|
38
|
-
max_tokens = kwargs.get(
|
39
|
-
|
36
|
+
model_name = model_name or kwargs.get("DEFAULT_MODEL", "mistral")
|
37
|
+
model_type = model_type or kwargs.get("DEFAULT_MODEL_TYPE", "ollama")
|
38
|
+
temperature = temperature or kwargs.get("DEFAULT_TEMPERATURE", 0.7)
|
39
|
+
max_tokens = kwargs.get("max_tokens", kwargs.get("MAX_TOKENS", 30000))
|
40
|
+
|
40
41
|
# Common parameters
|
41
42
|
common_params = {
|
42
43
|
"temperature": temperature,
|
43
44
|
"max_tokens": max_tokens,
|
44
45
|
}
|
45
|
-
|
46
|
+
|
46
47
|
# Add additional kwargs
|
47
48
|
for key, value in kwargs.items():
|
48
|
-
if key not in [
|
49
|
+
if key not in [
|
50
|
+
"DEFAULT_MODEL",
|
51
|
+
"DEFAULT_MODEL_TYPE",
|
52
|
+
"DEFAULT_TEMPERATURE",
|
53
|
+
"MAX_TOKENS",
|
54
|
+
]:
|
49
55
|
common_params[key] = value
|
50
|
-
|
56
|
+
|
51
57
|
# Try to load the model based on type
|
52
58
|
if model_type == "ollama":
|
53
59
|
try:
|
54
60
|
from langchain_ollama import ChatOllama
|
61
|
+
|
55
62
|
return ChatOllama(model=model_name, **common_params)
|
56
63
|
except ImportError:
|
57
64
|
try:
|
58
65
|
from langchain_community.llms import Ollama
|
66
|
+
|
59
67
|
return Ollama(model=model_name, **common_params)
|
60
68
|
except ImportError:
|
61
|
-
logger.error(
|
69
|
+
logger.error(
|
70
|
+
"Neither langchain_ollama nor langchain_community.llms.Ollama available"
|
71
|
+
)
|
62
72
|
raise
|
63
|
-
|
73
|
+
|
64
74
|
elif model_type == "openai":
|
65
75
|
try:
|
66
76
|
from langchain_openai import ChatOpenAI
|
77
|
+
|
67
78
|
api_key = os.getenv("OPENAI_API_KEY")
|
68
79
|
if not api_key:
|
69
80
|
raise ValueError("OPENAI_API_KEY environment variable not set")
|
@@ -71,46 +82,69 @@ def get_model(
|
|
71
82
|
except ImportError:
|
72
83
|
logger.error("langchain_openai not available")
|
73
84
|
raise
|
74
|
-
|
85
|
+
|
75
86
|
elif model_type == "anthropic":
|
76
87
|
try:
|
77
88
|
from langchain_anthropic import ChatAnthropic
|
89
|
+
|
78
90
|
api_key = os.getenv("ANTHROPIC_API_KEY")
|
79
91
|
if not api_key:
|
80
92
|
raise ValueError("ANTHROPIC_API_KEY environment variable not set")
|
81
|
-
return ChatAnthropic(
|
93
|
+
return ChatAnthropic(
|
94
|
+
model=model_name, anthropic_api_key=api_key, **common_params
|
95
|
+
)
|
82
96
|
except ImportError:
|
83
97
|
logger.error("langchain_anthropic not available")
|
84
98
|
raise
|
85
|
-
|
99
|
+
|
86
100
|
elif model_type == "openai_endpoint":
|
87
101
|
try:
|
88
102
|
from langchain_openai import ChatOpenAI
|
103
|
+
|
89
104
|
api_key = os.getenv("OPENAI_ENDPOINT_API_KEY")
|
90
105
|
if not api_key:
|
91
106
|
raise ValueError("OPENAI_ENDPOINT_API_KEY environment variable not set")
|
92
|
-
|
93
|
-
endpoint_url = kwargs.get(
|
94
|
-
|
95
|
-
|
96
|
-
|
107
|
+
|
108
|
+
endpoint_url = kwargs.get(
|
109
|
+
"OPENAI_ENDPOINT_URL", "https://openrouter.ai/api/v1"
|
110
|
+
)
|
111
|
+
|
112
|
+
if model_name is None and not kwargs.get(
|
113
|
+
"OPENAI_ENDPOINT_REQUIRES_MODEL", True
|
114
|
+
):
|
115
|
+
return ChatOpenAI(
|
116
|
+
api_key=api_key, openai_api_base=endpoint_url, **common_params
|
117
|
+
)
|
97
118
|
else:
|
98
|
-
return ChatOpenAI(
|
119
|
+
return ChatOpenAI(
|
120
|
+
model=model_name,
|
121
|
+
api_key=api_key,
|
122
|
+
openai_api_base=endpoint_url,
|
123
|
+
**common_params,
|
124
|
+
)
|
99
125
|
except ImportError:
|
100
126
|
logger.error("langchain_openai not available")
|
101
127
|
raise
|
102
|
-
|
128
|
+
|
103
129
|
# Default fallback
|
104
130
|
try:
|
105
131
|
from langchain_ollama import ChatOllama
|
132
|
+
|
106
133
|
logger.warning(f"Unknown model type '{model_type}', defaulting to Ollama")
|
107
134
|
return ChatOllama(model=model_name, **common_params)
|
108
135
|
except (ImportError, Exception) as e:
|
109
136
|
logger.error(f"Failed to load any model: {e}")
|
110
|
-
|
137
|
+
|
111
138
|
# Last resort: create a dummy model
|
112
139
|
try:
|
113
140
|
from langchain_community.llms.fake import FakeListLLM
|
114
|
-
|
141
|
+
|
142
|
+
return FakeListLLM(
|
143
|
+
responses=[
|
144
|
+
"No language models are available. Please install Ollama or set up API keys."
|
145
|
+
]
|
146
|
+
)
|
115
147
|
except ImportError:
|
116
|
-
raise ValueError(
|
148
|
+
raise ValueError(
|
149
|
+
"No language models available and could not create dummy model"
|
150
|
+
)
|