local-deep-research 0.4.4__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- local_deep_research/__init__.py +7 -0
- local_deep_research/__version__.py +1 -1
- local_deep_research/advanced_search_system/answer_decoding/__init__.py +5 -0
- local_deep_research/advanced_search_system/answer_decoding/browsecomp_answer_decoder.py +421 -0
- local_deep_research/advanced_search_system/candidate_exploration/README.md +219 -0
- local_deep_research/advanced_search_system/candidate_exploration/__init__.py +25 -0
- local_deep_research/advanced_search_system/candidate_exploration/adaptive_explorer.py +329 -0
- local_deep_research/advanced_search_system/candidate_exploration/base_explorer.py +341 -0
- local_deep_research/advanced_search_system/candidate_exploration/constraint_guided_explorer.py +436 -0
- local_deep_research/advanced_search_system/candidate_exploration/diversity_explorer.py +457 -0
- local_deep_research/advanced_search_system/candidate_exploration/parallel_explorer.py +250 -0
- local_deep_research/advanced_search_system/candidate_exploration/progressive_explorer.py +255 -0
- local_deep_research/advanced_search_system/candidates/__init__.py +5 -0
- local_deep_research/advanced_search_system/candidates/base_candidate.py +59 -0
- local_deep_research/advanced_search_system/constraint_checking/README.md +150 -0
- local_deep_research/advanced_search_system/constraint_checking/__init__.py +35 -0
- local_deep_research/advanced_search_system/constraint_checking/base_constraint_checker.py +122 -0
- local_deep_research/advanced_search_system/constraint_checking/constraint_checker.py +223 -0
- local_deep_research/advanced_search_system/constraint_checking/constraint_satisfaction_tracker.py +387 -0
- local_deep_research/advanced_search_system/constraint_checking/dual_confidence_checker.py +424 -0
- local_deep_research/advanced_search_system/constraint_checking/evidence_analyzer.py +174 -0
- local_deep_research/advanced_search_system/constraint_checking/intelligent_constraint_relaxer.py +503 -0
- local_deep_research/advanced_search_system/constraint_checking/rejection_engine.py +143 -0
- local_deep_research/advanced_search_system/constraint_checking/strict_checker.py +259 -0
- local_deep_research/advanced_search_system/constraint_checking/threshold_checker.py +213 -0
- local_deep_research/advanced_search_system/constraints/__init__.py +6 -0
- local_deep_research/advanced_search_system/constraints/base_constraint.py +58 -0
- local_deep_research/advanced_search_system/constraints/constraint_analyzer.py +143 -0
- local_deep_research/advanced_search_system/evidence/__init__.py +12 -0
- local_deep_research/advanced_search_system/evidence/base_evidence.py +57 -0
- local_deep_research/advanced_search_system/evidence/evaluator.py +159 -0
- local_deep_research/advanced_search_system/evidence/requirements.py +122 -0
- local_deep_research/advanced_search_system/filters/base_filter.py +3 -1
- local_deep_research/advanced_search_system/filters/cross_engine_filter.py +8 -2
- local_deep_research/advanced_search_system/filters/journal_reputation_filter.py +43 -29
- local_deep_research/advanced_search_system/findings/repository.py +54 -17
- local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +3 -1
- local_deep_research/advanced_search_system/query_generation/adaptive_query_generator.py +405 -0
- local_deep_research/advanced_search_system/questions/__init__.py +16 -0
- local_deep_research/advanced_search_system/questions/atomic_fact_question.py +171 -0
- local_deep_research/advanced_search_system/questions/browsecomp_question.py +287 -0
- local_deep_research/advanced_search_system/questions/decomposition_question.py +13 -4
- local_deep_research/advanced_search_system/questions/entity_aware_question.py +184 -0
- local_deep_research/advanced_search_system/questions/standard_question.py +9 -3
- local_deep_research/advanced_search_system/search_optimization/cross_constraint_manager.py +624 -0
- local_deep_research/advanced_search_system/source_management/diversity_manager.py +613 -0
- local_deep_research/advanced_search_system/strategies/__init__.py +42 -0
- local_deep_research/advanced_search_system/strategies/adaptive_decomposition_strategy.py +564 -0
- local_deep_research/advanced_search_system/strategies/base_strategy.py +4 -4
- local_deep_research/advanced_search_system/strategies/browsecomp_entity_strategy.py +1031 -0
- local_deep_research/advanced_search_system/strategies/browsecomp_optimized_strategy.py +778 -0
- local_deep_research/advanced_search_system/strategies/concurrent_dual_confidence_strategy.py +446 -0
- local_deep_research/advanced_search_system/strategies/constrained_search_strategy.py +1348 -0
- local_deep_research/advanced_search_system/strategies/constraint_parallel_strategy.py +522 -0
- local_deep_research/advanced_search_system/strategies/direct_search_strategy.py +217 -0
- local_deep_research/advanced_search_system/strategies/dual_confidence_strategy.py +320 -0
- local_deep_research/advanced_search_system/strategies/dual_confidence_with_rejection.py +219 -0
- local_deep_research/advanced_search_system/strategies/early_stop_constrained_strategy.py +369 -0
- local_deep_research/advanced_search_system/strategies/entity_aware_source_strategy.py +140 -0
- local_deep_research/advanced_search_system/strategies/evidence_based_strategy.py +1248 -0
- local_deep_research/advanced_search_system/strategies/evidence_based_strategy_v2.py +1337 -0
- local_deep_research/advanced_search_system/strategies/focused_iteration_strategy.py +537 -0
- local_deep_research/advanced_search_system/strategies/improved_evidence_based_strategy.py +782 -0
- local_deep_research/advanced_search_system/strategies/iterative_reasoning_strategy.py +760 -0
- local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +55 -21
- local_deep_research/advanced_search_system/strategies/llm_driven_modular_strategy.py +865 -0
- local_deep_research/advanced_search_system/strategies/modular_strategy.py +1142 -0
- local_deep_research/advanced_search_system/strategies/parallel_constrained_strategy.py +506 -0
- local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +34 -16
- local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +29 -9
- local_deep_research/advanced_search_system/strategies/recursive_decomposition_strategy.py +492 -0
- local_deep_research/advanced_search_system/strategies/smart_decomposition_strategy.py +284 -0
- local_deep_research/advanced_search_system/strategies/smart_query_strategy.py +515 -0
- local_deep_research/advanced_search_system/strategies/source_based_strategy.py +48 -24
- local_deep_research/advanced_search_system/strategies/standard_strategy.py +34 -14
- local_deep_research/advanced_search_system/tools/base_tool.py +7 -2
- local_deep_research/api/benchmark_functions.py +6 -2
- local_deep_research/api/research_functions.py +10 -4
- local_deep_research/benchmarks/__init__.py +9 -7
- local_deep_research/benchmarks/benchmark_functions.py +6 -2
- local_deep_research/benchmarks/cli/benchmark_commands.py +27 -10
- local_deep_research/benchmarks/cli.py +38 -13
- local_deep_research/benchmarks/comparison/__init__.py +4 -2
- local_deep_research/benchmarks/comparison/evaluator.py +316 -239
- local_deep_research/benchmarks/datasets/__init__.py +1 -1
- local_deep_research/benchmarks/datasets/base.py +91 -72
- local_deep_research/benchmarks/datasets/browsecomp.py +54 -33
- local_deep_research/benchmarks/datasets/custom_dataset_template.py +19 -19
- local_deep_research/benchmarks/datasets/simpleqa.py +14 -14
- local_deep_research/benchmarks/datasets/utils.py +48 -29
- local_deep_research/benchmarks/datasets.py +4 -11
- local_deep_research/benchmarks/efficiency/__init__.py +8 -4
- local_deep_research/benchmarks/efficiency/resource_monitor.py +223 -171
- local_deep_research/benchmarks/efficiency/speed_profiler.py +62 -48
- local_deep_research/benchmarks/evaluators/browsecomp.py +3 -1
- local_deep_research/benchmarks/evaluators/composite.py +6 -2
- local_deep_research/benchmarks/evaluators/simpleqa.py +36 -13
- local_deep_research/benchmarks/graders.py +32 -10
- local_deep_research/benchmarks/metrics/README.md +1 -1
- local_deep_research/benchmarks/metrics/calculation.py +25 -10
- local_deep_research/benchmarks/metrics/reporting.py +7 -3
- local_deep_research/benchmarks/metrics/visualization.py +42 -23
- local_deep_research/benchmarks/metrics.py +1 -1
- local_deep_research/benchmarks/optimization/__init__.py +3 -1
- local_deep_research/benchmarks/optimization/api.py +7 -1
- local_deep_research/benchmarks/optimization/optuna_optimizer.py +75 -26
- local_deep_research/benchmarks/runners.py +48 -15
- local_deep_research/citation_handler.py +65 -92
- local_deep_research/citation_handlers/__init__.py +15 -0
- local_deep_research/citation_handlers/base_citation_handler.py +70 -0
- local_deep_research/citation_handlers/forced_answer_citation_handler.py +179 -0
- local_deep_research/citation_handlers/precision_extraction_handler.py +550 -0
- local_deep_research/citation_handlers/standard_citation_handler.py +80 -0
- local_deep_research/config/llm_config.py +271 -169
- local_deep_research/config/search_config.py +14 -5
- local_deep_research/defaults/__init__.py +0 -1
- local_deep_research/metrics/__init__.py +13 -0
- local_deep_research/metrics/database.py +58 -0
- local_deep_research/metrics/db_models.py +115 -0
- local_deep_research/metrics/migrate_add_provider_to_token_usage.py +148 -0
- local_deep_research/metrics/migrate_call_stack_tracking.py +105 -0
- local_deep_research/metrics/migrate_enhanced_tracking.py +75 -0
- local_deep_research/metrics/migrate_research_ratings.py +31 -0
- local_deep_research/metrics/models.py +61 -0
- local_deep_research/metrics/pricing/__init__.py +12 -0
- local_deep_research/metrics/pricing/cost_calculator.py +237 -0
- local_deep_research/metrics/pricing/pricing_cache.py +143 -0
- local_deep_research/metrics/pricing/pricing_fetcher.py +240 -0
- local_deep_research/metrics/query_utils.py +51 -0
- local_deep_research/metrics/search_tracker.py +380 -0
- local_deep_research/metrics/token_counter.py +1078 -0
- local_deep_research/migrate_db.py +3 -1
- local_deep_research/report_generator.py +22 -8
- local_deep_research/search_system.py +390 -9
- local_deep_research/test_migration.py +15 -5
- local_deep_research/utilities/db_utils.py +7 -4
- local_deep_research/utilities/es_utils.py +115 -104
- local_deep_research/utilities/llm_utils.py +15 -5
- local_deep_research/utilities/log_utils.py +151 -0
- local_deep_research/utilities/search_cache.py +387 -0
- local_deep_research/utilities/search_utilities.py +14 -6
- local_deep_research/utilities/threading_utils.py +92 -0
- local_deep_research/utilities/url_utils.py +6 -0
- local_deep_research/web/api.py +347 -0
- local_deep_research/web/app.py +13 -17
- local_deep_research/web/app_factory.py +71 -66
- local_deep_research/web/database/migrate_to_ldr_db.py +12 -4
- local_deep_research/web/database/migrations.py +20 -3
- local_deep_research/web/database/models.py +74 -25
- local_deep_research/web/database/schema_upgrade.py +49 -29
- local_deep_research/web/models/database.py +63 -83
- local_deep_research/web/routes/api_routes.py +56 -22
- local_deep_research/web/routes/benchmark_routes.py +4 -1
- local_deep_research/web/routes/globals.py +22 -0
- local_deep_research/web/routes/history_routes.py +71 -46
- local_deep_research/web/routes/metrics_routes.py +1155 -0
- local_deep_research/web/routes/research_routes.py +192 -54
- local_deep_research/web/routes/settings_routes.py +156 -55
- local_deep_research/web/services/research_service.py +412 -251
- local_deep_research/web/services/resource_service.py +36 -11
- local_deep_research/web/services/settings_manager.py +55 -17
- local_deep_research/web/services/settings_service.py +12 -4
- local_deep_research/web/services/socket_service.py +295 -188
- local_deep_research/web/static/css/custom_dropdown.css +180 -0
- local_deep_research/web/static/css/styles.css +39 -1
- local_deep_research/web/static/js/components/detail.js +633 -267
- local_deep_research/web/static/js/components/details.js +751 -0
- local_deep_research/web/static/js/components/fallback/formatting.js +11 -11
- local_deep_research/web/static/js/components/fallback/ui.js +23 -23
- local_deep_research/web/static/js/components/history.js +76 -76
- local_deep_research/web/static/js/components/logpanel.js +61 -13
- local_deep_research/web/static/js/components/progress.js +13 -2
- local_deep_research/web/static/js/components/research.js +99 -12
- local_deep_research/web/static/js/components/results.js +239 -106
- local_deep_research/web/static/js/main.js +40 -40
- local_deep_research/web/static/js/services/audio.js +1 -1
- local_deep_research/web/static/js/services/formatting.js +11 -11
- local_deep_research/web/static/js/services/keyboard.js +157 -0
- local_deep_research/web/static/js/services/pdf.js +80 -80
- local_deep_research/web/static/sounds/README.md +1 -1
- local_deep_research/web/templates/base.html +1 -0
- local_deep_research/web/templates/components/log_panel.html +7 -1
- local_deep_research/web/templates/components/mobile_nav.html +1 -1
- local_deep_research/web/templates/components/sidebar.html +3 -0
- local_deep_research/web/templates/pages/cost_analytics.html +1245 -0
- local_deep_research/web/templates/pages/details.html +325 -24
- local_deep_research/web/templates/pages/history.html +1 -1
- local_deep_research/web/templates/pages/metrics.html +1929 -0
- local_deep_research/web/templates/pages/progress.html +2 -2
- local_deep_research/web/templates/pages/research.html +53 -17
- local_deep_research/web/templates/pages/results.html +12 -1
- local_deep_research/web/templates/pages/star_reviews.html +803 -0
- local_deep_research/web/utils/formatters.py +9 -3
- local_deep_research/web_search_engines/default_search_engines.py +5 -3
- local_deep_research/web_search_engines/engines/full_search.py +8 -2
- local_deep_research/web_search_engines/engines/meta_search_engine.py +59 -20
- local_deep_research/web_search_engines/engines/search_engine_arxiv.py +19 -6
- local_deep_research/web_search_engines/engines/search_engine_brave.py +6 -2
- local_deep_research/web_search_engines/engines/search_engine_ddg.py +3 -1
- local_deep_research/web_search_engines/engines/search_engine_elasticsearch.py +81 -58
- local_deep_research/web_search_engines/engines/search_engine_github.py +46 -15
- local_deep_research/web_search_engines/engines/search_engine_google_pse.py +16 -6
- local_deep_research/web_search_engines/engines/search_engine_guardian.py +39 -15
- local_deep_research/web_search_engines/engines/search_engine_local.py +58 -25
- local_deep_research/web_search_engines/engines/search_engine_local_all.py +15 -5
- local_deep_research/web_search_engines/engines/search_engine_pubmed.py +63 -21
- local_deep_research/web_search_engines/engines/search_engine_searxng.py +37 -11
- local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +27 -9
- local_deep_research/web_search_engines/engines/search_engine_serpapi.py +12 -4
- local_deep_research/web_search_engines/engines/search_engine_wayback.py +31 -10
- local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +12 -3
- local_deep_research/web_search_engines/search_engine_base.py +83 -35
- local_deep_research/web_search_engines/search_engine_factory.py +25 -8
- local_deep_research/web_search_engines/search_engines_config.py +9 -3
- {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/METADATA +7 -1
- local_deep_research-0.5.2.dist-info/RECORD +265 -0
- local_deep_research-0.4.4.dist-info/RECORD +0 -177
- {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/WHEEL +0 -0
- {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/entry_points.txt +0 -0
- {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -15,33 +15,26 @@ from flask import (
|
|
15
15
|
)
|
16
16
|
from loguru import logger
|
17
17
|
|
18
|
-
from ..models.database import
|
19
|
-
|
18
|
+
from ..models.database import (
|
19
|
+
calculate_duration,
|
20
|
+
get_db_connection,
|
21
|
+
)
|
22
|
+
from ..services.research_service import (
|
23
|
+
run_research_process,
|
24
|
+
start_research_process,
|
25
|
+
)
|
20
26
|
from ..utils.templates import render_template_with_defaults
|
27
|
+
from .globals import active_research, termination_flags
|
28
|
+
from ..database.models import ResearchHistory, ResearchLog
|
29
|
+
from ...utilities.db_utils import get_db_session
|
21
30
|
|
22
31
|
# Create a Blueprint for the research application
|
23
32
|
research_bp = Blueprint("research", __name__, url_prefix="/research")
|
24
33
|
|
25
|
-
# Active research processes and socket subscriptions
|
26
|
-
active_research = {}
|
27
|
-
socket_subscriptions = {}
|
28
|
-
|
29
|
-
# Add termination flags dictionary
|
30
|
-
termination_flags = {}
|
31
|
-
|
32
34
|
# Output directory for research results
|
33
35
|
OUTPUT_DIR = "research_outputs"
|
34
36
|
|
35
37
|
|
36
|
-
# Return reference to globals for other modules to access
|
37
|
-
def get_globals():
|
38
|
-
return {
|
39
|
-
"active_research": active_research,
|
40
|
-
"socket_subscriptions": socket_subscriptions,
|
41
|
-
"termination_flags": termination_flags,
|
42
|
-
}
|
43
|
-
|
44
|
-
|
45
38
|
# Route for index page - redirection
|
46
39
|
@research_bp.route("/")
|
47
40
|
def index():
|
@@ -141,12 +134,15 @@ def start_research():
|
|
141
134
|
iterations = data.get("iterations")
|
142
135
|
questions_per_iteration = data.get("questions_per_iteration")
|
143
136
|
|
137
|
+
# Add strategy parameter with default value
|
138
|
+
strategy = data.get("strategy", "source-based")
|
139
|
+
|
144
140
|
# Log the selections for troubleshooting
|
145
141
|
logger.info(
|
146
142
|
f"Starting research with provider: {model_provider}, model: {model}, search engine: {search_engine}"
|
147
143
|
)
|
148
144
|
logger.info(
|
149
|
-
f"Additional parameters: max_results={max_results}, time_period={time_period}, iterations={iterations}, questions={questions_per_iteration}"
|
145
|
+
f"Additional parameters: max_results={max_results}, time_period={time_period}, iterations={iterations}, questions={questions_per_iteration}, strategy={strategy}"
|
150
146
|
)
|
151
147
|
|
152
148
|
if not query:
|
@@ -176,7 +172,8 @@ def start_research():
|
|
176
172
|
conn = get_db_connection()
|
177
173
|
cursor = conn.cursor()
|
178
174
|
cursor.execute(
|
179
|
-
"SELECT status FROM research_history WHERE id = ?",
|
175
|
+
"SELECT status FROM research_history WHERE id = ?",
|
176
|
+
(research_id,),
|
180
177
|
)
|
181
178
|
result = cursor.fetchone()
|
182
179
|
conn.close()
|
@@ -228,22 +225,19 @@ def start_research():
|
|
228
225
|
"questions_per_iteration": questions_per_iteration,
|
229
226
|
}
|
230
227
|
|
231
|
-
|
232
|
-
|
233
|
-
(
|
234
|
-
query,
|
235
|
-
mode,
|
236
|
-
"in_progress",
|
237
|
-
created_at,
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
)
|
243
|
-
|
244
|
-
research_id = cursor.lastrowid
|
245
|
-
conn.commit()
|
246
|
-
conn.close()
|
228
|
+
db_session = get_db_session()
|
229
|
+
with db_session:
|
230
|
+
research = ResearchHistory(
|
231
|
+
query=query,
|
232
|
+
mode=mode,
|
233
|
+
status="in_progress",
|
234
|
+
created_at=created_at,
|
235
|
+
progress_log=[{"time": created_at, "progress": 0}],
|
236
|
+
research_meta=research_settings,
|
237
|
+
)
|
238
|
+
db_session.add(research)
|
239
|
+
db_session.commit()
|
240
|
+
research_id = research.id
|
247
241
|
|
248
242
|
# Start the research process with the selected parameters
|
249
243
|
research_thread = start_research_process(
|
@@ -261,6 +255,7 @@ def start_research():
|
|
261
255
|
time_period=time_period,
|
262
256
|
iterations=iterations,
|
263
257
|
questions_per_iteration=questions_per_iteration,
|
258
|
+
strategy=strategy,
|
264
259
|
)
|
265
260
|
|
266
261
|
# Store the thread reference in active_research
|
@@ -276,12 +271,16 @@ def terminate_research(research_id):
|
|
276
271
|
# Check if the research exists and is in progress
|
277
272
|
conn = get_db_connection()
|
278
273
|
cursor = conn.cursor()
|
279
|
-
cursor.execute(
|
274
|
+
cursor.execute(
|
275
|
+
"SELECT status FROM research_history WHERE id = ?", (research_id,)
|
276
|
+
)
|
280
277
|
result = cursor.fetchone()
|
281
278
|
|
282
279
|
if not result:
|
283
280
|
conn.close()
|
284
|
-
return jsonify(
|
281
|
+
return jsonify(
|
282
|
+
{"status": "error", "message": "Research not found"}
|
283
|
+
), 404
|
285
284
|
|
286
285
|
status = result[0]
|
287
286
|
|
@@ -289,7 +288,9 @@ def terminate_research(research_id):
|
|
289
288
|
if status != "in_progress":
|
290
289
|
conn.close()
|
291
290
|
return (
|
292
|
-
jsonify(
|
291
|
+
jsonify(
|
292
|
+
{"status": "error", "message": "Research is not in progress"}
|
293
|
+
),
|
293
294
|
400,
|
294
295
|
)
|
295
296
|
|
@@ -324,13 +325,7 @@ def terminate_research(research_id):
|
|
324
325
|
active_research[research_id]["log"].append(log_entry)
|
325
326
|
|
326
327
|
# Add to database log
|
327
|
-
|
328
|
-
research_id,
|
329
|
-
termination_message,
|
330
|
-
log_type="milestone",
|
331
|
-
progress=current_progress,
|
332
|
-
metadata={"phase": "termination"},
|
333
|
-
)
|
328
|
+
logger.log("milestone", "Research ended: {}", termination_message)
|
334
329
|
|
335
330
|
# Update the log in the database (old way for backward compatibility)
|
336
331
|
cursor.execute(
|
@@ -370,7 +365,9 @@ def terminate_research(research_id):
|
|
370
365
|
except Exception:
|
371
366
|
logger.exception("Socket emit error (non-critical)")
|
372
367
|
|
373
|
-
return jsonify(
|
368
|
+
return jsonify(
|
369
|
+
{"status": "success", "message": "Research termination requested"}
|
370
|
+
)
|
374
371
|
|
375
372
|
|
376
373
|
@research_bp.route("/api/delete/<int:research_id>", methods=["DELETE"])
|
@@ -381,13 +378,16 @@ def delete_research(research_id):
|
|
381
378
|
|
382
379
|
# First check if the research exists and is not in progress
|
383
380
|
cursor.execute(
|
384
|
-
"SELECT status, report_path FROM research_history WHERE id = ?",
|
381
|
+
"SELECT status, report_path FROM research_history WHERE id = ?",
|
382
|
+
(research_id,),
|
385
383
|
)
|
386
384
|
result = cursor.fetchone()
|
387
385
|
|
388
386
|
if not result:
|
389
387
|
conn.close()
|
390
|
-
return jsonify(
|
388
|
+
return jsonify(
|
389
|
+
{"status": "error", "message": "Research not found"}
|
390
|
+
), 404
|
391
391
|
|
392
392
|
status, report_path = result
|
393
393
|
|
@@ -477,7 +477,9 @@ def open_file_location():
|
|
477
477
|
|
478
478
|
# Check if path exists
|
479
479
|
if not os.path.exists(file_path):
|
480
|
-
return jsonify(
|
480
|
+
return jsonify(
|
481
|
+
{"status": "error", "message": "Path does not exist"}
|
482
|
+
), 404
|
481
483
|
|
482
484
|
try:
|
483
485
|
if platform.system() == "Windows":
|
@@ -506,13 +508,17 @@ def save_raw_config():
|
|
506
508
|
|
507
509
|
if not raw_config:
|
508
510
|
return (
|
509
|
-
jsonify(
|
511
|
+
jsonify(
|
512
|
+
{"success": False, "error": "Raw configuration is required"}
|
513
|
+
),
|
510
514
|
400,
|
511
515
|
)
|
512
516
|
|
513
517
|
try:
|
514
518
|
# Get the config file path
|
515
|
-
config_dir = os.path.join(
|
519
|
+
config_dir = os.path.join(
|
520
|
+
os.path.expanduser("~"), ".local_deep_research"
|
521
|
+
)
|
516
522
|
os.makedirs(config_dir, exist_ok=True)
|
517
523
|
config_path = os.path.join(config_dir, "config.toml")
|
518
524
|
|
@@ -577,7 +583,9 @@ def get_history():
|
|
577
583
|
duration_seconds = None
|
578
584
|
if completed_at and created_at:
|
579
585
|
try:
|
580
|
-
duration_seconds = calculate_duration(
|
586
|
+
duration_seconds = calculate_duration(
|
587
|
+
created_at, completed_at
|
588
|
+
)
|
581
589
|
except Exception:
|
582
590
|
logger.exception("Error calculating duration")
|
583
591
|
|
@@ -606,6 +614,135 @@ def get_history():
|
|
606
614
|
return jsonify({"status": "error", "message": str(e)}), 500
|
607
615
|
|
608
616
|
|
617
|
+
@research_bp.route("/api/research/<int:research_id>")
|
618
|
+
def get_research_details(research_id):
|
619
|
+
"""Get full details of a research using ORM"""
|
620
|
+
try:
|
621
|
+
db_session = get_db_session()
|
622
|
+
research = (
|
623
|
+
db_session.query(ResearchHistory)
|
624
|
+
.filter(ResearchHistory.id == research_id)
|
625
|
+
.first()
|
626
|
+
)
|
627
|
+
|
628
|
+
if not research:
|
629
|
+
return jsonify({"error": "Research not found"}), 404
|
630
|
+
|
631
|
+
return jsonify(
|
632
|
+
{
|
633
|
+
"id": research.id,
|
634
|
+
"query": research.query,
|
635
|
+
"status": research.status,
|
636
|
+
"progress": research.progress,
|
637
|
+
"progress_percentage": research.progress or 0,
|
638
|
+
"mode": research.mode,
|
639
|
+
"created_at": research.created_at,
|
640
|
+
"completed_at": research.completed_at,
|
641
|
+
"report_path": research.report_path,
|
642
|
+
"metadata": research.research_meta,
|
643
|
+
}
|
644
|
+
)
|
645
|
+
except Exception as e:
|
646
|
+
logger.exception(f"Error getting research details: {str(e)}")
|
647
|
+
return jsonify({"error": "An internal error has occurred"}), 500
|
648
|
+
|
649
|
+
|
650
|
+
@research_bp.route("/api/research/<int:research_id>/logs")
|
651
|
+
def get_research_logs(research_id):
|
652
|
+
"""Get logs for a specific research"""
|
653
|
+
try:
|
654
|
+
# First check if the research exists
|
655
|
+
db_session = get_db_session()
|
656
|
+
with db_session:
|
657
|
+
research = (
|
658
|
+
db_session.query(ResearchHistory)
|
659
|
+
.filter_by(id=research_id)
|
660
|
+
.first()
|
661
|
+
)
|
662
|
+
if not research:
|
663
|
+
return jsonify({"error": "Research not found"}), 404
|
664
|
+
|
665
|
+
# Get logs from research_logs table
|
666
|
+
log_results = (
|
667
|
+
db_session.query(ResearchLog)
|
668
|
+
.filter_by(research_id=research_id)
|
669
|
+
.order_by(ResearchLog.timestamp)
|
670
|
+
.all()
|
671
|
+
)
|
672
|
+
|
673
|
+
logs = []
|
674
|
+
for row in log_results:
|
675
|
+
logs.append(
|
676
|
+
{
|
677
|
+
"id": row.id,
|
678
|
+
"message": row.message,
|
679
|
+
"timestamp": row.timestamp,
|
680
|
+
"log_type": row.level,
|
681
|
+
}
|
682
|
+
)
|
683
|
+
|
684
|
+
return jsonify(logs)
|
685
|
+
|
686
|
+
except Exception as e:
|
687
|
+
logger.exception(f"Error getting research logs: {str(e)}")
|
688
|
+
return jsonify({"error": "An internal error has occurred"}), 500
|
689
|
+
|
690
|
+
|
691
|
+
@research_bp.route("/api/report/<int:research_id>")
|
692
|
+
def get_research_report(research_id):
|
693
|
+
"""Get the research report content"""
|
694
|
+
session = get_db_session()
|
695
|
+
try:
|
696
|
+
# Query using ORM
|
697
|
+
research = (
|
698
|
+
session.query(ResearchHistory).filter_by(id=research_id).first()
|
699
|
+
)
|
700
|
+
|
701
|
+
if research is None:
|
702
|
+
return jsonify({"error": "Research not found"}), 404
|
703
|
+
|
704
|
+
# Parse metadata if it exists
|
705
|
+
metadata = research.research_meta
|
706
|
+
# Check if report file exists
|
707
|
+
if not research.report_path or not os.path.exists(research.report_path):
|
708
|
+
return jsonify({"error": "Report file not found"}), 404
|
709
|
+
|
710
|
+
# Read the report content
|
711
|
+
try:
|
712
|
+
with open(research.report_path, "r", encoding="utf-8") as f:
|
713
|
+
content = f.read()
|
714
|
+
except Exception as e:
|
715
|
+
logger.error(
|
716
|
+
f"Error reading report file {research.report_path}: {e}"
|
717
|
+
)
|
718
|
+
return jsonify({"error": "Error reading report file"}), 500
|
719
|
+
|
720
|
+
# Return the report data
|
721
|
+
return jsonify(
|
722
|
+
{
|
723
|
+
"content": content,
|
724
|
+
"metadata": {
|
725
|
+
"query": research.query,
|
726
|
+
"mode": research.mode if research.mode else None,
|
727
|
+
"created_at": research.created_at
|
728
|
+
if research.created_at
|
729
|
+
else None,
|
730
|
+
"completed_at": research.completed_at
|
731
|
+
if research.completed_at
|
732
|
+
else None,
|
733
|
+
"report_path": research.report_path,
|
734
|
+
**metadata,
|
735
|
+
},
|
736
|
+
}
|
737
|
+
)
|
738
|
+
|
739
|
+
except Exception as e:
|
740
|
+
logger.exception(f"Error getting research report: {str(e)}")
|
741
|
+
return jsonify({"error": "An internal error has occurred"}), 500
|
742
|
+
finally:
|
743
|
+
session.close()
|
744
|
+
|
745
|
+
|
609
746
|
@research_bp.route("/api/research/<research_id>/status")
|
610
747
|
def get_research_status(research_id):
|
611
748
|
"""Get the status of a research process"""
|
@@ -648,7 +785,8 @@ def get_research_status(research_id):
|
|
648
785
|
"suggestion": "Try again later or use a smaller query scope.",
|
649
786
|
}
|
650
787
|
elif (
|
651
|
-
"token limit" in error_msg.lower()
|
788
|
+
"token limit" in error_msg.lower()
|
789
|
+
or "context length" in error_msg.lower()
|
652
790
|
):
|
653
791
|
error_type = "token_limit"
|
654
792
|
error_info = {
|