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
@@ -172,12 +172,12 @@
|
|
172
172
|
function cacheData(key, data) {
|
173
173
|
try {
|
174
174
|
// Store the data
|
175
|
-
|
175
|
+
// Don't cache - always fetch fresh from API
|
176
176
|
|
177
177
|
// Update or set the timestamp
|
178
178
|
let timestamps;
|
179
179
|
try {
|
180
|
-
timestamps =
|
180
|
+
timestamps = {}; // No cache timestamps
|
181
181
|
// Ensure timestamps is an object, not a number or other type
|
182
182
|
if (typeof timestamps !== 'object' || timestamps === null) {
|
183
183
|
timestamps = {};
|
@@ -188,7 +188,7 @@
|
|
188
188
|
}
|
189
189
|
|
190
190
|
timestamps[key] = Date.now();
|
191
|
-
|
191
|
+
// Don't save cache timestamps
|
192
192
|
|
193
193
|
console.log(`Cached data for ${key}`);
|
194
194
|
} catch (error) {
|
@@ -206,7 +206,7 @@
|
|
206
206
|
// Get timestamps
|
207
207
|
let timestamps;
|
208
208
|
try {
|
209
|
-
timestamps =
|
209
|
+
timestamps = {}; // No cache timestamps
|
210
210
|
// Ensure timestamps is an object, not a number or other type
|
211
211
|
if (typeof timestamps !== 'object' || timestamps === null) {
|
212
212
|
timestamps = {};
|
@@ -221,7 +221,7 @@
|
|
221
221
|
// Check if data exists and is not expired
|
222
222
|
if (timestamp && (Date.now() - timestamp < CACHE_EXPIRATION)) {
|
223
223
|
try {
|
224
|
-
const data =
|
224
|
+
const data = null; // No cached data
|
225
225
|
return data;
|
226
226
|
} catch (e) {
|
227
227
|
console.error('Error parsing cached data:', e);
|
@@ -997,7 +997,7 @@
|
|
997
997
|
// Only run this for the main settings dashboard
|
998
998
|
if (!settingsContent) return;
|
999
999
|
|
1000
|
-
fetch(
|
1000
|
+
fetch(URLS.SETTINGS_API.BASE)
|
1001
1001
|
.then(response => response.json())
|
1002
1002
|
.then(data => {
|
1003
1003
|
if (data.status === 'success') {
|
@@ -1054,6 +1054,7 @@
|
|
1054
1054
|
if (category === 'report_parameters') return 'Report Parameters';
|
1055
1055
|
if (category === 'search_general') return 'Search General';
|
1056
1056
|
if (category === 'search_parameters') return 'Search Parameters';
|
1057
|
+
if (category === 'warnings') return 'Warnings';
|
1057
1058
|
|
1058
1059
|
// Remove any underscores and capitalize each word
|
1059
1060
|
let formattedCategory = category.replace(/_/g, ' ');
|
@@ -1128,13 +1129,14 @@
|
|
1128
1129
|
'enable_web',
|
1129
1130
|
'dark_mode',
|
1130
1131
|
'default_theme',
|
1131
|
-
'theme'
|
1132
|
+
'theme',
|
1133
|
+
'warnings'
|
1132
1134
|
]
|
1133
1135
|
};
|
1134
1136
|
|
1135
1137
|
// Priority settings that should appear at the top of each tab
|
1136
1138
|
const prioritySettings = {
|
1137
|
-
'app': ['enable_web', 'enable_notifications', 'web_interface', 'theme', 'default_theme', 'dark_mode', 'debug', 'host', 'port'],
|
1139
|
+
'app': ['enable_web', 'enable_notifications', 'web_interface', 'theme', 'default_theme', 'dark_mode', 'debug', 'host', 'port', 'warnings'],
|
1138
1140
|
'llm': ['provider', 'model', 'temperature', 'max_tokens', 'api_key', 'openai_endpoint_url', 'lmstudio_url', 'llamacpp_model_path'],
|
1139
1141
|
'search': ['tool', 'iterations', 'questions_per_iteration', 'max_results', 'region', 'search_engine'],
|
1140
1142
|
'report': ['enable_fact_checking', 'knowledge_accumulation', 'output_dir', 'detailed_citations']
|
@@ -2009,10 +2011,10 @@
|
|
2009
2011
|
});
|
2010
2012
|
|
2011
2013
|
// --- ADD THIS LINE ---
|
2012
|
-
console.log('[submitSettingsData] Preparing to fetch /
|
2014
|
+
console.log('[submitSettingsData] Preparing to fetch /settings/save_all_settings with data:', JSON.stringify(formData));
|
2013
2015
|
// --- END ADD ---
|
2014
2016
|
|
2015
|
-
fetch(
|
2017
|
+
fetch(URLS.SETTINGS_API.SAVE_ALL_SETTINGS, {
|
2016
2018
|
method: 'POST',
|
2017
2019
|
headers: {
|
2018
2020
|
'Content-Type': 'application/json',
|
@@ -2363,7 +2365,7 @@
|
|
2363
2365
|
// Show confirmation dialog
|
2364
2366
|
if (confirm('Are you sure you want to reset ALL settings to their default values? This cannot be undone.')) {
|
2365
2367
|
// Call the reset to defaults API
|
2366
|
-
fetch(
|
2368
|
+
fetch(URLS.SETTINGS_API.RESET_TO_DEFAULTS, {
|
2367
2369
|
method: 'POST',
|
2368
2370
|
headers: {
|
2369
2371
|
'Content-Type': 'application/json',
|
@@ -2512,7 +2514,7 @@
|
|
2512
2514
|
// Create a hidden form and submit it to a route that will open the file location
|
2513
2515
|
const form = document.createElement('form');
|
2514
2516
|
form.method = 'POST';
|
2515
|
-
form.action = "/
|
2517
|
+
form.action = "/api/open_file_location";
|
2516
2518
|
|
2517
2519
|
const input = document.createElement('input');
|
2518
2520
|
input.type = 'hidden';
|
@@ -2563,7 +2565,7 @@
|
|
2563
2565
|
*/
|
2564
2566
|
function handleFixCorruptedSettings() {
|
2565
2567
|
// Call the fix corrupted settings API
|
2566
|
-
fetch(
|
2568
|
+
fetch(URLS.SETTINGS_API.FIX_CORRUPTED_SETTINGS, {
|
2567
2569
|
method: 'POST',
|
2568
2570
|
headers: {
|
2569
2571
|
'Content-Type': 'application/json',
|
@@ -2601,7 +2603,7 @@
|
|
2601
2603
|
const controller = new AbortController();
|
2602
2604
|
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
|
2603
2605
|
|
2604
|
-
const response = await fetch(
|
2606
|
+
const response = await fetch(URLS.SETTINGS_API.OLLAMA_STATUS, {
|
2605
2607
|
signal: controller.signal
|
2606
2608
|
});
|
2607
2609
|
|
@@ -2642,7 +2644,11 @@
|
|
2642
2644
|
console.log('Fetching model providers from API');
|
2643
2645
|
|
2644
2646
|
// Create a promise and store it
|
2645
|
-
|
2647
|
+
const url = forceRefresh
|
2648
|
+
? `${URLS.SETTINGS_API.AVAILABLE_MODELS}?force_refresh=true`
|
2649
|
+
: URLS.SETTINGS_API.AVAILABLE_MODELS;
|
2650
|
+
|
2651
|
+
window.modelProvidersRequestInProgress = fetch(url)
|
2646
2652
|
.then(response => {
|
2647
2653
|
if (!response.ok) {
|
2648
2654
|
throw new Error(`API returned status: ${response.status}`);
|
@@ -2695,7 +2701,7 @@
|
|
2695
2701
|
console.log('Fetching search engines from API');
|
2696
2702
|
|
2697
2703
|
// Create a promise and store it
|
2698
|
-
window.searchEnginesRequestInProgress = fetch(
|
2704
|
+
window.searchEnginesRequestInProgress = fetch(URLS.SETTINGS_API.AVAILABLE_SEARCH_ENGINES)
|
2699
2705
|
.then(response => {
|
2700
2706
|
if (!response.ok) {
|
2701
2707
|
throw new Error(`API returned status: ${response.status}`);
|
@@ -2915,7 +2921,7 @@
|
|
2915
2921
|
filterModelOptionsForProvider(value);
|
2916
2922
|
|
2917
2923
|
// Save to localStorage
|
2918
|
-
|
2924
|
+
// Provider saved to DB
|
2919
2925
|
|
2920
2926
|
// Trigger save
|
2921
2927
|
const changeEvent = new Event('change', { bubbles: true });
|
@@ -2961,7 +2967,7 @@
|
|
2961
2967
|
modelHiddenInput.value = value;
|
2962
2968
|
|
2963
2969
|
// Save to localStorage
|
2964
|
-
|
2970
|
+
// Model saved to DB
|
2965
2971
|
}
|
2966
2972
|
},
|
2967
2973
|
true // Allow custom values
|
@@ -3100,7 +3106,7 @@
|
|
3100
3106
|
const changeEvent = new Event('change', { bubbles: true });
|
3101
3107
|
searchEngineHiddenInput.dispatchEvent(changeEvent);
|
3102
3108
|
// Save to localStorage
|
3103
|
-
|
3109
|
+
// Search engine saved to DB
|
3104
3110
|
},
|
3105
3111
|
false, // Don't allow custom values
|
3106
3112
|
'No search engines available.'
|
@@ -3115,7 +3121,7 @@
|
|
3115
3121
|
}
|
3116
3122
|
}
|
3117
3123
|
if (!currentValue) {
|
3118
|
-
currentValue =
|
3124
|
+
currentValue = 'auto'; // Default value, actual value comes from DB
|
3119
3125
|
}
|
3120
3126
|
|
3121
3127
|
// Set initial value
|
@@ -3388,7 +3394,7 @@
|
|
3388
3394
|
const logoLink = document.getElementById('logo-link');
|
3389
3395
|
if (logoLink) {
|
3390
3396
|
logoLink.addEventListener('click', () => {
|
3391
|
-
window.location.href =
|
3397
|
+
window.location.href = URLS.PAGES.HOME;
|
3392
3398
|
});
|
3393
3399
|
}
|
3394
3400
|
|
@@ -3507,11 +3513,11 @@
|
|
3507
3513
|
// Fallback to localStorage values if we don't have a value yet
|
3508
3514
|
if (!currentValue) {
|
3509
3515
|
if (settingKey === 'llm.model') {
|
3510
|
-
currentValue =
|
3516
|
+
currentValue = ''; // Value comes from DB
|
3511
3517
|
} else if (settingKey === 'llm.provider') {
|
3512
|
-
currentValue =
|
3518
|
+
currentValue = ''; // Value comes from DB
|
3513
3519
|
} else if (settingKey === 'search.tool') {
|
3514
|
-
currentValue =
|
3520
|
+
currentValue = ''; // Value comes from DB
|
3515
3521
|
}
|
3516
3522
|
}
|
3517
3523
|
|
@@ -3623,11 +3629,11 @@
|
|
3623
3629
|
|
3624
3630
|
// Save to localStorage for persistence
|
3625
3631
|
if (settingKey === 'llm.model') {
|
3626
|
-
|
3632
|
+
// Model saved to DB
|
3627
3633
|
} else if (settingKey === 'llm.provider') {
|
3628
3634
|
localStorage.setItem('lastUsedProvider', value);
|
3629
3635
|
} else if (settingKey === 'search.tool') {
|
3630
|
-
|
3636
|
+
// Search engine saved to DB
|
3631
3637
|
}
|
3632
3638
|
},
|
3633
3639
|
allowCustom
|
@@ -1,45 +1,46 @@
|
|
1
|
-
// Function to save settings using the settings
|
1
|
+
// Function to save settings using the individual settings manager API
|
2
2
|
function saveMenuSettings(settingKey, settingValue) {
|
3
|
-
// Create payload with the single setting being changed
|
4
|
-
const payload = {};
|
5
|
-
payload[settingKey] = settingValue;
|
6
|
-
|
7
3
|
console.log('Saving setting:', settingKey, '=', settingValue);
|
8
4
|
|
9
5
|
// Get CSRF token
|
10
6
|
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
11
7
|
|
12
|
-
// Use
|
13
|
-
fetch(
|
14
|
-
method: '
|
8
|
+
// Use the individual settings API endpoint that uses the settings manager
|
9
|
+
fetch(`/settings/api/${settingKey}`, {
|
10
|
+
method: 'PUT',
|
15
11
|
headers: {
|
16
12
|
'Content-Type': 'application/json',
|
17
13
|
'X-CSRFToken': csrfToken
|
18
14
|
},
|
19
|
-
body: JSON.stringify(
|
15
|
+
body: JSON.stringify({ value: settingValue })
|
20
16
|
})
|
21
17
|
.then(response => response.json())
|
22
18
|
.then(data => {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
console.log(`Setting ${settingKey} saved via settings manager:`, data);
|
20
|
+
|
21
|
+
// If the response includes warnings, display them directly
|
22
|
+
if (data.warnings && typeof window.displayWarnings === 'function') {
|
23
|
+
window.displayWarnings(data.warnings);
|
24
|
+
}
|
25
|
+
|
26
|
+
// Also trigger client-side warning recalculation for search settings
|
27
|
+
if (settingKey.startsWith('search.') || settingKey === 'llm.provider') {
|
28
|
+
if (typeof window.refetchSettingsAndUpdateWarnings === 'function') {
|
29
|
+
window.refetchSettingsAndUpdateWarnings();
|
29
30
|
}
|
31
|
+
}
|
32
|
+
|
33
|
+
// Show success notification if UI module is available
|
34
|
+
if (window.ui && window.ui.showMessage) {
|
35
|
+
window.ui.showMessage(`${settingKey.split('.').pop()} updated successfully`, 'success');
|
30
36
|
} else {
|
31
|
-
|
32
|
-
if (window.ui && window.ui.showMessage) {
|
33
|
-
window.ui.showMessage('Failed to save setting: ' + (data.message || 'Unknown error'), 'error');
|
34
|
-
} else {
|
35
|
-
console.error('Failed to save setting:', data);
|
36
|
-
}
|
37
|
+
console.log('Setting saved successfully:', data);
|
37
38
|
}
|
38
39
|
})
|
39
40
|
.catch(error => {
|
40
|
-
console.error(
|
41
|
+
console.error(`Error saving setting ${settingKey}:`, error);
|
41
42
|
if (window.ui && window.ui.showMessage) {
|
42
|
-
window.ui.showMessage(
|
43
|
+
window.ui.showMessage(`Error updating ${settingKey}: ${error.message}`, 'error');
|
43
44
|
}
|
44
45
|
});
|
45
46
|
}
|
@@ -0,0 +1,285 @@
|
|
1
|
+
/**
|
2
|
+
* Centralized URL configuration for the Local Deep Research application
|
3
|
+
* This prevents hardcoded URLs scattered throughout the codebase
|
4
|
+
*/
|
5
|
+
|
6
|
+
const URLS = {
|
7
|
+
// API endpoints
|
8
|
+
API: {
|
9
|
+
START_RESEARCH: '/api/start_research',
|
10
|
+
RESEARCH_STATUS: '/api/research/{id}/status',
|
11
|
+
RESEARCH_DETAILS: '/api/research/{id}',
|
12
|
+
RESEARCH_LOGS: '/api/research/{id}/logs',
|
13
|
+
RESEARCH_REPORT: '/api/report/{id}',
|
14
|
+
TERMINATE_RESEARCH: '/api/terminate/{id}',
|
15
|
+
DELETE_RESEARCH: '/api/delete/{id}',
|
16
|
+
CLEAR_HISTORY: '/api/clear_history',
|
17
|
+
SAVE_RAW_CONFIG: '/api/save_raw_config',
|
18
|
+
SAVE_MAIN_CONFIG: '/api/save_main_config',
|
19
|
+
SAVE_SEARCH_ENGINES_CONFIG: '/api/save_search_engines_config',
|
20
|
+
SAVE_COLLECTIONS_CONFIG: '/api/save_collections_config',
|
21
|
+
SAVE_API_KEYS_CONFIG: '/api/save_api_keys_config',
|
22
|
+
SAVE_LLM_CONFIG: '/api/save_llm_config',
|
23
|
+
MARKDOWN_EXPORT: '/api/markdown/{id}',
|
24
|
+
HISTORY: '/history/api', // Changed to match backend route
|
25
|
+
HEALTH: '/api/v1/health' // Added health check endpoint
|
26
|
+
},
|
27
|
+
|
28
|
+
// Page routes
|
29
|
+
PAGES: {
|
30
|
+
HOME: '/',
|
31
|
+
PROGRESS: '/progress/{id}',
|
32
|
+
RESULTS: '/results/{id}',
|
33
|
+
DETAILS: '/details/{id}',
|
34
|
+
HISTORY: '/history/',
|
35
|
+
SETTINGS: '/settings/',
|
36
|
+
METRICS: '/metrics/',
|
37
|
+
METRICS_COSTS: '/metrics/costs', // Added metrics subpage
|
38
|
+
METRICS_STAR_REVIEWS: '/metrics/star-reviews' // Added metrics subpage
|
39
|
+
},
|
40
|
+
|
41
|
+
// History API routes
|
42
|
+
HISTORY_API: {
|
43
|
+
STATUS: '/history/status/{id}',
|
44
|
+
DETAILS: '/history/details/{id}',
|
45
|
+
LOGS: '/history/logs/{id}',
|
46
|
+
REPORT: '/history/history/report/{id}',
|
47
|
+
MARKDOWN: '/history/markdown/{id}',
|
48
|
+
LOG_COUNT: '/history/log_count/{id}'
|
49
|
+
},
|
50
|
+
|
51
|
+
// Settings API routes
|
52
|
+
SETTINGS_API: {
|
53
|
+
BASE: '/settings/api',
|
54
|
+
GET_SETTING: '/settings/api/{key}',
|
55
|
+
UPDATE_SETTING: '/settings/api/{key}',
|
56
|
+
DELETE_SETTING: '/settings/api/{key}',
|
57
|
+
IMPORT_SETTINGS: '/settings/api/import',
|
58
|
+
CATEGORIES: '/settings/api/categories',
|
59
|
+
TYPES: '/settings/api/types',
|
60
|
+
UI_ELEMENTS: '/settings/api/ui_elements',
|
61
|
+
AVAILABLE_MODELS: '/settings/api/available-models',
|
62
|
+
AVAILABLE_SEARCH_ENGINES: '/settings/api/available-search-engines',
|
63
|
+
WARNINGS: '/settings/api/warnings',
|
64
|
+
OLLAMA_STATUS: '/settings/api/ollama-status',
|
65
|
+
LLM_MODEL: '/settings/api/llm.model',
|
66
|
+
LLM_PROVIDER: '/settings/api/llm.provider',
|
67
|
+
LLM_CONFIG: '/settings/api/llm',
|
68
|
+
SEARCH_TOOL: '/settings/api/search.tool',
|
69
|
+
SAVE_ALL_SETTINGS: '/settings/save_all_settings',
|
70
|
+
RESET_TO_DEFAULTS: '/settings/reset_to_defaults',
|
71
|
+
FIX_CORRUPTED_SETTINGS: '/settings/fix_corrupted_settings'
|
72
|
+
},
|
73
|
+
|
74
|
+
// Metrics API routes
|
75
|
+
METRICS_API: {
|
76
|
+
BASE: '/metrics/api/metrics',
|
77
|
+
RESEARCH: '/metrics/api/metrics/research/{id}',
|
78
|
+
RESEARCH_TIMELINE: '/metrics/api/metrics/research/{id}/timeline',
|
79
|
+
RESEARCH_SEARCH: '/metrics/api/metrics/research/{id}/search',
|
80
|
+
COST_ANALYTICS: '/metrics/api/cost-analytics',
|
81
|
+
PRICING: '/metrics/api/pricing',
|
82
|
+
RATINGS_GET: '/metrics/api/ratings/{id}',
|
83
|
+
RATINGS_SAVE: '/metrics/api/ratings/{id}',
|
84
|
+
RESEARCH_COSTS: '/metrics/api/research-costs/{id}'
|
85
|
+
}
|
86
|
+
};
|
87
|
+
|
88
|
+
/**
|
89
|
+
* URL builder utility functions
|
90
|
+
*/
|
91
|
+
const URLBuilder = {
|
92
|
+
/**
|
93
|
+
* Build a URL by replacing {id} placeholders with actual values
|
94
|
+
* @param {string} urlTemplate - URL template with {id} placeholders
|
95
|
+
* @param {string|number} id - The ID to substitute
|
96
|
+
* @returns {string} - The built URL
|
97
|
+
*/
|
98
|
+
build(urlTemplate, id) {
|
99
|
+
return urlTemplate.replace('{id}', id);
|
100
|
+
},
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Build a URL with custom replacements
|
104
|
+
* @param {string} urlTemplate - URL template with placeholders
|
105
|
+
* @param {Object} replacements - Object with key-value pairs for replacement
|
106
|
+
* @returns {string} - The built URL
|
107
|
+
*/
|
108
|
+
buildWithReplacements(urlTemplate, replacements) {
|
109
|
+
let url = urlTemplate;
|
110
|
+
for (const [key, value] of Object.entries(replacements)) {
|
111
|
+
url = url.replace(`{${key}}`, value);
|
112
|
+
}
|
113
|
+
return url;
|
114
|
+
},
|
115
|
+
|
116
|
+
// Convenience methods for common URL patterns
|
117
|
+
progressPage(researchId) {
|
118
|
+
return this.build(URLS.PAGES.PROGRESS, researchId);
|
119
|
+
},
|
120
|
+
|
121
|
+
resultsPage(researchId) {
|
122
|
+
return this.build(URLS.PAGES.RESULTS, researchId);
|
123
|
+
},
|
124
|
+
|
125
|
+
detailsPage(researchId) {
|
126
|
+
return this.build(URLS.PAGES.DETAILS, researchId);
|
127
|
+
},
|
128
|
+
|
129
|
+
researchStatus(researchId) {
|
130
|
+
return this.build(URLS.API.RESEARCH_STATUS, researchId);
|
131
|
+
},
|
132
|
+
|
133
|
+
researchDetails(researchId) {
|
134
|
+
return this.build(URLS.API.RESEARCH_DETAILS, researchId);
|
135
|
+
},
|
136
|
+
|
137
|
+
researchLogs(researchId) {
|
138
|
+
return this.build(URLS.API.RESEARCH_LOGS, researchId);
|
139
|
+
},
|
140
|
+
|
141
|
+
researchReport(researchId) {
|
142
|
+
return this.build(URLS.API.RESEARCH_REPORT, researchId);
|
143
|
+
},
|
144
|
+
|
145
|
+
terminateResearch(researchId) {
|
146
|
+
return this.build(URLS.API.TERMINATE_RESEARCH, researchId);
|
147
|
+
},
|
148
|
+
|
149
|
+
deleteResearch(researchId) {
|
150
|
+
return this.build(URLS.API.DELETE_RESEARCH, researchId);
|
151
|
+
},
|
152
|
+
|
153
|
+
// History API convenience methods
|
154
|
+
historyStatus(researchId) {
|
155
|
+
return this.build(URLS.HISTORY_API.STATUS, researchId);
|
156
|
+
},
|
157
|
+
|
158
|
+
historyDetails(researchId) {
|
159
|
+
return this.build(URLS.HISTORY_API.DETAILS, researchId);
|
160
|
+
},
|
161
|
+
|
162
|
+
historyLogs(researchId) {
|
163
|
+
return this.build(URLS.HISTORY_API.LOGS, researchId);
|
164
|
+
},
|
165
|
+
|
166
|
+
markdownExport(researchId) {
|
167
|
+
return this.build(URLS.API.MARKDOWN_EXPORT, researchId);
|
168
|
+
},
|
169
|
+
|
170
|
+
historyReport(researchId) {
|
171
|
+
return this.build(URLS.HISTORY_API.REPORT, researchId);
|
172
|
+
},
|
173
|
+
|
174
|
+
// URL Pattern Extraction Methods
|
175
|
+
/**
|
176
|
+
* Extract research ID from current URL path
|
177
|
+
* @returns {string|null} Research ID or null if not found
|
178
|
+
*/
|
179
|
+
extractResearchId() {
|
180
|
+
const path = window.location.pathname;
|
181
|
+
|
182
|
+
// Try different URL patterns
|
183
|
+
const patterns = [
|
184
|
+
/\/results\/(\d+)/, // /results/123
|
185
|
+
/\/details\/(\d+)/, // /details/123
|
186
|
+
/\/progress\/(\d+)/ // /progress/123
|
187
|
+
];
|
188
|
+
|
189
|
+
for (const pattern of patterns) {
|
190
|
+
const match = path.match(pattern);
|
191
|
+
if (match) {
|
192
|
+
return match[1];
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
return null;
|
197
|
+
},
|
198
|
+
|
199
|
+
/**
|
200
|
+
* Extract research ID from a specific URL pattern
|
201
|
+
* @param {string} pattern - The pattern to match ('results', 'details', 'progress')
|
202
|
+
* @returns {string|null} Research ID or null if not found
|
203
|
+
*/
|
204
|
+
extractResearchIdFromPattern(pattern) {
|
205
|
+
const path = window.location.pathname;
|
206
|
+
const regex = new RegExp(`\\/${pattern}\\/(\\d+)`);
|
207
|
+
const match = path.match(regex);
|
208
|
+
return match ? match[1] : null;
|
209
|
+
},
|
210
|
+
|
211
|
+
/**
|
212
|
+
* Get current page type based on URL
|
213
|
+
* @returns {string} Page type ('home', 'results', 'details', 'progress', 'history', 'settings', 'metrics', 'unknown')
|
214
|
+
*/
|
215
|
+
getCurrentPageType() {
|
216
|
+
const path = window.location.pathname;
|
217
|
+
|
218
|
+
if (path === '/' || path === '/index' || path === '/home') return 'home';
|
219
|
+
if (path.startsWith('/results/')) return 'results';
|
220
|
+
if (path.startsWith('/details/')) return 'details';
|
221
|
+
if (path.startsWith('/progress/')) return 'progress';
|
222
|
+
if (path.startsWith('/history')) return 'history';
|
223
|
+
if (path.startsWith('/settings')) return 'settings';
|
224
|
+
if (path.startsWith('/metrics')) return 'metrics';
|
225
|
+
|
226
|
+
return 'unknown';
|
227
|
+
},
|
228
|
+
|
229
|
+
historyMarkdown(researchId) {
|
230
|
+
return this.build(URLS.HISTORY_API.MARKDOWN, researchId);
|
231
|
+
},
|
232
|
+
|
233
|
+
historyLogCount(researchId) {
|
234
|
+
return this.build(URLS.HISTORY_API.LOG_COUNT, researchId);
|
235
|
+
},
|
236
|
+
|
237
|
+
// Settings API convenience methods
|
238
|
+
getSetting(key) {
|
239
|
+
return this.buildWithReplacements(URLS.SETTINGS_API.GET_SETTING, { key });
|
240
|
+
},
|
241
|
+
|
242
|
+
updateSetting(key) {
|
243
|
+
return this.buildWithReplacements(URLS.SETTINGS_API.UPDATE_SETTING, { key });
|
244
|
+
},
|
245
|
+
|
246
|
+
deleteSetting(key) {
|
247
|
+
return this.buildWithReplacements(URLS.SETTINGS_API.DELETE_SETTING, { key });
|
248
|
+
},
|
249
|
+
|
250
|
+
// Metrics API convenience methods
|
251
|
+
researchMetrics(researchId) {
|
252
|
+
return this.build(URLS.METRICS_API.RESEARCH, researchId);
|
253
|
+
},
|
254
|
+
|
255
|
+
researchTimelineMetrics(researchId) {
|
256
|
+
return this.build(URLS.METRICS_API.RESEARCH_TIMELINE, researchId);
|
257
|
+
},
|
258
|
+
|
259
|
+
researchSearchMetrics(researchId) {
|
260
|
+
return this.build(URLS.METRICS_API.RESEARCH_SEARCH, researchId);
|
261
|
+
},
|
262
|
+
|
263
|
+
getRating(researchId) {
|
264
|
+
return this.build(URLS.METRICS_API.RATINGS_GET, researchId);
|
265
|
+
},
|
266
|
+
|
267
|
+
saveRating(researchId) {
|
268
|
+
return this.build(URLS.METRICS_API.RATINGS_SAVE, researchId);
|
269
|
+
},
|
270
|
+
|
271
|
+
researchCosts(researchId) {
|
272
|
+
return this.build(URLS.METRICS_API.RESEARCH_COSTS, researchId);
|
273
|
+
}
|
274
|
+
};
|
275
|
+
|
276
|
+
// Export for module systems first (before window assignment)
|
277
|
+
if (typeof module !== 'undefined' && module.exports) {
|
278
|
+
module.exports = { URLS, URLBuilder };
|
279
|
+
}
|
280
|
+
|
281
|
+
// Make URLs and URLBuilder available globally
|
282
|
+
if (typeof window !== 'undefined') {
|
283
|
+
window.URLS = URLS;
|
284
|
+
window.URLBuilder = URLBuilder;
|
285
|
+
}
|
@@ -75,7 +75,7 @@
|
|
75
75
|
function loadAudioServiceFirst(callback) {
|
76
76
|
console.log('Loading audio service script first...');
|
77
77
|
const audioScript = document.createElement('script');
|
78
|
-
audioScript.src = `/
|
78
|
+
audioScript.src = `/static/js/services/audio.js?t=${new Date().getTime()}`; // Add timestamp to avoid cache
|
79
79
|
audioScript.async = false;
|
80
80
|
|
81
81
|
// Set up callback for when script loads
|
@@ -122,17 +122,17 @@
|
|
122
122
|
// Check URL patterns as fallback
|
123
123
|
const path = window.location.pathname;
|
124
124
|
|
125
|
-
if (path === '/' || path === '/index' || path === '/home'
|
125
|
+
if (path === '/' || path === '/index' || path === '/home') {
|
126
126
|
return 'page-home';
|
127
|
-
} else if (path.includes('/
|
127
|
+
} else if (path.includes('/progress')) {
|
128
128
|
return 'page-progress';
|
129
|
-
} else if (path.includes('/
|
129
|
+
} else if (path.includes('/results')) {
|
130
130
|
return 'page-results';
|
131
|
-
} else if (path.includes('/
|
131
|
+
} else if (path.includes('/details')) {
|
132
132
|
return 'page-detail';
|
133
|
-
} else if (path.includes('/
|
133
|
+
} else if (path.includes('/history')) {
|
134
134
|
return 'page-history';
|
135
|
-
} else if (path.includes('/
|
135
|
+
} else if (path.includes('/settings')) {
|
136
136
|
return 'page-settings';
|
137
137
|
}
|
138
138
|
|
@@ -149,7 +149,7 @@
|
|
149
149
|
|
150
150
|
scripts.forEach(script => {
|
151
151
|
const scriptElement = document.createElement('script');
|
152
|
-
scriptElement.src = `/
|
152
|
+
scriptElement.src = `/static/js/${folder}/${script}`;
|
153
153
|
scriptElement.async = false; // Load in sequence
|
154
154
|
document.body.appendChild(scriptElement);
|
155
155
|
});
|