local-deep-research 0.5.7__py3-none-any.whl → 0.6.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/__version__.py +1 -1
- local_deep_research/advanced_search_system/candidate_exploration/progressive_explorer.py +11 -1
- local_deep_research/advanced_search_system/questions/browsecomp_question.py +32 -6
- local_deep_research/advanced_search_system/strategies/focused_iteration_strategy.py +33 -8
- local_deep_research/advanced_search_system/strategies/source_based_strategy.py +2 -0
- local_deep_research/api/__init__.py +2 -0
- local_deep_research/api/research_functions.py +177 -3
- local_deep_research/benchmarks/graders.py +150 -5
- local_deep_research/benchmarks/models/__init__.py +19 -0
- local_deep_research/benchmarks/models/benchmark_models.py +283 -0
- local_deep_research/benchmarks/ui/__init__.py +1 -0
- local_deep_research/benchmarks/web_api/__init__.py +6 -0
- local_deep_research/benchmarks/web_api/benchmark_routes.py +862 -0
- local_deep_research/benchmarks/web_api/benchmark_service.py +920 -0
- local_deep_research/config/llm_config.py +106 -21
- local_deep_research/defaults/default_settings.json +448 -3
- local_deep_research/error_handling/report_generator.py +10 -0
- local_deep_research/llm/__init__.py +19 -0
- local_deep_research/llm/llm_registry.py +155 -0
- local_deep_research/metrics/db_models.py +3 -7
- local_deep_research/metrics/search_tracker.py +25 -11
- local_deep_research/report_generator.py +3 -2
- local_deep_research/search_system.py +12 -9
- local_deep_research/utilities/log_utils.py +23 -10
- local_deep_research/utilities/thread_context.py +99 -0
- local_deep_research/web/app_factory.py +32 -8
- local_deep_research/web/database/benchmark_schema.py +230 -0
- local_deep_research/web/database/convert_research_id_to_string.py +161 -0
- local_deep_research/web/database/models.py +55 -1
- local_deep_research/web/database/schema_upgrade.py +397 -2
- local_deep_research/web/database/uuid_migration.py +265 -0
- local_deep_research/web/routes/api_routes.py +62 -31
- local_deep_research/web/routes/history_routes.py +13 -6
- local_deep_research/web/routes/metrics_routes.py +264 -4
- local_deep_research/web/routes/research_routes.py +45 -18
- local_deep_research/web/routes/route_registry.py +352 -0
- local_deep_research/web/routes/settings_routes.py +382 -22
- local_deep_research/web/services/research_service.py +22 -29
- local_deep_research/web/services/settings_manager.py +53 -0
- local_deep_research/web/services/settings_service.py +2 -0
- local_deep_research/web/static/css/styles.css +8 -0
- local_deep_research/web/static/js/components/detail.js +7 -14
- local_deep_research/web/static/js/components/details.js +8 -10
- local_deep_research/web/static/js/components/fallback/ui.js +4 -4
- local_deep_research/web/static/js/components/history.js +6 -6
- local_deep_research/web/static/js/components/logpanel.js +14 -11
- local_deep_research/web/static/js/components/progress.js +51 -46
- local_deep_research/web/static/js/components/research.js +250 -89
- local_deep_research/web/static/js/components/results.js +5 -7
- local_deep_research/web/static/js/components/settings.js +32 -26
- local_deep_research/web/static/js/components/settings_sync.js +24 -23
- local_deep_research/web/static/js/config/urls.js +285 -0
- local_deep_research/web/static/js/main.js +8 -8
- local_deep_research/web/static/js/research_form.js +267 -12
- local_deep_research/web/static/js/services/api.js +18 -18
- local_deep_research/web/static/js/services/keyboard.js +8 -8
- local_deep_research/web/static/js/services/socket.js +53 -35
- local_deep_research/web/static/js/services/ui.js +1 -1
- local_deep_research/web/templates/base.html +4 -1
- local_deep_research/web/templates/components/custom_dropdown.html +5 -3
- local_deep_research/web/templates/components/mobile_nav.html +3 -3
- local_deep_research/web/templates/components/sidebar.html +9 -3
- local_deep_research/web/templates/pages/benchmark.html +2697 -0
- local_deep_research/web/templates/pages/benchmark_results.html +1136 -0
- local_deep_research/web/templates/pages/benchmark_simple.html +453 -0
- local_deep_research/web/templates/pages/cost_analytics.html +1 -1
- local_deep_research/web/templates/pages/metrics.html +212 -39
- local_deep_research/web/templates/pages/research.html +8 -6
- local_deep_research/web/templates/pages/star_reviews.html +1 -1
- local_deep_research/web_search_engines/engines/search_engine_arxiv.py +14 -1
- local_deep_research/web_search_engines/engines/search_engine_brave.py +15 -1
- local_deep_research/web_search_engines/engines/search_engine_ddg.py +20 -1
- local_deep_research/web_search_engines/engines/search_engine_google_pse.py +26 -2
- local_deep_research/web_search_engines/engines/search_engine_pubmed.py +15 -1
- local_deep_research/web_search_engines/engines/search_engine_retriever.py +192 -0
- local_deep_research/web_search_engines/engines/search_engine_tavily.py +307 -0
- local_deep_research/web_search_engines/rate_limiting/__init__.py +14 -0
- local_deep_research/web_search_engines/rate_limiting/__main__.py +9 -0
- local_deep_research/web_search_engines/rate_limiting/cli.py +209 -0
- local_deep_research/web_search_engines/rate_limiting/exceptions.py +21 -0
- local_deep_research/web_search_engines/rate_limiting/tracker.py +506 -0
- local_deep_research/web_search_engines/retriever_registry.py +108 -0
- local_deep_research/web_search_engines/search_engine_base.py +161 -43
- local_deep_research/web_search_engines/search_engine_factory.py +14 -0
- local_deep_research/web_search_engines/search_engines_config.py +20 -0
- local_deep_research-0.6.0.dist-info/METADATA +374 -0
- {local_deep_research-0.5.7.dist-info → local_deep_research-0.6.0.dist-info}/RECORD +90 -65
- local_deep_research-0.5.7.dist-info/METADATA +0 -420
- {local_deep_research-0.5.7.dist-info → local_deep_research-0.6.0.dist-info}/WHEEL +0 -0
- {local_deep_research-0.5.7.dist-info → local_deep_research-0.6.0.dist-info}/entry_points.txt +0 -0
- {local_deep_research-0.5.7.dist-info → local_deep_research-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -139,36 +139,18 @@
|
|
139
139
|
advancedToggle = document.querySelector('.advanced-options-toggle');
|
140
140
|
advancedPanel = document.querySelector('.advanced-options-panel');
|
141
141
|
|
142
|
-
//
|
143
|
-
|
144
|
-
|
145
|
-
const lastSearchEngine = localStorage.getItem('lastUsedSearchEngine');
|
146
|
-
const lastStrategy = localStorage.getItem('lastUsedStrategy') || 'source-based';
|
147
|
-
|
148
|
-
console.log('Local storage values:', { provider: lastProvider, model: lastModel, searchEngine: lastSearchEngine, strategy: lastStrategy });
|
149
|
-
|
150
|
-
// Apply local storage values if available
|
151
|
-
if (lastProvider && modelProviderSelect) {
|
152
|
-
console.log('Setting provider from localStorage:', lastProvider);
|
153
|
-
modelProviderSelect.value = lastProvider;
|
154
|
-
// Show/hide endpoint container as needed
|
155
|
-
if (endpointContainer) {
|
156
|
-
endpointContainer.style.display = lastProvider === 'OPENAI_ENDPOINT' ? 'block' : 'none';
|
157
|
-
}
|
158
|
-
}
|
159
|
-
|
160
|
-
// Apply saved strategy
|
161
|
-
const strategySelect = document.getElementById('strategy');
|
162
|
-
if (strategySelect && lastStrategy) {
|
163
|
-
console.log('Setting strategy from localStorage:', lastStrategy);
|
164
|
-
strategySelect.value = lastStrategy;
|
165
|
-
}
|
142
|
+
// Note: Settings are now loaded from the database via the template
|
143
|
+
// The form values are already set by the server-side rendering
|
144
|
+
// We just need to initialize the UI components
|
166
145
|
|
167
146
|
// Initialize the UI first (immediate operations)
|
168
147
|
setupEventListeners();
|
169
148
|
populateModelProviders();
|
170
149
|
initializeDropdowns();
|
171
150
|
|
151
|
+
// Also set initial values here for immediate feedback
|
152
|
+
setInitialFormValues();
|
153
|
+
|
172
154
|
// Auto-focus the query input
|
173
155
|
if (queryInput) {
|
174
156
|
queryInput.focus();
|
@@ -179,14 +161,17 @@
|
|
179
161
|
}
|
180
162
|
|
181
163
|
// Set initial state of the advanced options panel based on localStorage
|
182
|
-
const savedState = localStorage.getItem('
|
164
|
+
const savedState = localStorage.getItem('advancedMenuOpen') === 'true';
|
183
165
|
if (savedState && advancedPanel) {
|
184
166
|
advancedPanel.style.display = 'block';
|
185
167
|
advancedPanel.classList.add('expanded');
|
186
168
|
if (advancedToggle) {
|
187
169
|
advancedToggle.classList.add('open');
|
170
|
+
advancedToggle.setAttribute('aria-expanded', 'true');
|
188
171
|
const icon = advancedToggle.querySelector('i');
|
189
172
|
if (icon) icon.className = 'fas fa-chevron-up';
|
173
|
+
const srText = advancedToggle.querySelector('.sr-only');
|
174
|
+
if (srText) srText.textContent = 'Click to collapse advanced options';
|
190
175
|
}
|
191
176
|
}
|
192
177
|
|
@@ -195,16 +180,13 @@
|
|
195
180
|
loadModelOptions(false),
|
196
181
|
loadSearchEngineOptions(false)
|
197
182
|
]).then(([modelData, searchEngineData]) => {
|
198
|
-
console.log('Data loaded successfully');
|
199
|
-
|
200
183
|
// After loading model data, update the UI with the loaded data
|
201
|
-
const currentProvider = modelProviderSelect ? modelProviderSelect.value :
|
184
|
+
const currentProvider = modelProviderSelect ? modelProviderSelect.value : 'OLLAMA';
|
202
185
|
updateModelOptionsForProvider(currentProvider, false);
|
203
186
|
|
204
187
|
// Update search engine options
|
205
188
|
if (searchEngineData && Array.isArray(searchEngineData)) {
|
206
189
|
searchEngineOptions = searchEngineData;
|
207
|
-
console.log('Loaded search engines:', searchEngineData.length);
|
208
190
|
|
209
191
|
// Force search engine dropdown to update with new data
|
210
192
|
if (searchEngineDropdownList && window.setupCustomDropdown) {
|
@@ -214,7 +196,6 @@
|
|
214
196
|
searchEngineDropdownList,
|
215
197
|
() => searchEngineOptions.length > 0 ? searchEngineOptions : [{ value: '', label: 'No search engines available' }],
|
216
198
|
(value, item) => {
|
217
|
-
console.log('Search engine selected:', value, item);
|
218
199
|
selectedSearchEngineValue = value;
|
219
200
|
|
220
201
|
// Update the input field
|
@@ -235,13 +216,11 @@
|
|
235
216
|
|
236
217
|
// If we have a last selected search engine, try to select it
|
237
218
|
if (lastSearchEngine) {
|
238
|
-
console.log('Trying to select last search engine:', lastSearchEngine);
|
239
219
|
// Find the matching engine
|
240
220
|
const matchingEngine = searchEngineOptions.find(engine =>
|
241
221
|
engine.value === lastSearchEngine || engine.id === lastSearchEngine);
|
242
222
|
|
243
223
|
if (matchingEngine) {
|
244
|
-
console.log('Found matching search engine:', matchingEngine);
|
245
224
|
searchEngineInput.value = matchingEngine.label;
|
246
225
|
selectedSearchEngineValue = matchingEngine.value;
|
247
226
|
|
@@ -255,11 +234,17 @@
|
|
255
234
|
}
|
256
235
|
}
|
257
236
|
|
237
|
+
// Set initial form values from data attributes
|
238
|
+
setInitialFormValues();
|
239
|
+
|
258
240
|
// Finally, load settings after data is available
|
259
241
|
loadSettings();
|
260
242
|
}).catch(error => {
|
261
243
|
console.error('Failed to load options:', error);
|
262
244
|
|
245
|
+
// Set initial form values even if data loading fails
|
246
|
+
setInitialFormValues();
|
247
|
+
|
263
248
|
// Still load settings even if data loading fails
|
264
249
|
loadSettings();
|
265
250
|
|
@@ -423,6 +408,65 @@
|
|
423
408
|
}
|
424
409
|
}
|
425
410
|
|
411
|
+
/**
|
412
|
+
* Set initial form values from data attributes
|
413
|
+
*/
|
414
|
+
function setInitialFormValues() {
|
415
|
+
console.log('Setting initial form values...');
|
416
|
+
|
417
|
+
// Set initial model value if available
|
418
|
+
if (modelInput) {
|
419
|
+
const initialModel = modelInput.getAttribute('data-initial-value');
|
420
|
+
console.log('Initial model value from data attribute:', initialModel);
|
421
|
+
if (initialModel) {
|
422
|
+
// Find the matching model in the options
|
423
|
+
const matchingModel = modelOptions.find(m =>
|
424
|
+
m.value === initialModel || m.id === initialModel
|
425
|
+
);
|
426
|
+
|
427
|
+
if (matchingModel) {
|
428
|
+
modelInput.value = matchingModel.label;
|
429
|
+
selectedModelValue = matchingModel.value;
|
430
|
+
} else {
|
431
|
+
// If not found in options, set it as custom value
|
432
|
+
modelInput.value = initialModel;
|
433
|
+
selectedModelValue = initialModel;
|
434
|
+
}
|
435
|
+
|
436
|
+
// Update hidden input
|
437
|
+
const hiddenInput = document.getElementById('model_hidden');
|
438
|
+
if (hiddenInput) {
|
439
|
+
hiddenInput.value = selectedModelValue;
|
440
|
+
}
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
// Set initial search engine value if available
|
445
|
+
if (searchEngineInput) {
|
446
|
+
const initialSearchEngine = searchEngineInput.getAttribute('data-initial-value');
|
447
|
+
if (initialSearchEngine) {
|
448
|
+
// Find the matching search engine in the options
|
449
|
+
const matchingEngine = searchEngineOptions.find(e =>
|
450
|
+
e.value === initialSearchEngine || e.id === initialSearchEngine
|
451
|
+
);
|
452
|
+
|
453
|
+
if (matchingEngine) {
|
454
|
+
searchEngineInput.value = matchingEngine.label;
|
455
|
+
selectedSearchEngineValue = matchingEngine.value;
|
456
|
+
} else {
|
457
|
+
searchEngineInput.value = initialSearchEngine;
|
458
|
+
selectedSearchEngineValue = initialSearchEngine;
|
459
|
+
}
|
460
|
+
|
461
|
+
// Update hidden input
|
462
|
+
const hiddenInput = document.getElementById('search_engine_hidden');
|
463
|
+
if (hiddenInput) {
|
464
|
+
hiddenInput.value = selectedSearchEngineValue;
|
465
|
+
}
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
426
470
|
/**
|
427
471
|
* Setup event listeners
|
428
472
|
*/
|
@@ -432,23 +476,19 @@
|
|
432
476
|
// INITIALIZE ADVANCED OPTIONS FIRST - before any async operations
|
433
477
|
// Advanced options toggle - make immediately responsive
|
434
478
|
if (advancedToggle && advancedPanel) {
|
435
|
-
// Set initial state based on localStorage
|
436
|
-
const savedState = localStorage.getItem('
|
479
|
+
// Set initial state based on localStorage
|
480
|
+
const savedState = localStorage.getItem('advancedMenuOpen') === 'true';
|
437
481
|
|
438
482
|
if (savedState) {
|
439
483
|
advancedToggle.classList.add('open');
|
440
484
|
advancedPanel.classList.add('expanded');
|
441
|
-
|
442
|
-
// Update ARIA attributes
|
443
485
|
advancedToggle.setAttribute('aria-expanded', 'true');
|
444
486
|
|
445
|
-
// Update screen reader text
|
446
487
|
const srText = advancedToggle.querySelector('.sr-only');
|
447
488
|
if (srText) {
|
448
489
|
srText.textContent = 'Click to collapse advanced options';
|
449
490
|
}
|
450
491
|
|
451
|
-
// Update icon immediately
|
452
492
|
const icon = advancedToggle.querySelector('i');
|
453
493
|
if (icon) {
|
454
494
|
icon.className = 'fas fa-chevron-up';
|
@@ -456,17 +496,13 @@
|
|
456
496
|
} else {
|
457
497
|
advancedToggle.classList.remove('open');
|
458
498
|
advancedPanel.classList.remove('expanded');
|
459
|
-
|
460
|
-
// Update ARIA attributes
|
461
499
|
advancedToggle.setAttribute('aria-expanded', 'false');
|
462
500
|
|
463
|
-
// Update screen reader text
|
464
501
|
const srText = advancedToggle.querySelector('.sr-only');
|
465
502
|
if (srText) {
|
466
503
|
srText.textContent = 'Click to expand advanced options';
|
467
504
|
}
|
468
505
|
|
469
|
-
// Ensure icon is correct
|
470
506
|
const icon = advancedToggle.querySelector('i');
|
471
507
|
if (icon) {
|
472
508
|
icon.className = 'fas fa-chevron-down';
|
@@ -489,7 +525,7 @@
|
|
489
525
|
}
|
490
526
|
|
491
527
|
// Save state to localStorage
|
492
|
-
localStorage.setItem('
|
528
|
+
localStorage.setItem('advancedMenuOpen', isOpen.toString());
|
493
529
|
|
494
530
|
// Update icon
|
495
531
|
const icon = this.querySelector('i');
|
@@ -622,6 +658,33 @@
|
|
622
658
|
});
|
623
659
|
}
|
624
660
|
|
661
|
+
// Search engine change - save to settings manager
|
662
|
+
if (searchEngineInput) {
|
663
|
+
searchEngineInput.addEventListener('change', function() {
|
664
|
+
const searchEngine = this.value;
|
665
|
+
console.log('Search engine changed to:', searchEngine);
|
666
|
+
saveSearchSetting('search.tool', searchEngine);
|
667
|
+
});
|
668
|
+
}
|
669
|
+
|
670
|
+
// Iterations change - save to settings manager
|
671
|
+
if (iterationsInput) {
|
672
|
+
iterationsInput.addEventListener('change', function() {
|
673
|
+
const iterations = parseInt(this.value);
|
674
|
+
console.log('Iterations changed to:', iterations);
|
675
|
+
saveSearchSetting('search.iterations', iterations);
|
676
|
+
});
|
677
|
+
}
|
678
|
+
|
679
|
+
// Questions per iteration change - save to settings manager
|
680
|
+
if (questionsPerIterationInput) {
|
681
|
+
questionsPerIterationInput.addEventListener('change', function() {
|
682
|
+
const questions = parseInt(this.value);
|
683
|
+
console.log('Questions per iteration changed to:', questions);
|
684
|
+
saveSearchSetting('search.questions_per_iteration', questions);
|
685
|
+
});
|
686
|
+
}
|
687
|
+
|
625
688
|
// Load options data from APIs
|
626
689
|
Promise.all([
|
627
690
|
loadModelOptions(false),
|
@@ -678,11 +741,21 @@
|
|
678
741
|
modelProviderSelect.appendChild(option);
|
679
742
|
});
|
680
743
|
|
681
|
-
//
|
682
|
-
modelProviderSelect.value
|
744
|
+
// Set initial value from data attribute or default to Ollama
|
745
|
+
const initialProvider = modelProviderSelect.getAttribute('data-initial-value') || 'OLLAMA';
|
746
|
+
console.log('Initial provider from data attribute:', initialProvider);
|
747
|
+
modelProviderSelect.value = initialProvider.toUpperCase();
|
748
|
+
|
749
|
+
// Show custom endpoint input if OpenAI endpoint is selected
|
750
|
+
if (endpointContainer) {
|
751
|
+
console.log('Setting endpoint container display for provider:', initialProvider.toUpperCase());
|
752
|
+
endpointContainer.style.display = initialProvider.toUpperCase() === 'OPENAI_ENDPOINT' ? 'block' : 'none';
|
753
|
+
} else {
|
754
|
+
console.warn('Endpoint container not found');
|
755
|
+
}
|
683
756
|
|
684
757
|
// Initial update of model options
|
685
|
-
updateModelOptionsForProvider(
|
758
|
+
updateModelOptionsForProvider(initialProvider.toUpperCase());
|
686
759
|
}
|
687
760
|
|
688
761
|
/**
|
@@ -932,10 +1005,10 @@
|
|
932
1005
|
console.log(`Updated model options for provider ${provider}: ${modelOptions.length} models`);
|
933
1006
|
|
934
1007
|
// Check for stored last model before deciding what to select
|
935
|
-
let lastSelectedModel = localStorage
|
1008
|
+
let lastSelectedModel = null; // Don't use localStorage
|
936
1009
|
|
937
1010
|
// Also check the database setting
|
938
|
-
fetch(
|
1011
|
+
fetch(URLS.SETTINGS_API.LLM_MODEL, {
|
939
1012
|
method: 'GET',
|
940
1013
|
headers: {
|
941
1014
|
'Content-Type': 'application/json'
|
@@ -1063,7 +1136,7 @@
|
|
1063
1136
|
const controller = new AbortController();
|
1064
1137
|
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
|
1065
1138
|
|
1066
|
-
const response = await fetch(
|
1139
|
+
const response = await fetch(URLS.SETTINGS_API.OLLAMA_STATUS, {
|
1067
1140
|
signal: controller.signal
|
1068
1141
|
});
|
1069
1142
|
|
@@ -1144,7 +1217,7 @@
|
|
1144
1217
|
const controller = new AbortController();
|
1145
1218
|
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
1146
1219
|
|
1147
|
-
const response = await fetch(`/
|
1220
|
+
const response = await fetch(`/api/check/ollama_model?model=${encodeURIComponent(model)}`, {
|
1148
1221
|
signal: controller.signal
|
1149
1222
|
});
|
1150
1223
|
|
@@ -1186,8 +1259,11 @@
|
|
1186
1259
|
console.log('Loading settings from database...');
|
1187
1260
|
let numApiCallsPending = 1;
|
1188
1261
|
|
1262
|
+
// Increase the API calls counter to include strategy loading
|
1263
|
+
numApiCallsPending = 3;
|
1264
|
+
|
1189
1265
|
// Fetch the current settings from the settings API
|
1190
|
-
fetch(
|
1266
|
+
fetch(URLS.SETTINGS_API.LLM_CONFIG, {
|
1191
1267
|
method: 'GET',
|
1192
1268
|
headers: {
|
1193
1269
|
'Content-Type': 'application/json'
|
@@ -1223,7 +1299,7 @@
|
|
1223
1299
|
console.log('Found matching provider option:', matchingOption.value);
|
1224
1300
|
modelProviderSelect.value = matchingOption.value;
|
1225
1301
|
// Also save to localStorage
|
1226
|
-
|
1302
|
+
// Provider saved to DB: matchingOption.value);
|
1227
1303
|
} else {
|
1228
1304
|
// If no match, try to find case-insensitive or partial match
|
1229
1305
|
const caseInsensitiveMatch = Array.from(modelProviderSelect.options).find(
|
@@ -1235,7 +1311,7 @@
|
|
1235
1311
|
console.log('Found case-insensitive provider match:', caseInsensitiveMatch.value);
|
1236
1312
|
modelProviderSelect.value = caseInsensitiveMatch.value;
|
1237
1313
|
// Also save to localStorage
|
1238
|
-
|
1314
|
+
// Provider saved to DB: caseInsensitiveMatch.value);
|
1239
1315
|
} else {
|
1240
1316
|
console.warn(`No matching provider option found for '${providerValue}'`);
|
1241
1317
|
}
|
@@ -1266,7 +1342,7 @@
|
|
1266
1342
|
console.log('Setting model to:', modelValue);
|
1267
1343
|
|
1268
1344
|
// Save to localStorage
|
1269
|
-
|
1345
|
+
// Model saved to DB
|
1270
1346
|
|
1271
1347
|
// Find the model in our loaded options
|
1272
1348
|
const matchingModel = modelOptions.find(m =>
|
@@ -1308,7 +1384,7 @@
|
|
1308
1384
|
console.log('Setting search engine to:', engineValue);
|
1309
1385
|
|
1310
1386
|
// Save to localStorage
|
1311
|
-
|
1387
|
+
// Search engine saved to DB
|
1312
1388
|
|
1313
1389
|
// Find the engine in our loaded options
|
1314
1390
|
const matchingEngine = searchEngineOptions.find(e =>
|
@@ -1361,13 +1437,59 @@
|
|
1361
1437
|
numApiCallsPending--;
|
1362
1438
|
isInitializing = (numApiCallsPending === 0);
|
1363
1439
|
});
|
1440
|
+
|
1441
|
+
// Load search strategy setting
|
1442
|
+
fetch(URLS.SETTINGS_API.SEARCH_TOOL, {
|
1443
|
+
method: 'GET',
|
1444
|
+
headers: {
|
1445
|
+
'Content-Type': 'application/json'
|
1446
|
+
}
|
1447
|
+
})
|
1448
|
+
.then(response => {
|
1449
|
+
if (!response.ok) {
|
1450
|
+
throw new Error(`API error: ${response.status}`);
|
1451
|
+
}
|
1452
|
+
return response.json();
|
1453
|
+
})
|
1454
|
+
.then(data => {
|
1455
|
+
console.log('Loaded strategy from database:', data);
|
1456
|
+
|
1457
|
+
const strategySelect = document.getElementById('strategy');
|
1458
|
+
if (data && data.setting && data.setting.value && strategySelect) {
|
1459
|
+
const strategyValue = data.setting.value;
|
1460
|
+
console.log('Setting strategy to:', strategyValue);
|
1461
|
+
|
1462
|
+
// Update the select element
|
1463
|
+
strategySelect.value = strategyValue;
|
1464
|
+
|
1465
|
+
// Save to localStorage
|
1466
|
+
// Strategy saved to DB
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
numApiCallsPending--;
|
1470
|
+
isInitializing = (numApiCallsPending === 0);
|
1471
|
+
})
|
1472
|
+
.catch(error => {
|
1473
|
+
console.error('Error loading strategy:', error);
|
1474
|
+
|
1475
|
+
// Fallback to localStorage
|
1476
|
+
const lastStrategy = null; // Strategy loaded from DB
|
1477
|
+
const strategySelect = document.getElementById('strategy');
|
1478
|
+
if (lastStrategy && strategySelect) {
|
1479
|
+
strategySelect.value = lastStrategy;
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
numApiCallsPending--;
|
1483
|
+
isInitializing = (numApiCallsPending === 0);
|
1484
|
+
});
|
1364
1485
|
}
|
1365
1486
|
|
1366
1487
|
// Add a fallback function to use localStorage settings
|
1367
1488
|
function fallbackToLocalStorageSettings() {
|
1368
|
-
|
1369
|
-
const
|
1370
|
-
const
|
1489
|
+
// Settings are loaded from database, not localStorage
|
1490
|
+
const provider = null;
|
1491
|
+
const model = null;
|
1492
|
+
const searchEngine = null;
|
1371
1493
|
|
1372
1494
|
console.log('Falling back to localStorage settings:', { provider, model, searchEngine });
|
1373
1495
|
|
@@ -1440,7 +1562,11 @@
|
|
1440
1562
|
}
|
1441
1563
|
|
1442
1564
|
// Fetch from API if cache is invalid or refresh is forced
|
1443
|
-
|
1565
|
+
const url = forceRefresh
|
1566
|
+
? `${URLS.SETTINGS_API.AVAILABLE_MODELS}?force_refresh=true`
|
1567
|
+
: URLS.SETTINGS_API.AVAILABLE_MODELS;
|
1568
|
+
|
1569
|
+
fetch(url)
|
1444
1570
|
.then(response => {
|
1445
1571
|
if (!response.ok) {
|
1446
1572
|
throw new Error(`API error: ${response.status}`);
|
@@ -1578,23 +1704,23 @@
|
|
1578
1704
|
];
|
1579
1705
|
}
|
1580
1706
|
|
1581
|
-
//
|
1707
|
+
// In-memory cache to avoid excessive API calls within a session
|
1708
|
+
const memoryCache = {};
|
1709
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
1710
|
+
|
1582
1711
|
function cacheData(key, data) {
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
}
|
1712
|
+
memoryCache[key] = {
|
1713
|
+
data: data,
|
1714
|
+
timestamp: Date.now()
|
1715
|
+
};
|
1588
1716
|
}
|
1589
1717
|
|
1590
1718
|
function getCachedData(key) {
|
1591
|
-
|
1592
|
-
|
1593
|
-
return
|
1594
|
-
} catch (e) {
|
1595
|
-
console.error('Error retrieving cached data:', e);
|
1596
|
-
return null;
|
1719
|
+
const cached = memoryCache[key];
|
1720
|
+
if (cached && (Date.now() - cached.timestamp < CACHE_DURATION)) {
|
1721
|
+
return cached.data;
|
1597
1722
|
}
|
1723
|
+
return null;
|
1598
1724
|
}
|
1599
1725
|
|
1600
1726
|
// Load search engine options
|
@@ -1622,7 +1748,7 @@
|
|
1622
1748
|
console.log('Fetching search engines from API...');
|
1623
1749
|
|
1624
1750
|
// Fetch from API
|
1625
|
-
fetch(
|
1751
|
+
fetch(URLS.SETTINGS_API.AVAILABLE_SEARCH_ENGINES)
|
1626
1752
|
.then(response => {
|
1627
1753
|
if (!response.ok) {
|
1628
1754
|
throw new Error(`API error: ${response.status}`);
|
@@ -1739,8 +1865,7 @@
|
|
1739
1865
|
|
1740
1866
|
// Save model settings to database
|
1741
1867
|
function saveModelSettings(modelValue) {
|
1742
|
-
//
|
1743
|
-
localStorage.setItem('lastUsedModel', modelValue);
|
1868
|
+
// Only save to database, not localStorage
|
1744
1869
|
|
1745
1870
|
// Update any hidden input with the same settings key that might exist in other forms
|
1746
1871
|
const hiddenInputs = document.querySelectorAll('input[id$="_hidden"][name="llm.model"]');
|
@@ -1749,7 +1874,7 @@
|
|
1749
1874
|
});
|
1750
1875
|
|
1751
1876
|
// Save to the database using the settings API
|
1752
|
-
fetch('
|
1877
|
+
fetch(URLBuilder.updateSetting('llm.model'), {
|
1753
1878
|
method: 'PUT',
|
1754
1879
|
headers: {
|
1755
1880
|
'Content-Type': 'application/json',
|
@@ -1778,8 +1903,7 @@
|
|
1778
1903
|
|
1779
1904
|
// Save search engine settings to database
|
1780
1905
|
function saveSearchEngineSettings(engineValue) {
|
1781
|
-
//
|
1782
|
-
localStorage.setItem('lastUsedSearchEngine', engineValue);
|
1906
|
+
// Only save to database, not localStorage
|
1783
1907
|
|
1784
1908
|
// Update any hidden input with the same settings key that might exist in other forms
|
1785
1909
|
const hiddenInputs = document.querySelectorAll('input[id$="_hidden"][name="search.tool"]');
|
@@ -1788,7 +1912,7 @@
|
|
1788
1912
|
});
|
1789
1913
|
|
1790
1914
|
// Save to the database using the settings API
|
1791
|
-
fetch(
|
1915
|
+
fetch(URLS.SETTINGS_API.SEARCH_TOOL, {
|
1792
1916
|
method: 'PUT',
|
1793
1917
|
headers: {
|
1794
1918
|
'Content-Type': 'application/json',
|
@@ -1817,8 +1941,7 @@
|
|
1817
1941
|
|
1818
1942
|
// Save provider setting to database
|
1819
1943
|
function saveProviderSetting(providerValue) {
|
1820
|
-
//
|
1821
|
-
localStorage.setItem('lastUsedProvider', providerValue);
|
1944
|
+
// Only save to database, not localStorage
|
1822
1945
|
|
1823
1946
|
// Update any hidden input with the same settings key that might exist in other forms
|
1824
1947
|
const hiddenInputs = document.querySelectorAll('input[id$="_hidden"][name="llm.provider"]');
|
@@ -1827,7 +1950,7 @@
|
|
1827
1950
|
});
|
1828
1951
|
|
1829
1952
|
// Save to the database using the settings API
|
1830
|
-
fetch(
|
1953
|
+
fetch(URLS.SETTINGS_API.LLM_PROVIDER, {
|
1831
1954
|
method: 'PUT',
|
1832
1955
|
headers: {
|
1833
1956
|
'Content-Type': 'application/json',
|
@@ -1839,6 +1962,14 @@
|
|
1839
1962
|
.then(data => {
|
1840
1963
|
console.log('Provider setting saved to database:', data);
|
1841
1964
|
|
1965
|
+
// If the response includes warnings, display them directly
|
1966
|
+
if (data.warnings && typeof window.displayWarnings === 'function') {
|
1967
|
+
window.displayWarnings(data.warnings);
|
1968
|
+
} else if (typeof window.refetchSettingsAndUpdateWarnings === 'function') {
|
1969
|
+
// Fallback: trigger warning system update
|
1970
|
+
window.refetchSettingsAndUpdateWarnings();
|
1971
|
+
}
|
1972
|
+
|
1842
1973
|
// Optionally show a notification
|
1843
1974
|
if (window.ui && window.ui.showMessage) {
|
1844
1975
|
window.ui.showMessage(`Provider updated to: ${providerValue}`, 'success', 2000);
|
@@ -1854,6 +1985,41 @@
|
|
1854
1985
|
});
|
1855
1986
|
}
|
1856
1987
|
|
1988
|
+
// Save search setting to database
|
1989
|
+
function saveSearchSetting(settingKey, value) {
|
1990
|
+
// Save to the database using the settings API
|
1991
|
+
fetch(`/settings/api/${settingKey}`, {
|
1992
|
+
method: 'PUT',
|
1993
|
+
headers: {
|
1994
|
+
'Content-Type': 'application/json',
|
1995
|
+
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
1996
|
+
},
|
1997
|
+
body: JSON.stringify({ value: value })
|
1998
|
+
})
|
1999
|
+
.then(response => response.json())
|
2000
|
+
.then(data => {
|
2001
|
+
console.log(`Search setting ${settingKey} saved to database:`, data);
|
2002
|
+
|
2003
|
+
// If the response includes warnings, display them directly
|
2004
|
+
if (data.warnings && typeof window.displayWarnings === 'function') {
|
2005
|
+
window.displayWarnings(data.warnings);
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
// Optionally show a notification
|
2009
|
+
if (window.ui && window.ui.showMessage) {
|
2010
|
+
window.ui.showMessage(`${settingKey.split('.').pop()} updated to: ${value}`, 'success', 2000);
|
2011
|
+
}
|
2012
|
+
})
|
2013
|
+
.catch(error => {
|
2014
|
+
console.error(`Error saving search setting ${settingKey} to database:`, error);
|
2015
|
+
|
2016
|
+
// Show error notification if available
|
2017
|
+
if (window.ui && window.ui.showMessage) {
|
2018
|
+
window.ui.showMessage(`Error updating ${settingKey}: ${error.message}`, 'error', 3000);
|
2019
|
+
}
|
2020
|
+
});
|
2021
|
+
}
|
2022
|
+
|
1857
2023
|
// Research form submission handler
|
1858
2024
|
function handleResearchSubmit(event) {
|
1859
2025
|
event.preventDefault();
|
@@ -1918,7 +2084,7 @@
|
|
1918
2084
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
|
1919
2085
|
|
1920
2086
|
// Submit the form data to the backend
|
1921
|
-
fetch(
|
2087
|
+
fetch(URLS.API.START_RESEARCH, {
|
1922
2088
|
method: 'POST',
|
1923
2089
|
headers: {
|
1924
2090
|
'Content-Type': 'application/json',
|
@@ -1932,15 +2098,10 @@
|
|
1932
2098
|
console.log('Research started successfully:', data);
|
1933
2099
|
|
1934
2100
|
// Store research preferences in localStorage
|
1935
|
-
|
1936
|
-
localStorage.setItem('lastModelProvider', modelProvider);
|
1937
|
-
localStorage.setItem('lastModel', model);
|
1938
|
-
localStorage.setItem('lastSearchEngine', searchEngine);
|
1939
|
-
localStorage.setItem('enableNotifications', enableNotifications);
|
1940
|
-
localStorage.setItem('lastUsedStrategy', strategy);
|
2101
|
+
// Settings are saved to database via the API, not localStorage
|
1941
2102
|
|
1942
2103
|
// Redirect to the progress page
|
1943
|
-
window.location.href =
|
2104
|
+
window.location.href = URLBuilder.progressPage(data.research_id);
|
1944
2105
|
} else {
|
1945
2106
|
// Show error message
|
1946
2107
|
showAlert(data.message || 'Failed to start research.', 'error');
|
@@ -55,7 +55,7 @@
|
|
55
55
|
const metricsBtn = document.getElementById('view-metrics-btn');
|
56
56
|
if (metricsBtn) {
|
57
57
|
metricsBtn.addEventListener('click', () => {
|
58
|
-
window.location.href =
|
58
|
+
window.location.href = URLBuilder.detailsPage(researchId);
|
59
59
|
});
|
60
60
|
}
|
61
61
|
|
@@ -73,20 +73,18 @@
|
|
73
73
|
const backBtn = document.getElementById('back-to-history');
|
74
74
|
if (backBtn) {
|
75
75
|
backBtn.addEventListener('click', () => {
|
76
|
-
window.location.href =
|
76
|
+
window.location.href = URLS.PAGES.HISTORY;
|
77
77
|
});
|
78
78
|
}
|
79
79
|
|
80
80
|
}
|
81
81
|
|
82
82
|
/**
|
83
|
-
* Get research ID from URL
|
83
|
+
* Get research ID from URL using centralized URL system
|
84
84
|
* @returns {string|null} Research ID
|
85
85
|
*/
|
86
86
|
function getResearchIdFromUrl() {
|
87
|
-
|
88
|
-
const match = path.match(/\/research\/results\/(\d+)/);
|
89
|
-
return match ? match[1] : null;
|
87
|
+
return URLBuilder.extractResearchIdFromPattern('results');
|
90
88
|
}
|
91
89
|
|
92
90
|
/**
|
@@ -98,7 +96,7 @@
|
|
98
96
|
resultsContainer.innerHTML = '<div class="text-center my-5"><i class="fas fa-spinner fa-pulse"></i><p class="mt-3">Loading research results...</p></div>';
|
99
97
|
|
100
98
|
// Fetch result from API
|
101
|
-
const response = await fetch(`/
|
99
|
+
const response = await fetch(`/api/report/${researchId}`);
|
102
100
|
|
103
101
|
if (!response.ok) {
|
104
102
|
throw new Error(`HTTP error ${response.status}`);
|