local-deep-research 0.5.9__py3-none-any.whl → 0.6.1__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 (90) hide show
  1. local_deep_research/__version__.py +1 -1
  2. local_deep_research/advanced_search_system/candidate_exploration/progressive_explorer.py +11 -1
  3. local_deep_research/advanced_search_system/questions/browsecomp_question.py +32 -6
  4. local_deep_research/advanced_search_system/strategies/focused_iteration_strategy.py +32 -8
  5. local_deep_research/advanced_search_system/strategies/source_based_strategy.py +2 -0
  6. local_deep_research/api/__init__.py +2 -0
  7. local_deep_research/api/research_functions.py +177 -3
  8. local_deep_research/benchmarks/graders.py +150 -5
  9. local_deep_research/benchmarks/models/__init__.py +19 -0
  10. local_deep_research/benchmarks/models/benchmark_models.py +283 -0
  11. local_deep_research/benchmarks/ui/__init__.py +1 -0
  12. local_deep_research/benchmarks/web_api/__init__.py +6 -0
  13. local_deep_research/benchmarks/web_api/benchmark_routes.py +862 -0
  14. local_deep_research/benchmarks/web_api/benchmark_service.py +920 -0
  15. local_deep_research/config/llm_config.py +106 -21
  16. local_deep_research/defaults/default_settings.json +447 -2
  17. local_deep_research/error_handling/report_generator.py +10 -0
  18. local_deep_research/llm/__init__.py +19 -0
  19. local_deep_research/llm/llm_registry.py +155 -0
  20. local_deep_research/metrics/db_models.py +3 -7
  21. local_deep_research/metrics/search_tracker.py +25 -11
  22. local_deep_research/search_system.py +12 -9
  23. local_deep_research/utilities/log_utils.py +23 -10
  24. local_deep_research/utilities/thread_context.py +99 -0
  25. local_deep_research/web/app_factory.py +32 -8
  26. local_deep_research/web/database/benchmark_schema.py +230 -0
  27. local_deep_research/web/database/convert_research_id_to_string.py +161 -0
  28. local_deep_research/web/database/models.py +55 -1
  29. local_deep_research/web/database/schema_upgrade.py +397 -2
  30. local_deep_research/web/database/uuid_migration.py +265 -0
  31. local_deep_research/web/routes/api_routes.py +62 -31
  32. local_deep_research/web/routes/history_routes.py +13 -6
  33. local_deep_research/web/routes/metrics_routes.py +264 -4
  34. local_deep_research/web/routes/research_routes.py +45 -18
  35. local_deep_research/web/routes/route_registry.py +352 -0
  36. local_deep_research/web/routes/settings_routes.py +382 -22
  37. local_deep_research/web/services/research_service.py +22 -29
  38. local_deep_research/web/services/settings_manager.py +53 -0
  39. local_deep_research/web/services/settings_service.py +2 -0
  40. local_deep_research/web/static/css/styles.css +8 -0
  41. local_deep_research/web/static/js/components/detail.js +7 -14
  42. local_deep_research/web/static/js/components/details.js +8 -10
  43. local_deep_research/web/static/js/components/fallback/ui.js +4 -4
  44. local_deep_research/web/static/js/components/history.js +6 -6
  45. local_deep_research/web/static/js/components/logpanel.js +14 -11
  46. local_deep_research/web/static/js/components/progress.js +51 -46
  47. local_deep_research/web/static/js/components/research.js +250 -89
  48. local_deep_research/web/static/js/components/results.js +5 -7
  49. local_deep_research/web/static/js/components/settings.js +32 -26
  50. local_deep_research/web/static/js/components/settings_sync.js +24 -23
  51. local_deep_research/web/static/js/config/urls.js +285 -0
  52. local_deep_research/web/static/js/main.js +8 -8
  53. local_deep_research/web/static/js/research_form.js +267 -12
  54. local_deep_research/web/static/js/services/api.js +18 -18
  55. local_deep_research/web/static/js/services/keyboard.js +8 -8
  56. local_deep_research/web/static/js/services/socket.js +53 -35
  57. local_deep_research/web/static/js/services/ui.js +1 -1
  58. local_deep_research/web/templates/base.html +4 -1
  59. local_deep_research/web/templates/components/custom_dropdown.html +5 -3
  60. local_deep_research/web/templates/components/mobile_nav.html +3 -3
  61. local_deep_research/web/templates/components/sidebar.html +9 -3
  62. local_deep_research/web/templates/pages/benchmark.html +2697 -0
  63. local_deep_research/web/templates/pages/benchmark_results.html +1274 -0
  64. local_deep_research/web/templates/pages/benchmark_simple.html +453 -0
  65. local_deep_research/web/templates/pages/cost_analytics.html +1 -1
  66. local_deep_research/web/templates/pages/metrics.html +212 -39
  67. local_deep_research/web/templates/pages/research.html +8 -6
  68. local_deep_research/web/templates/pages/star_reviews.html +1 -1
  69. local_deep_research/web_search_engines/engines/search_engine_arxiv.py +14 -1
  70. local_deep_research/web_search_engines/engines/search_engine_brave.py +15 -1
  71. local_deep_research/web_search_engines/engines/search_engine_ddg.py +20 -1
  72. local_deep_research/web_search_engines/engines/search_engine_google_pse.py +26 -2
  73. local_deep_research/web_search_engines/engines/search_engine_pubmed.py +15 -1
  74. local_deep_research/web_search_engines/engines/search_engine_retriever.py +192 -0
  75. local_deep_research/web_search_engines/engines/search_engine_tavily.py +307 -0
  76. local_deep_research/web_search_engines/rate_limiting/__init__.py +14 -0
  77. local_deep_research/web_search_engines/rate_limiting/__main__.py +9 -0
  78. local_deep_research/web_search_engines/rate_limiting/cli.py +209 -0
  79. local_deep_research/web_search_engines/rate_limiting/exceptions.py +21 -0
  80. local_deep_research/web_search_engines/rate_limiting/tracker.py +506 -0
  81. local_deep_research/web_search_engines/retriever_registry.py +108 -0
  82. local_deep_research/web_search_engines/search_engine_base.py +161 -43
  83. local_deep_research/web_search_engines/search_engine_factory.py +14 -0
  84. local_deep_research/web_search_engines/search_engines_config.py +20 -0
  85. local_deep_research-0.6.1.dist-info/METADATA +374 -0
  86. {local_deep_research-0.5.9.dist-info → local_deep_research-0.6.1.dist-info}/RECORD +89 -64
  87. local_deep_research-0.5.9.dist-info/METADATA +0 -420
  88. {local_deep_research-0.5.9.dist-info → local_deep_research-0.6.1.dist-info}/WHEEL +0 -0
  89. {local_deep_research-0.5.9.dist-info → local_deep_research-0.6.1.dist-info}/entry_points.txt +0 -0
  90. {local_deep_research-0.5.9.dist-info → local_deep_research-0.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -32,7 +32,7 @@ window.socket = (function() {
32
32
  try {
33
33
  // Use polling only to avoid WebSocket issues
34
34
  socket = io(baseUrl, {
35
- path: '/research/socket.io',
35
+ path: '/socket.io',
36
36
  reconnection: true,
37
37
  reconnectionDelay: 1000,
38
38
  reconnectionAttempts: 5,
@@ -249,16 +249,8 @@ window.socket = (function() {
249
249
  }
250
250
 
251
251
  // Continue with normal progress update handling
252
- // Call all registered event handlers for this research
253
- if (researchEventHandlers[researchId]) {
254
- researchEventHandlers[researchId].forEach(handler => {
255
- try {
256
- handler(data);
257
- } catch (error) {
258
- console.error('Error in progress update handler:', error);
259
- }
260
- });
261
- }
252
+ // NOTE: We defer calling handlers until after we've processed log_entry data
253
+ // so that handlers can see the complete data including any log entries
262
254
 
263
255
  // Handle special engine selection events
264
256
  if (data.event === 'search_engine_selected' || (data.engine && data.result_count !== undefined)) {
@@ -319,8 +311,9 @@ window.socket = (function() {
319
311
  logItem.metadata.phase === 'complete' ||
320
312
  logItem.metadata.phase === 'search_complete' ||
321
313
  logItem.metadata.is_milestone === true ||
322
- logItem.metadata.type === 'milestone') {
323
- logType = 'milestone';
314
+ logItem.metadata.type === 'milestone' ||
315
+ logItem.metadata.type === 'MILESTONE') {
316
+ logType = 'MILESTONE';
324
317
  } else if (logItem.metadata.phase === 'error' ||
325
318
  logItem.metadata.type === 'error') {
326
319
  logType = 'error';
@@ -375,6 +368,11 @@ window.socket = (function() {
375
368
  if (data.log_entry) {
376
369
  console.log('Adding log entry from socket event:', data.log_entry);
377
370
 
371
+ // Debug: Check if this is a milestone
372
+ if (data.log_entry.type === 'milestone' || data.log_entry.type === 'MILESTONE') {
373
+ console.log('MILESTONE LOG received:', data.log_entry.message);
374
+ }
375
+
378
376
  // Make sure global tracking is initialized
379
377
  window._processedSocketMessages = window._processedSocketMessages || new Map();
380
378
 
@@ -384,24 +382,25 @@ window.socket = (function() {
384
382
  // Skip if we've seen this message before
385
383
  if (window._processedSocketMessages.has(messageKey)) {
386
384
  console.log('Skipping duplicate individual log entry:', data.log_entry.message);
387
- return;
388
- }
389
-
390
- // Record that we've processed this message
391
- window._processedSocketMessages.set(messageKey, Date.now());
392
-
393
- if (typeof window.addConsoleLog === 'function') {
394
- window.addConsoleLog(
395
- data.log_entry.message,
396
- data.log_entry.type ||
397
- (data.log_entry.metadata && data.log_entry.metadata.type) ||
398
- 'info',
399
- data.log_entry.metadata
400
- );
401
- } else if (typeof window._socketAddLogEntry === 'function') {
402
- window._socketAddLogEntry(data.log_entry);
385
+ // Don't return here - we still need to call handlers in case this is a milestone
386
+ // that should update the current task
403
387
  } else {
404
- console.warn('No log handler function available for direct log entry');
388
+ // Record that we've processed this message
389
+ window._processedSocketMessages.set(messageKey, Date.now());
390
+
391
+ if (typeof window.addConsoleLog === 'function') {
392
+ window.addConsoleLog(
393
+ data.log_entry.message,
394
+ data.log_entry.type ||
395
+ (data.log_entry.metadata && data.log_entry.metadata.type) ||
396
+ 'info',
397
+ data.log_entry.metadata
398
+ );
399
+ } else if (typeof window._socketAddLogEntry === 'function') {
400
+ window._socketAddLogEntry(data.log_entry);
401
+ } else {
402
+ console.warn('No log handler function available for direct log entry');
403
+ }
405
404
  }
406
405
  } else if (data.message && typeof window.addConsoleLog === 'function') {
407
406
  // Use the message field if no specific log entry
@@ -411,13 +410,32 @@ window.socket = (function() {
411
410
  const messageKey = `${new Date().toISOString()}-${data.message}`;
412
411
  if (window._processedSocketMessages.has(messageKey)) {
413
412
  console.log('Skipping duplicate message:', data.message);
414
- return;
415
- }
413
+ // Don't return - still call handlers
414
+ } else {
415
+ // Record this message
416
+ window._processedSocketMessages.set(messageKey, Date.now());
416
417
 
417
- // Record this message
418
- window._processedSocketMessages.set(messageKey, Date.now());
418
+ window.addConsoleLog(data.message, determineLogLevel(data.status));
419
+ }
420
+ }
419
421
 
420
- window.addConsoleLog(data.message, determineLogLevel(data.status));
422
+ // Call all registered event handlers for this research AFTER processing all data
423
+ // This ensures handlers see the complete data including any log entries
424
+ if (researchEventHandlers[researchId]) {
425
+ console.log(`Calling ${researchEventHandlers[researchId].length} handlers for research ${researchId} with data:`, {
426
+ hasLogEntry: !!data.log_entry,
427
+ logType: data.log_entry?.type,
428
+ message: data.log_entry?.message?.substring(0, 50) + '...'
429
+ });
430
+ researchEventHandlers[researchId].forEach(handler => {
431
+ try {
432
+ handler(data);
433
+ } catch (error) {
434
+ console.error('Error in progress update handler:', error);
435
+ }
436
+ });
437
+ } else {
438
+ console.log(`No handlers registered for research ${researchId}`);
421
439
  }
422
440
  }
423
441
 
@@ -215,7 +215,7 @@ function processSpecialMarkdown(html) {
215
215
  // Check if this is a reference to a generated image
216
216
  if (ref.startsWith('image-')) {
217
217
  return `<div class="generated-image" data-image-id="${ref}">
218
- <img src="/research/static/img/generated/${ref}.png"
218
+ <img src="/static/img/generated/${ref}.png"
219
219
  alt="Generated image ${ref}"
220
220
  class="img-fluid"
221
221
  loading="lazy" />
@@ -36,6 +36,9 @@
36
36
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
37
37
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js" integrity="sha512-BNaRQnYJYiPSqHHDb58B0yaPfCu+Wgds8Gp/gU33kqBtgNS4tSPHuGibyoeqMV/TJlSKda6FXzoEyYGjTe+vXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
38
38
 
39
+ <!-- URL Configuration (must load first) -->
40
+ <script src="{{ url_for('research.serve_static', path='js/config/urls.js') }}"></script>
41
+
39
42
  <!-- Core JS -->
40
43
  <script src="{{ url_for('research.serve_static', path='js/services/formatting.js') }}"></script>
41
44
  <script src="{{ url_for('research.serve_static', path='js/services/ui.js') }}"></script>
@@ -68,6 +71,6 @@
68
71
  }
69
72
  </script>
70
73
 
71
- <script src="/research/static/js/components/settings_sync.js"></script>
74
+ <script src="{{ url_for('research.serve_static', path='js/components/settings_sync.js') }}"></script>
72
75
  </body>
73
76
  </html>
@@ -1,4 +1,4 @@
1
- {% macro render_dropdown(input_id, dropdown_id, placeholder, label=None, help_text=None, allow_custom=False, show_refresh=False, refresh_aria_label="Refresh options", data_setting_key=None) %}
1
+ {% macro render_dropdown(input_id, dropdown_id, placeholder, label=None, help_text=None, allow_custom=False, show_refresh=False, refresh_aria_label="Refresh options", data_setting_key=None, data_initial_value=None) %}
2
2
  <div class="form-group">
3
3
  {% if label %}
4
4
  <label for="{{ input_id }}">{{ label }}</label>
@@ -10,12 +10,13 @@
10
10
  <input type="text"
11
11
  id="{{ input_id }}"
12
12
  data-key="{{ data_setting_key or input_id }}"
13
+ {% if data_initial_value %}data-initial-value="{{ data_initial_value }}"{% endif %}
13
14
  class="custom-dropdown-input"
14
15
  placeholder="{{ placeholder }}"
15
16
  autocomplete="off"
16
17
  aria-haspopup="listbox">
17
18
  <!-- Hidden input that will be included in form submission -->
18
- <input type="hidden" name="{{ input_id }}" id="{{ input_id }}_hidden" value="">
19
+ <input type="hidden" name="{{ input_id }}" id="{{ input_id }}_hidden" value="{{ data_initial_value or '' }}">
19
20
  <div class="custom-dropdown-list" id="{{ dropdown_id }}-list"></div>
20
21
  </div>
21
22
  <button type="button"
@@ -30,12 +31,13 @@
30
31
  <input type="text"
31
32
  id="{{ input_id }}"
32
33
  data-key="{{ data_setting_key or input_id }}"
34
+ {% if data_initial_value %}data-initial-value="{{ data_initial_value }}"{% endif %}
33
35
  class="custom-dropdown-input"
34
36
  placeholder="{{ placeholder }}"
35
37
  autocomplete="off"
36
38
  aria-haspopup="listbox">
37
39
  <!-- Hidden input that will be included in form submission -->
38
- <input type="hidden" name="{{ input_id }}" id="{{ input_id }}_hidden" value="">
40
+ <input type="hidden" name="{{ input_id }}" id="{{ input_id }}_hidden" value="{{ data_initial_value or '' }}">
39
41
  <div class="custom-dropdown-list" id="{{ dropdown_id }}-list"></div>
40
42
  </div>
41
43
  {% endif %}
@@ -1,19 +1,19 @@
1
1
  <nav class="mobile-tab-bar">
2
2
  <ul>
3
3
  <li {% if active_page == 'new-research' %}class="active"{% endif %} data-page="new-research">
4
- <a href="{{ url_for('research.index') }}">
4
+ <a href="/">
5
5
  <i class="fas fa-search"></i>
6
6
  <span>Research</span>
7
7
  </a>
8
8
  </li>
9
9
  <li {% if active_page == 'history' %}class="active"{% endif %} data-page="history">
10
- <a href="{{ url_for('research.history_page') }}">
10
+ <a href="{{ url_for('history.history_page') }}">
11
11
  <i class="fas fa-history"></i>
12
12
  <span>History</span>
13
13
  </a>
14
14
  </li>
15
15
  <li {% if active_page == 'settings' %}class="active"{% endif %} data-page="settings">
16
- <a href="{{ url_for('research.settings_page') }}">
16
+ <a href="{{ url_for('settings.settings_page') }}">
17
17
  <i class="fas fa-cog"></i>
18
18
  <span>Settings</span>
19
19
  </a>
@@ -5,16 +5,22 @@
5
5
  <nav class="sidebar-nav">
6
6
  <ul>
7
7
  <li {% if active_page == 'new-research' %}class="active"{% endif %} data-page="new-research">
8
- <a href="{{ url_for('research.index') }}"><i class="fas fa-search"></i> New Research</a>
8
+ <a href="/"><i class="fas fa-search"></i> New Research</a>
9
9
  </li>
10
10
  <li {% if active_page == 'history' %}class="active"{% endif %} data-page="history">
11
- <a href="{{ url_for('research.history_page') }}"><i class="fas fa-history"></i> History</a>
11
+ <a href="{{ url_for('history.history_page') }}"><i class="fas fa-history"></i> History</a>
12
+ </li>
13
+ <li {% if active_page == 'benchmark' %}class="active"{% endif %} data-page="benchmark">
14
+ <a href="{{ url_for('benchmark.index') }}"><i class="fas fa-tachometer-alt"></i> Benchmark</a>
15
+ </li>
16
+ <li {% if active_page == 'benchmark-results' %}class="active"{% endif %} data-page="benchmark-results">
17
+ <a href="{{ url_for('benchmark.results') }}"><i class="fas fa-chart-line"></i> Benchmark Results</a>
12
18
  </li>
13
19
  <li {% if active_page == 'metrics' %}class="active"{% endif %} data-page="metrics">
14
20
  <a href="{{ url_for('metrics.metrics_dashboard') }}"><i class="fas fa-chart-bar"></i> Metrics</a>
15
21
  </li>
16
22
  <li {% if active_page == 'settings' %}class="active"{% endif %} data-page="settings">
17
- <a href="{{ url_for('research.settings_page') }}"><i class="fas fa-cog"></i> Settings</a>
23
+ <a href="{{ url_for('settings.settings_page') }}"><i class="fas fa-cog"></i> Settings</a>
18
24
  </li>
19
25
  </ul>
20
26
  </nav>