local-deep-research 0.6.0__py3-none-any.whl → 0.6.4__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 +6 -0
- local_deep_research/__version__.py +1 -1
- local_deep_research/setup_data_dir.py +3 -2
- local_deep_research/utilities/db_utils.py +11 -9
- local_deep_research/utilities/log_utils.py +1 -1
- local_deep_research/utilities/threading_utils.py +17 -4
- local_deep_research/web/api.py +5 -3
- local_deep_research/web/app.py +0 -74
- local_deep_research/web/app_factory.py +1 -11
- local_deep_research/web/database/migrations.py +699 -28
- local_deep_research/web/database/uuid_migration.py +2 -247
- local_deep_research/web/models/database.py +0 -79
- local_deep_research/web/routes/settings_routes.py +70 -73
- local_deep_research/web/services/settings_manager.py +13 -28
- local_deep_research/web/services/settings_service.py +6 -40
- local_deep_research/web/services/socket_service.py +1 -1
- local_deep_research/web/templates/pages/benchmark_results.html +146 -8
- local_deep_research/web_search_engines/rate_limiting/tracker.py +1 -3
- {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/METADATA +20 -5
- {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/RECORD +23 -26
- local_deep_research/migrate_db.py +0 -149
- local_deep_research/web/database/migrate_to_ldr_db.py +0 -297
- local_deep_research/web/database/schema_upgrade.py +0 -519
- {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/WHEEL +0 -0
- {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/entry_points.txt +0 -0
- {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,149 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
"""
|
3
|
-
Database migration script for Local Deep Research.
|
4
|
-
Migrates data from legacy databases (deep_research.db and research_history.db) to the new unified database (ldr.db).
|
5
|
-
"""
|
6
|
-
|
7
|
-
import argparse
|
8
|
-
import logging
|
9
|
-
import os
|
10
|
-
import sys
|
11
|
-
|
12
|
-
try:
|
13
|
-
from local_deep_research.web.database.migrate_to_ldr_db import (
|
14
|
-
migrate_to_ldr_db,
|
15
|
-
)
|
16
|
-
from local_deep_research.web.models.database import (
|
17
|
-
DB_PATH,
|
18
|
-
LEGACY_DEEP_RESEARCH_DB,
|
19
|
-
LEGACY_RESEARCH_HISTORY_DB,
|
20
|
-
)
|
21
|
-
except ImportError:
|
22
|
-
# If that fails, try with the relative path.
|
23
|
-
from .web.database.migrate_to_ldr_db import migrate_to_ldr_db
|
24
|
-
from .web.models.database import (
|
25
|
-
DB_PATH,
|
26
|
-
LEGACY_DEEP_RESEARCH_DB,
|
27
|
-
LEGACY_RESEARCH_HISTORY_DB,
|
28
|
-
)
|
29
|
-
|
30
|
-
# Configure logging
|
31
|
-
logging.basicConfig(
|
32
|
-
level=logging.INFO,
|
33
|
-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
34
|
-
handlers=[logging.StreamHandler()],
|
35
|
-
)
|
36
|
-
logger = logging.getLogger("migrate_db")
|
37
|
-
|
38
|
-
# Add proper paths for import
|
39
|
-
current_dir = os.path.dirname(os.path.abspath(__file__))
|
40
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(current_dir)))
|
41
|
-
|
42
|
-
|
43
|
-
def main():
|
44
|
-
"""Main migration function that parses arguments and runs the migration"""
|
45
|
-
parser = argparse.ArgumentParser(
|
46
|
-
description="Local Deep Research Database Migration"
|
47
|
-
)
|
48
|
-
parser.add_argument(
|
49
|
-
"--backup",
|
50
|
-
action="store_true",
|
51
|
-
help="Create backup of existing databases before migration",
|
52
|
-
)
|
53
|
-
parser.add_argument(
|
54
|
-
"--force",
|
55
|
-
action="store_true",
|
56
|
-
help="Force migration even if target database exists",
|
57
|
-
)
|
58
|
-
parser.add_argument(
|
59
|
-
"--dry-run",
|
60
|
-
action="store_true",
|
61
|
-
help="Only check what would be migrated, don't perform actual migration",
|
62
|
-
)
|
63
|
-
parser.add_argument(
|
64
|
-
"--verbose", action="store_true", help="Enable verbose logging"
|
65
|
-
)
|
66
|
-
|
67
|
-
args = parser.parse_args()
|
68
|
-
|
69
|
-
if args.verbose:
|
70
|
-
logging.getLogger().setLevel(logging.DEBUG)
|
71
|
-
|
72
|
-
print("=" * 80)
|
73
|
-
print("LOCAL DEEP RESEARCH DATABASE MIGRATION")
|
74
|
-
print("=" * 80)
|
75
|
-
|
76
|
-
try:
|
77
|
-
# First try the normal import
|
78
|
-
print(f"Target database will be created at: {DB_PATH}")
|
79
|
-
|
80
|
-
# Check if migration is needed
|
81
|
-
if os.path.exists(DB_PATH) and not args.force:
|
82
|
-
print(f"Target database already exists at: {DB_PATH}")
|
83
|
-
if (
|
84
|
-
input(
|
85
|
-
"Do you want to continue anyway? This may overwrite data. (y/n): "
|
86
|
-
).lower()
|
87
|
-
!= "y"
|
88
|
-
):
|
89
|
-
print("Migration aborted.")
|
90
|
-
return 1
|
91
|
-
|
92
|
-
# Check if source databases exist
|
93
|
-
deep_research_exists = os.path.exists(LEGACY_DEEP_RESEARCH_DB)
|
94
|
-
research_history_exists = os.path.exists(LEGACY_RESEARCH_HISTORY_DB)
|
95
|
-
|
96
|
-
if not deep_research_exists and not research_history_exists:
|
97
|
-
print("No legacy databases found. Nothing to migrate.")
|
98
|
-
return 0
|
99
|
-
|
100
|
-
print("Found legacy databases:")
|
101
|
-
if deep_research_exists:
|
102
|
-
print(f" - {LEGACY_DEEP_RESEARCH_DB}")
|
103
|
-
if research_history_exists:
|
104
|
-
print(f" - {LEGACY_RESEARCH_HISTORY_DB}")
|
105
|
-
|
106
|
-
# Create backups if requested
|
107
|
-
if args.backup:
|
108
|
-
if deep_research_exists:
|
109
|
-
backup_path = f"{LEGACY_DEEP_RESEARCH_DB}.bak"
|
110
|
-
import shutil
|
111
|
-
|
112
|
-
shutil.copy2(LEGACY_DEEP_RESEARCH_DB, backup_path)
|
113
|
-
print(f"Created backup: {backup_path}")
|
114
|
-
|
115
|
-
if research_history_exists:
|
116
|
-
backup_path = f"{LEGACY_RESEARCH_HISTORY_DB}.bak"
|
117
|
-
import shutil
|
118
|
-
|
119
|
-
shutil.copy2(LEGACY_RESEARCH_HISTORY_DB, backup_path)
|
120
|
-
print(f"Created backup: {backup_path}")
|
121
|
-
|
122
|
-
# Run migration or dry run
|
123
|
-
if args.dry_run:
|
124
|
-
print("\nDRY RUN - No changes will be made.")
|
125
|
-
print(f"Would migrate data to: {DB_PATH}")
|
126
|
-
return 0
|
127
|
-
else:
|
128
|
-
print(f"\nStarting migration to: {DB_PATH}")
|
129
|
-
|
130
|
-
success = migrate_to_ldr_db()
|
131
|
-
|
132
|
-
if success:
|
133
|
-
print("\nMigration completed successfully.")
|
134
|
-
print(
|
135
|
-
"You can now start the application with the new unified database."
|
136
|
-
)
|
137
|
-
return 0
|
138
|
-
else:
|
139
|
-
print("\nMigration failed. Check the logs for details.")
|
140
|
-
return 1
|
141
|
-
|
142
|
-
except Exception as e:
|
143
|
-
logger.error(f"Migration error: {e}", exc_info=True)
|
144
|
-
print(f"Error during migration: {e}")
|
145
|
-
return 1
|
146
|
-
|
147
|
-
|
148
|
-
if __name__ == "__main__":
|
149
|
-
sys.exit(main())
|
@@ -1,297 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Migration script to merge deep_research.db and research_history.db into ldr.db
|
3
|
-
"""
|
4
|
-
|
5
|
-
# Standard library imports
|
6
|
-
# import json # Remove unused imports
|
7
|
-
import logging
|
8
|
-
import os
|
9
|
-
import sqlite3
|
10
|
-
import sys
|
11
|
-
import traceback
|
12
|
-
|
13
|
-
# from pathlib import Path # Remove unused imports
|
14
|
-
|
15
|
-
# Set up logging
|
16
|
-
logging.basicConfig(level=logging.INFO)
|
17
|
-
logger = logging.getLogger(__name__)
|
18
|
-
|
19
|
-
# Add the parent directory to sys.path to allow relative imports
|
20
|
-
sys.path.append(
|
21
|
-
os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
22
|
-
)
|
23
|
-
|
24
|
-
# Import the database module after adding to sys path
|
25
|
-
# pylint: disable=wrong-import-position
|
26
|
-
from src.local_deep_research.web.models.database import ( # noqa: E402
|
27
|
-
DB_PATH,
|
28
|
-
LEGACY_DEEP_RESEARCH_DB,
|
29
|
-
LEGACY_RESEARCH_HISTORY_DB,
|
30
|
-
)
|
31
|
-
|
32
|
-
|
33
|
-
def migrate_to_ldr_db():
|
34
|
-
"""
|
35
|
-
Migrates data from deep_research.db and research_history.db to ldr.db
|
36
|
-
"""
|
37
|
-
# Ensure data directory exists
|
38
|
-
try:
|
39
|
-
from src.local_deep_research.setup_data_dir import setup_data_dir
|
40
|
-
|
41
|
-
setup_data_dir()
|
42
|
-
except ImportError:
|
43
|
-
# If we can't import directly, check the path manually
|
44
|
-
logger.info("Creating data directory manually")
|
45
|
-
data_dir = os.path.dirname(DB_PATH)
|
46
|
-
os.makedirs(data_dir, exist_ok=True)
|
47
|
-
|
48
|
-
logger.info(f"Using database path: {DB_PATH}")
|
49
|
-
|
50
|
-
# Check if ldr.db already exists
|
51
|
-
if os.path.exists(DB_PATH):
|
52
|
-
logger.info(f"Target database {DB_PATH} already exists")
|
53
|
-
|
54
|
-
# Ask for confirmation
|
55
|
-
if (
|
56
|
-
input(
|
57
|
-
f"Target database {DB_PATH} already exists. Do you want to continue migration? (y/n): "
|
58
|
-
).lower()
|
59
|
-
!= "y"
|
60
|
-
):
|
61
|
-
logger.info("Migration aborted by user")
|
62
|
-
return False
|
63
|
-
|
64
|
-
# Connect to the target database
|
65
|
-
try:
|
66
|
-
ldr_conn = sqlite3.connect(DB_PATH)
|
67
|
-
ldr_cursor = ldr_conn.cursor()
|
68
|
-
logger.info(f"Connected to target database: {DB_PATH}")
|
69
|
-
except Exception as e:
|
70
|
-
logger.error(f"Failed to connect to target database: {e}")
|
71
|
-
return False
|
72
|
-
|
73
|
-
# Enable foreign keys
|
74
|
-
ldr_cursor.execute("PRAGMA foreign_keys = OFF")
|
75
|
-
|
76
|
-
# Initialize the database schema
|
77
|
-
try:
|
78
|
-
from src.local_deep_research.web.models.database import init_db
|
79
|
-
|
80
|
-
init_db()
|
81
|
-
logger.info("Initialized database schema")
|
82
|
-
except Exception as e:
|
83
|
-
logger.error(f"Failed to initialize database schema: {e}")
|
84
|
-
ldr_conn.close()
|
85
|
-
return False
|
86
|
-
|
87
|
-
# Migrate from research_history.db
|
88
|
-
migrated_research = migrate_research_history_db(
|
89
|
-
ldr_conn, LEGACY_RESEARCH_HISTORY_DB
|
90
|
-
)
|
91
|
-
|
92
|
-
# Migrate from deep_research.db
|
93
|
-
migrated_deep_research = migrate_deep_research_db(
|
94
|
-
ldr_conn, LEGACY_DEEP_RESEARCH_DB
|
95
|
-
)
|
96
|
-
|
97
|
-
# Re-enable foreign keys and commit
|
98
|
-
ldr_cursor.execute("PRAGMA foreign_keys = ON")
|
99
|
-
ldr_conn.commit()
|
100
|
-
ldr_conn.close()
|
101
|
-
|
102
|
-
logger.info(
|
103
|
-
f"Migration completed - Research History: {migrated_research}, Deep Research: {migrated_deep_research}"
|
104
|
-
)
|
105
|
-
return True
|
106
|
-
|
107
|
-
|
108
|
-
def migrate_research_history_db(ldr_conn, legacy_path):
|
109
|
-
"""
|
110
|
-
Migrates data from research_history.db to ldr.db
|
111
|
-
|
112
|
-
Args:
|
113
|
-
ldr_conn: Connection to the target ldr.db
|
114
|
-
legacy_path: Path to legacy research_history.db
|
115
|
-
|
116
|
-
Returns:
|
117
|
-
bool: True if migration was successful, False otherwise
|
118
|
-
"""
|
119
|
-
if not os.path.exists(legacy_path):
|
120
|
-
logger.warning(f"Legacy database not found: {legacy_path}")
|
121
|
-
return False
|
122
|
-
|
123
|
-
try:
|
124
|
-
# Connect to legacy database
|
125
|
-
legacy_conn = sqlite3.connect(legacy_path)
|
126
|
-
legacy_cursor = legacy_conn.cursor()
|
127
|
-
ldr_cursor = ldr_conn.cursor()
|
128
|
-
|
129
|
-
logger.info(f"Connected to legacy database: {legacy_path}")
|
130
|
-
|
131
|
-
# Get tables from legacy database
|
132
|
-
legacy_cursor.execute(
|
133
|
-
"SELECT name FROM sqlite_master WHERE type='table'"
|
134
|
-
)
|
135
|
-
tables = [row[0] for row in legacy_cursor.fetchall()]
|
136
|
-
|
137
|
-
for table in tables:
|
138
|
-
# Skip sqlite internal tables
|
139
|
-
if table.startswith("sqlite_"):
|
140
|
-
continue
|
141
|
-
|
142
|
-
logger.info(f"Migrating table: {table}")
|
143
|
-
|
144
|
-
# Check if table exists in target database
|
145
|
-
ldr_cursor.execute(
|
146
|
-
f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table}'"
|
147
|
-
)
|
148
|
-
if not ldr_cursor.fetchone():
|
149
|
-
# Create the table in the target database
|
150
|
-
legacy_cursor.execute(
|
151
|
-
f"SELECT sql FROM sqlite_master WHERE type='table' AND name='{table}'"
|
152
|
-
)
|
153
|
-
create_sql = legacy_cursor.fetchone()[0]
|
154
|
-
logger.info(f"Creating table {table} with SQL: {create_sql}")
|
155
|
-
ldr_cursor.execute(create_sql)
|
156
|
-
logger.info(f"Created table {table} in target database")
|
157
|
-
|
158
|
-
# Get column names
|
159
|
-
legacy_cursor.execute(f"PRAGMA table_info({table})")
|
160
|
-
columns = [row[1] for row in legacy_cursor.fetchall()]
|
161
|
-
|
162
|
-
# Get all data from legacy table
|
163
|
-
legacy_cursor.execute(f"SELECT * FROM {table}")
|
164
|
-
rows = legacy_cursor.fetchall()
|
165
|
-
|
166
|
-
logger.info(f"Found {len(rows)} rows in {table}")
|
167
|
-
|
168
|
-
if rows:
|
169
|
-
# Create placeholders for the SQL query
|
170
|
-
placeholders = ", ".join(["?" for _ in columns])
|
171
|
-
columns_str = ", ".join(columns)
|
172
|
-
|
173
|
-
# Insert data into target database
|
174
|
-
for row in rows:
|
175
|
-
try:
|
176
|
-
ldr_cursor.execute(
|
177
|
-
f"INSERT OR IGNORE INTO {table} ({columns_str}) VALUES ({placeholders})",
|
178
|
-
row,
|
179
|
-
)
|
180
|
-
except sqlite3.Error as e:
|
181
|
-
logger.error(f"Error inserting into {table}: {e}")
|
182
|
-
logger.error(f"Row data: {row}")
|
183
|
-
continue
|
184
|
-
|
185
|
-
# Verify data was inserted
|
186
|
-
ldr_cursor.execute(f"SELECT COUNT(*) FROM {table}")
|
187
|
-
count = ldr_cursor.fetchone()[0]
|
188
|
-
logger.info(
|
189
|
-
f"Migrated {count} rows to {table} (expected {len(rows)})"
|
190
|
-
)
|
191
|
-
else:
|
192
|
-
logger.info(f"No data to migrate from {table}")
|
193
|
-
|
194
|
-
legacy_conn.close()
|
195
|
-
return True
|
196
|
-
|
197
|
-
except Exception as e:
|
198
|
-
logger.error(f"Failed to migrate from {legacy_path}: {e}")
|
199
|
-
logger.error(f"Exception details: {traceback.format_exc()}")
|
200
|
-
return False
|
201
|
-
|
202
|
-
|
203
|
-
def migrate_deep_research_db(ldr_conn, legacy_path):
|
204
|
-
"""
|
205
|
-
Migrates data from deep_research.db to ldr.db
|
206
|
-
|
207
|
-
Args:
|
208
|
-
ldr_conn: Connection to the target ldr.db
|
209
|
-
legacy_path: Path to legacy deep_research.db
|
210
|
-
|
211
|
-
Returns:
|
212
|
-
bool: True if migration was successful, False otherwise
|
213
|
-
"""
|
214
|
-
if not os.path.exists(legacy_path):
|
215
|
-
logger.warning(f"Legacy database not found: {legacy_path}")
|
216
|
-
return False
|
217
|
-
|
218
|
-
try:
|
219
|
-
# Connect to legacy database
|
220
|
-
legacy_conn = sqlite3.connect(legacy_path)
|
221
|
-
legacy_cursor = legacy_conn.cursor()
|
222
|
-
ldr_cursor = ldr_conn.cursor()
|
223
|
-
|
224
|
-
logger.info(f"Connected to legacy database: {legacy_path}")
|
225
|
-
|
226
|
-
# Get tables from legacy database
|
227
|
-
legacy_cursor.execute(
|
228
|
-
"SELECT name FROM sqlite_master WHERE type='table'"
|
229
|
-
)
|
230
|
-
tables = [row[0] for row in legacy_cursor.fetchall()]
|
231
|
-
|
232
|
-
# Migrate each table
|
233
|
-
for table in tables:
|
234
|
-
# Skip sqlite internal tables
|
235
|
-
if table.startswith("sqlite_"):
|
236
|
-
continue
|
237
|
-
|
238
|
-
# Skip the research_log table as it's redundant with research_logs
|
239
|
-
if table == "research_log":
|
240
|
-
logger.info(
|
241
|
-
"Skipping redundant table 'research_log', using 'research_logs' instead"
|
242
|
-
)
|
243
|
-
continue
|
244
|
-
|
245
|
-
logger.info(f"Migrating table: {table}")
|
246
|
-
|
247
|
-
# Check if table exists in target database
|
248
|
-
ldr_cursor.execute(
|
249
|
-
f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table}'"
|
250
|
-
)
|
251
|
-
if not ldr_cursor.fetchone():
|
252
|
-
# Create the table in the target database
|
253
|
-
legacy_cursor.execute(
|
254
|
-
f"SELECT sql FROM sqlite_master WHERE type='table' AND name='{table}'"
|
255
|
-
)
|
256
|
-
create_sql = legacy_cursor.fetchone()[0]
|
257
|
-
ldr_cursor.execute(create_sql)
|
258
|
-
logger.info(f"Created table {table} in target database")
|
259
|
-
|
260
|
-
# Get column names
|
261
|
-
legacy_cursor.execute(f"PRAGMA table_info({table})")
|
262
|
-
columns = [row[1] for row in legacy_cursor.fetchall()]
|
263
|
-
|
264
|
-
# Get all data from legacy table
|
265
|
-
legacy_cursor.execute(f"SELECT * FROM {table}")
|
266
|
-
rows = legacy_cursor.fetchall()
|
267
|
-
|
268
|
-
if rows:
|
269
|
-
# Create placeholders for the SQL query
|
270
|
-
placeholders = ", ".join(["?" for _ in columns])
|
271
|
-
columns_str = ", ".join(columns)
|
272
|
-
|
273
|
-
# Insert data into target database
|
274
|
-
for row in rows:
|
275
|
-
try:
|
276
|
-
ldr_cursor.execute(
|
277
|
-
f"INSERT OR IGNORE INTO {table} ({columns_str}) VALUES ({placeholders})",
|
278
|
-
row,
|
279
|
-
)
|
280
|
-
except sqlite3.Error as e:
|
281
|
-
logger.error(f"Error inserting into {table}: {e}")
|
282
|
-
continue
|
283
|
-
|
284
|
-
logger.info(f"Migrated {len(rows)} rows from {table}")
|
285
|
-
else:
|
286
|
-
logger.info(f"No data to migrate from {table}")
|
287
|
-
|
288
|
-
legacy_conn.close()
|
289
|
-
return True
|
290
|
-
|
291
|
-
except Exception as e:
|
292
|
-
logger.error(f"Failed to migrate from {legacy_path}: {e}")
|
293
|
-
return False
|
294
|
-
|
295
|
-
|
296
|
-
if __name__ == "__main__":
|
297
|
-
migrate_to_ldr_db()
|