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
@@ -0,0 +1,115 @@
|
|
1
|
+
"""SQLAlchemy models for metrics."""
|
2
|
+
|
3
|
+
from sqlalchemy import (
|
4
|
+
Column,
|
5
|
+
DateTime,
|
6
|
+
Integer,
|
7
|
+
String,
|
8
|
+
Text,
|
9
|
+
UniqueConstraint,
|
10
|
+
func,
|
11
|
+
)
|
12
|
+
from sqlalchemy.ext.declarative import declarative_base
|
13
|
+
|
14
|
+
Base = declarative_base()
|
15
|
+
|
16
|
+
|
17
|
+
class TokenUsage(Base):
|
18
|
+
"""Model for tracking individual token usage events."""
|
19
|
+
|
20
|
+
__tablename__ = "token_usage"
|
21
|
+
|
22
|
+
id = Column(Integer, primary_key=True)
|
23
|
+
research_id = Column(
|
24
|
+
Integer
|
25
|
+
) # Removed foreign key constraint to fix token tracking
|
26
|
+
model_name = Column(String)
|
27
|
+
provider = Column(
|
28
|
+
String
|
29
|
+
) # Added provider column for accurate cost tracking
|
30
|
+
prompt_tokens = Column(Integer)
|
31
|
+
completion_tokens = Column(Integer)
|
32
|
+
total_tokens = Column(Integer)
|
33
|
+
|
34
|
+
# Phase 1 Enhancement: Research context
|
35
|
+
research_query = Column(Text)
|
36
|
+
research_mode = Column(String) # 'quick' or 'detailed'
|
37
|
+
research_phase = Column(String) # 'init', 'iteration_1', etc.
|
38
|
+
search_iteration = Column(Integer)
|
39
|
+
|
40
|
+
# Phase 1 Enhancement: Performance metrics
|
41
|
+
response_time_ms = Column(Integer)
|
42
|
+
success_status = Column(
|
43
|
+
String, default="success"
|
44
|
+
) # 'success', 'error', 'timeout'
|
45
|
+
error_type = Column(String)
|
46
|
+
|
47
|
+
# Phase 1 Enhancement: Search engine context
|
48
|
+
search_engines_planned = Column(Text) # JSON array as text
|
49
|
+
search_engine_selected = Column(String)
|
50
|
+
|
51
|
+
# Call stack tracking
|
52
|
+
calling_file = Column(String) # File that made the LLM call
|
53
|
+
calling_function = Column(String) # Function that made the LLM call
|
54
|
+
call_stack = Column(Text) # Full call stack as JSON
|
55
|
+
|
56
|
+
timestamp = Column(DateTime, server_default=func.now())
|
57
|
+
|
58
|
+
|
59
|
+
class ModelUsage(Base):
|
60
|
+
"""Model for aggregated token usage by model and research."""
|
61
|
+
|
62
|
+
__tablename__ = "model_usage"
|
63
|
+
__table_args__ = (UniqueConstraint("research_id", "model_name"),)
|
64
|
+
|
65
|
+
id = Column(Integer, primary_key=True)
|
66
|
+
research_id = Column(
|
67
|
+
Integer
|
68
|
+
) # Removed foreign key constraint to fix token tracking
|
69
|
+
model_name = Column(String)
|
70
|
+
provider = Column(String)
|
71
|
+
prompt_tokens = Column(Integer, default=0)
|
72
|
+
completion_tokens = Column(Integer, default=0)
|
73
|
+
total_tokens = Column(Integer, default=0)
|
74
|
+
calls = Column(Integer, default=0)
|
75
|
+
timestamp = Column(DateTime, server_default=func.now())
|
76
|
+
|
77
|
+
|
78
|
+
class ResearchRating(Base):
|
79
|
+
"""Model for storing user ratings of research sessions."""
|
80
|
+
|
81
|
+
__tablename__ = "research_ratings"
|
82
|
+
|
83
|
+
id = Column(Integer, primary_key=True)
|
84
|
+
research_id = Column(Integer, unique=True) # References research session ID
|
85
|
+
rating = Column(Integer) # 1-5 star rating
|
86
|
+
rated_at = Column(DateTime, server_default=func.now())
|
87
|
+
updated_at = Column(
|
88
|
+
DateTime, server_default=func.now(), onupdate=func.now()
|
89
|
+
)
|
90
|
+
|
91
|
+
|
92
|
+
class SearchCall(Base):
|
93
|
+
"""Model for individual search engine calls."""
|
94
|
+
|
95
|
+
__tablename__ = "search_calls"
|
96
|
+
|
97
|
+
id = Column(Integer, primary_key=True)
|
98
|
+
research_id = Column(Integer)
|
99
|
+
research_query = Column(Text)
|
100
|
+
research_mode = Column(String)
|
101
|
+
research_phase = Column(String)
|
102
|
+
search_iteration = Column(Integer)
|
103
|
+
|
104
|
+
# Search details
|
105
|
+
search_engine = Column(String)
|
106
|
+
query = Column(Text)
|
107
|
+
results_count = Column(Integer)
|
108
|
+
response_time_ms = Column(Integer)
|
109
|
+
|
110
|
+
# Status tracking
|
111
|
+
success_status = Column(String, default="success")
|
112
|
+
error_type = Column(String)
|
113
|
+
error_message = Column(Text)
|
114
|
+
|
115
|
+
timestamp = Column(DateTime, server_default=func.now())
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Migration: Add provider column to TokenUsage table
|
3
|
+
|
4
|
+
This migration adds the provider column to the TokenUsage table to enable
|
5
|
+
accurate cost tracking based on both model and provider information.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import logging
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from sqlalchemy import text
|
12
|
+
|
13
|
+
from .database import get_metrics_db
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def add_provider_column_to_token_usage():
|
19
|
+
"""Add provider column to TokenUsage table."""
|
20
|
+
try:
|
21
|
+
db = get_metrics_db()
|
22
|
+
|
23
|
+
with db.get_session() as session:
|
24
|
+
# Check if provider column already exists
|
25
|
+
result = session.execute(
|
26
|
+
text(
|
27
|
+
"""
|
28
|
+
SELECT COUNT(*) as count
|
29
|
+
FROM pragma_table_info('token_usage')
|
30
|
+
WHERE name='provider'
|
31
|
+
"""
|
32
|
+
)
|
33
|
+
)
|
34
|
+
|
35
|
+
provider_exists = result.fetchone()[0] > 0
|
36
|
+
|
37
|
+
if provider_exists:
|
38
|
+
logger.info(
|
39
|
+
"Provider column already exists in token_usage table"
|
40
|
+
)
|
41
|
+
return True
|
42
|
+
|
43
|
+
logger.info("Adding provider column to token_usage table...")
|
44
|
+
|
45
|
+
# Add the provider column
|
46
|
+
session.execute(
|
47
|
+
text(
|
48
|
+
"""
|
49
|
+
ALTER TABLE token_usage
|
50
|
+
ADD COLUMN provider VARCHAR
|
51
|
+
"""
|
52
|
+
)
|
53
|
+
)
|
54
|
+
|
55
|
+
# Try to populate provider info for existing records based on model name patterns
|
56
|
+
logger.info("Populating provider info for existing records...")
|
57
|
+
|
58
|
+
# Update known local model providers
|
59
|
+
local_model_updates = [
|
60
|
+
(
|
61
|
+
"ollama",
|
62
|
+
[
|
63
|
+
"ollama",
|
64
|
+
"llama",
|
65
|
+
"mistral",
|
66
|
+
"gemma",
|
67
|
+
"qwen",
|
68
|
+
"codellama",
|
69
|
+
"vicuna",
|
70
|
+
"alpaca",
|
71
|
+
],
|
72
|
+
),
|
73
|
+
("openai", ["gpt-", "davinci", "curie", "babbage", "ada"]),
|
74
|
+
("anthropic", ["claude"]),
|
75
|
+
("google", ["gemini", "bard"]),
|
76
|
+
]
|
77
|
+
|
78
|
+
for provider, model_patterns in local_model_updates:
|
79
|
+
for pattern in model_patterns:
|
80
|
+
session.execute(
|
81
|
+
text(
|
82
|
+
"""
|
83
|
+
UPDATE token_usage
|
84
|
+
SET provider = :provider
|
85
|
+
WHERE provider IS NULL
|
86
|
+
AND (LOWER(model_name) LIKE :pattern OR LOWER(model_name) LIKE :pattern_percent)
|
87
|
+
"""
|
88
|
+
),
|
89
|
+
{
|
90
|
+
"provider": provider,
|
91
|
+
"pattern": pattern,
|
92
|
+
"pattern_percent": f"%{pattern}%",
|
93
|
+
},
|
94
|
+
)
|
95
|
+
|
96
|
+
# Set any remaining NULL providers to 'unknown'
|
97
|
+
session.execute(
|
98
|
+
text(
|
99
|
+
"""
|
100
|
+
UPDATE token_usage
|
101
|
+
SET provider = 'unknown'
|
102
|
+
WHERE provider IS NULL
|
103
|
+
"""
|
104
|
+
)
|
105
|
+
)
|
106
|
+
|
107
|
+
session.commit()
|
108
|
+
logger.info(
|
109
|
+
"Successfully added provider column and populated existing data"
|
110
|
+
)
|
111
|
+
return True
|
112
|
+
|
113
|
+
except Exception as e:
|
114
|
+
logger.error(f"Error adding provider column to token_usage: {e}")
|
115
|
+
return False
|
116
|
+
|
117
|
+
|
118
|
+
def run_migration():
|
119
|
+
"""Run the provider column migration."""
|
120
|
+
logger.info("Starting migration: Add provider column to TokenUsage")
|
121
|
+
|
122
|
+
success = add_provider_column_to_token_usage()
|
123
|
+
|
124
|
+
if success:
|
125
|
+
logger.info("Migration completed successfully")
|
126
|
+
else:
|
127
|
+
logger.error("Migration failed")
|
128
|
+
|
129
|
+
return success
|
130
|
+
|
131
|
+
|
132
|
+
if __name__ == "__main__":
|
133
|
+
# Allow running migration directly
|
134
|
+
import sys
|
135
|
+
|
136
|
+
# Add the project root to the path
|
137
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
138
|
+
sys.path.insert(0, str(project_root))
|
139
|
+
|
140
|
+
logging.basicConfig(level=logging.INFO)
|
141
|
+
success = run_migration()
|
142
|
+
|
143
|
+
if success:
|
144
|
+
print("✅ Migration completed successfully")
|
145
|
+
sys.exit(0)
|
146
|
+
else:
|
147
|
+
print("❌ Migration failed")
|
148
|
+
sys.exit(1)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Database migration script to add call stack tracking columns to token_usage table.
|
4
|
+
This adds the Phase 1 call stack tracking functionality.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import sqlite3
|
8
|
+
import sys
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from loguru import logger
|
12
|
+
|
13
|
+
|
14
|
+
def migrate_call_stack_tracking(db_path: str):
|
15
|
+
"""Add call stack tracking columns to the token_usage table.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
db_path: Path to the SQLite database file
|
19
|
+
"""
|
20
|
+
try:
|
21
|
+
conn = sqlite3.connect(db_path)
|
22
|
+
cursor = conn.cursor()
|
23
|
+
|
24
|
+
# Check if columns already exist
|
25
|
+
cursor.execute("PRAGMA table_info(token_usage)")
|
26
|
+
columns = [row[1] for row in cursor.fetchall()]
|
27
|
+
|
28
|
+
# Add call stack tracking columns if they don't exist
|
29
|
+
new_columns = [
|
30
|
+
("calling_file", "TEXT"),
|
31
|
+
("calling_function", "TEXT"),
|
32
|
+
("call_stack", "TEXT"),
|
33
|
+
]
|
34
|
+
|
35
|
+
for column_name, column_type in new_columns:
|
36
|
+
if column_name not in columns:
|
37
|
+
logger.info(f"Adding column {column_name} to token_usage table")
|
38
|
+
cursor.execute(
|
39
|
+
f"ALTER TABLE token_usage ADD COLUMN {column_name} {column_type}"
|
40
|
+
)
|
41
|
+
else:
|
42
|
+
logger.info(
|
43
|
+
f"Column {column_name} already exists in token_usage table"
|
44
|
+
)
|
45
|
+
|
46
|
+
conn.commit()
|
47
|
+
logger.success(
|
48
|
+
"Call stack tracking columns migration completed successfully"
|
49
|
+
)
|
50
|
+
|
51
|
+
except sqlite3.Error as e:
|
52
|
+
logger.error(f"Database error during call stack migration: {e}")
|
53
|
+
raise
|
54
|
+
except Exception as e:
|
55
|
+
logger.error(f"Unexpected error during call stack migration: {e}")
|
56
|
+
raise
|
57
|
+
finally:
|
58
|
+
if conn:
|
59
|
+
conn.close()
|
60
|
+
|
61
|
+
|
62
|
+
def find_database_file():
|
63
|
+
"""Find the metrics database file."""
|
64
|
+
# Common locations for the database
|
65
|
+
possible_paths = [
|
66
|
+
"data/metrics.db",
|
67
|
+
"../data/metrics.db",
|
68
|
+
"../../data/metrics.db",
|
69
|
+
]
|
70
|
+
|
71
|
+
for path in possible_paths:
|
72
|
+
db_path = Path(path)
|
73
|
+
if db_path.exists():
|
74
|
+
return str(db_path.absolute())
|
75
|
+
|
76
|
+
return None
|
77
|
+
|
78
|
+
|
79
|
+
if __name__ == "__main__":
|
80
|
+
logger.info("Starting call stack tracking migration...")
|
81
|
+
|
82
|
+
# Check if database path provided as argument
|
83
|
+
if len(sys.argv) > 1:
|
84
|
+
db_path = sys.argv[1]
|
85
|
+
else:
|
86
|
+
db_path = find_database_file()
|
87
|
+
|
88
|
+
if not db_path:
|
89
|
+
logger.error("Could not find metrics database file.")
|
90
|
+
logger.info("Please provide the database path as an argument:")
|
91
|
+
logger.info("python migrate_call_stack_tracking.py /path/to/metrics.db")
|
92
|
+
sys.exit(1)
|
93
|
+
|
94
|
+
if not Path(db_path).exists():
|
95
|
+
logger.error(f"Database file does not exist: {db_path}")
|
96
|
+
sys.exit(1)
|
97
|
+
|
98
|
+
logger.info(f"Using database: {db_path}")
|
99
|
+
|
100
|
+
try:
|
101
|
+
migrate_call_stack_tracking(db_path)
|
102
|
+
logger.success("Call stack tracking migration completed!")
|
103
|
+
except Exception as e:
|
104
|
+
logger.error(f"Migration failed: {e}")
|
105
|
+
sys.exit(1)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
"""Migration script to add Phase 1 enhanced token tracking fields."""
|
2
|
+
|
3
|
+
import sqlite3
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
from loguru import logger
|
7
|
+
|
8
|
+
from ..utilities.db_utils import DB_PATH
|
9
|
+
|
10
|
+
|
11
|
+
def migrate_enhanced_tracking():
|
12
|
+
"""Add Phase 1 enhanced tracking columns to existing token_usage table."""
|
13
|
+
|
14
|
+
if not Path(DB_PATH).exists():
|
15
|
+
logger.info("Database doesn't exist yet, skipping migration")
|
16
|
+
return
|
17
|
+
|
18
|
+
try:
|
19
|
+
conn = sqlite3.connect(DB_PATH)
|
20
|
+
cursor = conn.cursor()
|
21
|
+
|
22
|
+
# Check if token_usage table exists
|
23
|
+
cursor.execute(
|
24
|
+
"""
|
25
|
+
SELECT name FROM sqlite_master
|
26
|
+
WHERE type='table' AND name='token_usage'
|
27
|
+
"""
|
28
|
+
)
|
29
|
+
|
30
|
+
if not cursor.fetchone():
|
31
|
+
logger.info(
|
32
|
+
"token_usage table doesn't exist yet, skipping migration"
|
33
|
+
)
|
34
|
+
conn.close()
|
35
|
+
return
|
36
|
+
|
37
|
+
# Check if enhanced columns already exist
|
38
|
+
cursor.execute("PRAGMA table_info(token_usage)")
|
39
|
+
columns = [column[1] for column in cursor.fetchall()]
|
40
|
+
|
41
|
+
# Define new columns to add
|
42
|
+
new_columns = [
|
43
|
+
("research_query", "TEXT"),
|
44
|
+
("research_mode", "TEXT"),
|
45
|
+
("research_phase", "TEXT"),
|
46
|
+
("search_iteration", "INTEGER"),
|
47
|
+
("response_time_ms", "INTEGER"),
|
48
|
+
("success_status", "TEXT DEFAULT 'success'"),
|
49
|
+
("error_type", "TEXT"),
|
50
|
+
("search_engines_planned", "TEXT"),
|
51
|
+
("search_engine_selected", "TEXT"),
|
52
|
+
]
|
53
|
+
|
54
|
+
# Add missing columns
|
55
|
+
for column_name, column_type in new_columns:
|
56
|
+
if column_name not in columns:
|
57
|
+
logger.info(f"Adding column {column_name} to token_usage table")
|
58
|
+
cursor.execute(
|
59
|
+
f"ALTER TABLE token_usage ADD COLUMN {column_name} {column_type}"
|
60
|
+
)
|
61
|
+
|
62
|
+
conn.commit()
|
63
|
+
conn.close()
|
64
|
+
|
65
|
+
logger.info("Enhanced token tracking migration completed successfully")
|
66
|
+
|
67
|
+
except Exception as e:
|
68
|
+
logger.exception(f"Error during enhanced token tracking migration: {e}")
|
69
|
+
if "conn" in locals():
|
70
|
+
conn.close()
|
71
|
+
raise
|
72
|
+
|
73
|
+
|
74
|
+
if __name__ == "__main__":
|
75
|
+
migrate_enhanced_tracking()
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""Migration script to add research ratings table."""
|
3
|
+
|
4
|
+
import sys
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
# Add the project root to Python path
|
8
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
9
|
+
sys.path.insert(0, str(project_root))
|
10
|
+
|
11
|
+
# Import after path modification
|
12
|
+
from local_deep_research.metrics.database import MetricsDatabase # noqa: E402
|
13
|
+
from local_deep_research.metrics.db_models import ResearchRating # noqa: E402
|
14
|
+
|
15
|
+
|
16
|
+
def main():
|
17
|
+
"""Run the migration to add research ratings table."""
|
18
|
+
print("Creating research ratings table...")
|
19
|
+
|
20
|
+
# Initialize database
|
21
|
+
db = MetricsDatabase()
|
22
|
+
|
23
|
+
# Create the research_ratings table
|
24
|
+
ResearchRating.__table__.create(db.engine, checkfirst=True)
|
25
|
+
|
26
|
+
print("✅ Research ratings table created successfully!")
|
27
|
+
print("Users can now rate their research sessions on a 1-5 star scale.")
|
28
|
+
|
29
|
+
|
30
|
+
if __name__ == "__main__":
|
31
|
+
main()
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""SQLAlchemy models for metrics."""
|
2
|
+
|
3
|
+
from sqlalchemy import Column, DateTime, Integer, String, Text, UniqueConstraint
|
4
|
+
from sqlalchemy.ext.declarative import declarative_base
|
5
|
+
from sqlalchemy.sql import func
|
6
|
+
|
7
|
+
Base = declarative_base()
|
8
|
+
|
9
|
+
|
10
|
+
class TokenUsage(Base):
|
11
|
+
"""Model for tracking individual token usage events."""
|
12
|
+
|
13
|
+
__tablename__ = "token_usage"
|
14
|
+
|
15
|
+
id = Column(Integer, primary_key=True)
|
16
|
+
research_id = Column(Integer, index=True) # No foreign key for now
|
17
|
+
model_name = Column(String)
|
18
|
+
prompt_tokens = Column(Integer)
|
19
|
+
completion_tokens = Column(Integer)
|
20
|
+
total_tokens = Column(Integer)
|
21
|
+
|
22
|
+
# Phase 1 Enhancement: Research context
|
23
|
+
research_query = Column(Text)
|
24
|
+
research_mode = Column(String) # 'quick' or 'detailed'
|
25
|
+
research_phase = Column(String) # 'init', 'iteration_1', etc.
|
26
|
+
search_iteration = Column(Integer)
|
27
|
+
|
28
|
+
# Phase 1 Enhancement: Performance metrics
|
29
|
+
response_time_ms = Column(Integer)
|
30
|
+
success_status = Column(
|
31
|
+
String, default="success"
|
32
|
+
) # 'success', 'error', 'timeout'
|
33
|
+
error_type = Column(String)
|
34
|
+
|
35
|
+
# Phase 1 Enhancement: Search engine context
|
36
|
+
search_engines_planned = Column(Text) # JSON array as text
|
37
|
+
search_engine_selected = Column(String)
|
38
|
+
|
39
|
+
# Call stack tracking
|
40
|
+
calling_file = Column(String) # File that made the LLM call
|
41
|
+
calling_function = Column(String) # Function that made the LLM call
|
42
|
+
call_stack = Column(Text) # Full call stack as JSON
|
43
|
+
|
44
|
+
timestamp = Column(DateTime, server_default=func.now())
|
45
|
+
|
46
|
+
|
47
|
+
class ModelUsage(Base):
|
48
|
+
"""Model for aggregated token usage by model and research."""
|
49
|
+
|
50
|
+
__tablename__ = "model_usage"
|
51
|
+
__table_args__ = (UniqueConstraint("research_id", "model_name"),)
|
52
|
+
|
53
|
+
id = Column(Integer, primary_key=True)
|
54
|
+
research_id = Column(Integer, index=True) # No foreign key for now
|
55
|
+
model_name = Column(String)
|
56
|
+
provider = Column(String)
|
57
|
+
prompt_tokens = Column(Integer, default=0)
|
58
|
+
completion_tokens = Column(Integer, default=0)
|
59
|
+
total_tokens = Column(Integer, default=0)
|
60
|
+
calls = Column(Integer, default=0)
|
61
|
+
timestamp = Column(DateTime, server_default=func.now())
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"""
|
2
|
+
LLM Pricing API Module
|
3
|
+
|
4
|
+
Provides real-time pricing data for LLM models from various providers.
|
5
|
+
Includes caching and cost calculation utilities.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .cost_calculator import CostCalculator
|
9
|
+
from .pricing_cache import PricingCache
|
10
|
+
from .pricing_fetcher import PricingFetcher
|
11
|
+
|
12
|
+
__all__ = ["PricingFetcher", "PricingCache", "CostCalculator"]
|