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.
Files changed (26) hide show
  1. local_deep_research/__init__.py +6 -0
  2. local_deep_research/__version__.py +1 -1
  3. local_deep_research/setup_data_dir.py +3 -2
  4. local_deep_research/utilities/db_utils.py +11 -9
  5. local_deep_research/utilities/log_utils.py +1 -1
  6. local_deep_research/utilities/threading_utils.py +17 -4
  7. local_deep_research/web/api.py +5 -3
  8. local_deep_research/web/app.py +0 -74
  9. local_deep_research/web/app_factory.py +1 -11
  10. local_deep_research/web/database/migrations.py +699 -28
  11. local_deep_research/web/database/uuid_migration.py +2 -247
  12. local_deep_research/web/models/database.py +0 -79
  13. local_deep_research/web/routes/settings_routes.py +70 -73
  14. local_deep_research/web/services/settings_manager.py +13 -28
  15. local_deep_research/web/services/settings_service.py +6 -40
  16. local_deep_research/web/services/socket_service.py +1 -1
  17. local_deep_research/web/templates/pages/benchmark_results.html +146 -8
  18. local_deep_research/web_search_engines/rate_limiting/tracker.py +1 -3
  19. {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/METADATA +20 -5
  20. {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/RECORD +23 -26
  21. local_deep_research/migrate_db.py +0 -149
  22. local_deep_research/web/database/migrate_to_ldr_db.py +0 -297
  23. local_deep_research/web/database/schema_upgrade.py +0 -519
  24. {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/WHEEL +0 -0
  25. {local_deep_research-0.6.0.dist-info → local_deep_research-0.6.4.dist-info}/entry_points.txt +0 -0
  26. {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()