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,1245 @@
|
|
1
|
+
{% extends "base.html" %}
|
2
|
+
|
3
|
+
{% set active_page = 'metrics' %}
|
4
|
+
|
5
|
+
{% block title %}Cost Analytics - Deep Research System{% endblock %}
|
6
|
+
|
7
|
+
{% block extra_head %}
|
8
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
9
|
+
<style>
|
10
|
+
.cost-analytics-container {
|
11
|
+
max-width: 1400px;
|
12
|
+
margin: 0 auto;
|
13
|
+
padding: 1rem;
|
14
|
+
}
|
15
|
+
|
16
|
+
.cost-header {
|
17
|
+
display: flex;
|
18
|
+
align-items: center;
|
19
|
+
justify-content: space-between;
|
20
|
+
margin-bottom: 2rem;
|
21
|
+
flex-wrap: wrap;
|
22
|
+
gap: 1rem;
|
23
|
+
}
|
24
|
+
|
25
|
+
.cost-title {
|
26
|
+
display: flex;
|
27
|
+
align-items: center;
|
28
|
+
gap: 1rem;
|
29
|
+
}
|
30
|
+
|
31
|
+
.cost-title h1 {
|
32
|
+
margin: 0;
|
33
|
+
background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
|
34
|
+
-webkit-background-clip: text;
|
35
|
+
-webkit-text-fill-color: transparent;
|
36
|
+
background-clip: text;
|
37
|
+
}
|
38
|
+
|
39
|
+
.back-button {
|
40
|
+
background: var(--bg-secondary);
|
41
|
+
color: var(--text-primary);
|
42
|
+
padding: 8px 16px;
|
43
|
+
border-radius: 6px;
|
44
|
+
text-decoration: none;
|
45
|
+
font-size: 0.875rem;
|
46
|
+
transition: all 0.2s;
|
47
|
+
border: 1px solid var(--border-color);
|
48
|
+
}
|
49
|
+
|
50
|
+
.back-button:hover {
|
51
|
+
background: var(--border-color);
|
52
|
+
transform: translateY(-1px);
|
53
|
+
}
|
54
|
+
|
55
|
+
.time-range-selector {
|
56
|
+
display: flex;
|
57
|
+
gap: 0.5rem;
|
58
|
+
align-items: center;
|
59
|
+
}
|
60
|
+
|
61
|
+
.time-range-btn {
|
62
|
+
padding: 6px 12px;
|
63
|
+
border: 1px solid var(--border-color);
|
64
|
+
background: var(--bg-secondary);
|
65
|
+
color: var(--text-secondary);
|
66
|
+
border-radius: 4px;
|
67
|
+
cursor: pointer;
|
68
|
+
font-size: 0.875rem;
|
69
|
+
transition: all 0.2s;
|
70
|
+
}
|
71
|
+
|
72
|
+
.time-range-btn:hover,
|
73
|
+
.time-range-btn.active {
|
74
|
+
background: var(--primary-color);
|
75
|
+
color: white;
|
76
|
+
border-color: var(--primary-color);
|
77
|
+
}
|
78
|
+
|
79
|
+
.cost-grid {
|
80
|
+
display: grid;
|
81
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
82
|
+
gap: 1.5rem;
|
83
|
+
margin-bottom: 2rem;
|
84
|
+
}
|
85
|
+
|
86
|
+
.cost-card {
|
87
|
+
background: var(--card-bg);
|
88
|
+
border: 1px solid var(--border-color);
|
89
|
+
border-radius: 0.5rem;
|
90
|
+
padding: 1.5rem;
|
91
|
+
transition: transform 0.2s;
|
92
|
+
}
|
93
|
+
|
94
|
+
.cost-card:hover {
|
95
|
+
transform: translateY(-2px);
|
96
|
+
}
|
97
|
+
|
98
|
+
.cost-card-header {
|
99
|
+
display: flex;
|
100
|
+
align-items: center;
|
101
|
+
gap: 0.75rem;
|
102
|
+
margin-bottom: 1rem;
|
103
|
+
}
|
104
|
+
|
105
|
+
.cost-icon {
|
106
|
+
width: 40px;
|
107
|
+
height: 40px;
|
108
|
+
display: flex;
|
109
|
+
align-items: center;
|
110
|
+
justify-content: center;
|
111
|
+
background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
|
112
|
+
color: white;
|
113
|
+
border-radius: 50%;
|
114
|
+
font-size: 1.25rem;
|
115
|
+
}
|
116
|
+
|
117
|
+
.cost-card-title {
|
118
|
+
font-size: 0.875rem;
|
119
|
+
color: var(--text-secondary);
|
120
|
+
text-transform: uppercase;
|
121
|
+
letter-spacing: 0.05em;
|
122
|
+
margin: 0;
|
123
|
+
}
|
124
|
+
|
125
|
+
.cost-value {
|
126
|
+
font-size: 2rem;
|
127
|
+
font-weight: bold;
|
128
|
+
color: var(--primary-color);
|
129
|
+
margin: 0.5rem 0;
|
130
|
+
}
|
131
|
+
|
132
|
+
.cost-subtitle {
|
133
|
+
font-size: 0.875rem;
|
134
|
+
color: var(--text-secondary);
|
135
|
+
margin: 0;
|
136
|
+
}
|
137
|
+
|
138
|
+
.chart-container {
|
139
|
+
background: var(--card-bg);
|
140
|
+
border: 1px solid var(--border-color);
|
141
|
+
border-radius: 0.5rem;
|
142
|
+
padding: 1.5rem;
|
143
|
+
margin-bottom: 2rem;
|
144
|
+
}
|
145
|
+
|
146
|
+
.chart-title {
|
147
|
+
display: flex;
|
148
|
+
align-items: center;
|
149
|
+
gap: 0.5rem;
|
150
|
+
margin-bottom: 1rem;
|
151
|
+
font-size: 1.25rem;
|
152
|
+
font-weight: 600;
|
153
|
+
color: var(--text-primary);
|
154
|
+
}
|
155
|
+
|
156
|
+
.chart-canvas {
|
157
|
+
position: relative;
|
158
|
+
height: 400px;
|
159
|
+
width: 100%;
|
160
|
+
}
|
161
|
+
|
162
|
+
.cost-table {
|
163
|
+
background: var(--card-bg);
|
164
|
+
border: 1px solid var(--border-color);
|
165
|
+
border-radius: 0.5rem;
|
166
|
+
overflow: hidden;
|
167
|
+
margin-bottom: 2rem;
|
168
|
+
}
|
169
|
+
|
170
|
+
.cost-table-header {
|
171
|
+
background: var(--bg-secondary);
|
172
|
+
padding: 1rem 1.5rem;
|
173
|
+
border-bottom: 1px solid var(--border-color);
|
174
|
+
}
|
175
|
+
|
176
|
+
.cost-table-title {
|
177
|
+
margin: 0;
|
178
|
+
font-size: 1.1rem;
|
179
|
+
font-weight: 600;
|
180
|
+
color: var(--text-primary);
|
181
|
+
display: flex;
|
182
|
+
align-items: center;
|
183
|
+
gap: 0.5rem;
|
184
|
+
}
|
185
|
+
|
186
|
+
.cost-table-content {
|
187
|
+
padding: 1rem;
|
188
|
+
}
|
189
|
+
|
190
|
+
.cost-item {
|
191
|
+
display: flex;
|
192
|
+
justify-content: space-between;
|
193
|
+
align-items: center;
|
194
|
+
padding: 0.75rem 0;
|
195
|
+
border-bottom: 1px solid var(--border-color);
|
196
|
+
}
|
197
|
+
|
198
|
+
.cost-item:last-child {
|
199
|
+
border-bottom: none;
|
200
|
+
}
|
201
|
+
|
202
|
+
.cost-item-info {
|
203
|
+
flex: 1;
|
204
|
+
}
|
205
|
+
|
206
|
+
.cost-item-name {
|
207
|
+
font-weight: 500;
|
208
|
+
color: var(--text-primary);
|
209
|
+
margin-bottom: 0.25rem;
|
210
|
+
}
|
211
|
+
|
212
|
+
.cost-item-details {
|
213
|
+
font-size: 0.875rem;
|
214
|
+
color: var(--text-secondary);
|
215
|
+
}
|
216
|
+
|
217
|
+
.cost-item-value {
|
218
|
+
font-weight: 600;
|
219
|
+
color: var(--primary-color);
|
220
|
+
font-size: 1.1rem;
|
221
|
+
}
|
222
|
+
|
223
|
+
.cost-optimization {
|
224
|
+
background: linear-gradient(135deg, #e8f5e8 0%, #f1f8f1 100%);
|
225
|
+
border: 1px solid #4CAF50;
|
226
|
+
border-radius: 0.5rem;
|
227
|
+
padding: 1.5rem;
|
228
|
+
margin-bottom: 2rem;
|
229
|
+
}
|
230
|
+
|
231
|
+
.cost-optimization h3 {
|
232
|
+
color: #2e7d32;
|
233
|
+
margin: 0 0 1rem 0;
|
234
|
+
display: flex;
|
235
|
+
align-items: center;
|
236
|
+
gap: 0.5rem;
|
237
|
+
}
|
238
|
+
|
239
|
+
.cost-optimization ul {
|
240
|
+
list-style: none;
|
241
|
+
padding: 0;
|
242
|
+
margin: 0;
|
243
|
+
}
|
244
|
+
|
245
|
+
.cost-optimization li {
|
246
|
+
margin-bottom: 0.75rem;
|
247
|
+
padding-left: 1.5rem;
|
248
|
+
position: relative;
|
249
|
+
color: #2e7d32;
|
250
|
+
}
|
251
|
+
|
252
|
+
.cost-optimization li::before {
|
253
|
+
content: '💡';
|
254
|
+
position: absolute;
|
255
|
+
left: 0;
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
.loading, .error, .no-data {
|
260
|
+
text-align: center;
|
261
|
+
padding: 3rem;
|
262
|
+
color: var(--text-secondary);
|
263
|
+
}
|
264
|
+
|
265
|
+
.loading i, .error i, .no-data i {
|
266
|
+
font-size: 3rem;
|
267
|
+
margin-bottom: 1rem;
|
268
|
+
display: block;
|
269
|
+
}
|
270
|
+
|
271
|
+
.no-data {
|
272
|
+
background: var(--card-bg);
|
273
|
+
border: 1px solid var(--border-color);
|
274
|
+
border-radius: 0.5rem;
|
275
|
+
margin: 2rem 0;
|
276
|
+
}
|
277
|
+
|
278
|
+
.research-link {
|
279
|
+
color: var(--primary-color);
|
280
|
+
text-decoration: none;
|
281
|
+
font-weight: 500;
|
282
|
+
}
|
283
|
+
|
284
|
+
.research-link:hover {
|
285
|
+
text-decoration: underline;
|
286
|
+
}
|
287
|
+
|
288
|
+
/* Tooltip Styles */
|
289
|
+
.tooltip {
|
290
|
+
position: relative;
|
291
|
+
cursor: help;
|
292
|
+
display: inline-block;
|
293
|
+
}
|
294
|
+
|
295
|
+
.tooltip::after {
|
296
|
+
content: attr(data-tooltip);
|
297
|
+
position: absolute;
|
298
|
+
bottom: 120%;
|
299
|
+
left: 50%;
|
300
|
+
transform: translateX(-50%);
|
301
|
+
background: rgba(0, 0, 0, 0.95);
|
302
|
+
color: white;
|
303
|
+
padding: 0.75rem;
|
304
|
+
border-radius: 0.5rem;
|
305
|
+
font-size: 0.75rem;
|
306
|
+
line-height: 1.4;
|
307
|
+
max-width: 280px;
|
308
|
+
min-width: 200px;
|
309
|
+
width: max-content;
|
310
|
+
white-space: normal;
|
311
|
+
word-wrap: break-word;
|
312
|
+
text-align: center;
|
313
|
+
opacity: 0;
|
314
|
+
pointer-events: none;
|
315
|
+
transition: opacity 0.2s, transform 0.2s;
|
316
|
+
z-index: 1001;
|
317
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
318
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
319
|
+
}
|
320
|
+
|
321
|
+
.tooltip::before {
|
322
|
+
content: '';
|
323
|
+
position: absolute;
|
324
|
+
bottom: 105%;
|
325
|
+
left: 50%;
|
326
|
+
transform: translateX(-50%);
|
327
|
+
border: 6px solid transparent;
|
328
|
+
border-top-color: rgba(0, 0, 0, 0.95);
|
329
|
+
opacity: 0;
|
330
|
+
pointer-events: none;
|
331
|
+
transition: opacity 0.2s;
|
332
|
+
z-index: 1001;
|
333
|
+
}
|
334
|
+
|
335
|
+
.tooltip:hover::after,
|
336
|
+
.tooltip:hover::before {
|
337
|
+
opacity: 1;
|
338
|
+
transform: translateX(-50%) translateY(-2px);
|
339
|
+
}
|
340
|
+
|
341
|
+
.info-icon {
|
342
|
+
color: var(--text-secondary);
|
343
|
+
margin-left: 0.25rem;
|
344
|
+
font-size: 0.875rem;
|
345
|
+
cursor: help;
|
346
|
+
}
|
347
|
+
|
348
|
+
.info-icon:hover {
|
349
|
+
color: var(--primary-color);
|
350
|
+
}
|
351
|
+
|
352
|
+
/* Page Information Section */
|
353
|
+
.page-info {
|
354
|
+
background: var(--card-bg);
|
355
|
+
border: 1px solid var(--border-color);
|
356
|
+
border-radius: 0.5rem;
|
357
|
+
padding: 2rem;
|
358
|
+
margin-top: 3rem;
|
359
|
+
}
|
360
|
+
|
361
|
+
.page-info h3 {
|
362
|
+
color: var(--text-primary);
|
363
|
+
margin: 0 0 1.5rem 0;
|
364
|
+
display: flex;
|
365
|
+
align-items: center;
|
366
|
+
gap: 0.5rem;
|
367
|
+
font-size: 1.5rem;
|
368
|
+
}
|
369
|
+
|
370
|
+
.info-grid {
|
371
|
+
display: grid;
|
372
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
373
|
+
gap: 2rem;
|
374
|
+
margin-bottom: 2rem;
|
375
|
+
}
|
376
|
+
|
377
|
+
.info-section h4 {
|
378
|
+
color: var(--primary-color);
|
379
|
+
margin: 0 0 1rem 0;
|
380
|
+
font-size: 1.1rem;
|
381
|
+
display: flex;
|
382
|
+
align-items: center;
|
383
|
+
gap: 0.5rem;
|
384
|
+
}
|
385
|
+
|
386
|
+
.info-section ul {
|
387
|
+
list-style: none;
|
388
|
+
padding: 0;
|
389
|
+
margin: 0;
|
390
|
+
}
|
391
|
+
|
392
|
+
.info-section li {
|
393
|
+
margin-bottom: 0.75rem;
|
394
|
+
padding-left: 1.5rem;
|
395
|
+
position: relative;
|
396
|
+
color: var(--text-secondary);
|
397
|
+
line-height: 1.5;
|
398
|
+
}
|
399
|
+
|
400
|
+
.info-section li::before {
|
401
|
+
content: '•';
|
402
|
+
position: absolute;
|
403
|
+
left: 0;
|
404
|
+
color: var(--primary-color);
|
405
|
+
font-weight: bold;
|
406
|
+
}
|
407
|
+
|
408
|
+
.info-section strong {
|
409
|
+
color: var(--text-primary);
|
410
|
+
}
|
411
|
+
|
412
|
+
.info-note {
|
413
|
+
background: var(--bg-secondary);
|
414
|
+
border-left: 3px solid var(--primary-color);
|
415
|
+
padding: 1.5rem;
|
416
|
+
border-radius: 0.375rem;
|
417
|
+
margin-top: 2rem;
|
418
|
+
}
|
419
|
+
|
420
|
+
.info-note p {
|
421
|
+
margin: 0;
|
422
|
+
color: var(--text-secondary);
|
423
|
+
line-height: 1.6;
|
424
|
+
}
|
425
|
+
|
426
|
+
.info-note strong {
|
427
|
+
color: var(--text-primary);
|
428
|
+
}
|
429
|
+
|
430
|
+
/* Dark theme adjustments */
|
431
|
+
[data-theme="dark"] .cost-optimization {
|
432
|
+
background: linear-gradient(135deg, #1a3a1a 0%, #2d4a2d 100%);
|
433
|
+
border-color: #4CAF50;
|
434
|
+
}
|
435
|
+
|
436
|
+
[data-theme="dark"] .cost-optimization h3,
|
437
|
+
[data-theme="dark"] .cost-optimization li {
|
438
|
+
color: #81c784;
|
439
|
+
}
|
440
|
+
|
441
|
+
@media (max-width: 768px) {
|
442
|
+
.cost-header {
|
443
|
+
flex-direction: column;
|
444
|
+
align-items: stretch;
|
445
|
+
}
|
446
|
+
|
447
|
+
.time-range-selector {
|
448
|
+
justify-content: center;
|
449
|
+
flex-wrap: wrap;
|
450
|
+
}
|
451
|
+
|
452
|
+
.cost-grid {
|
453
|
+
grid-template-columns: 1fr;
|
454
|
+
}
|
455
|
+
|
456
|
+
.cost-item {
|
457
|
+
flex-direction: column;
|
458
|
+
align-items: flex-start;
|
459
|
+
gap: 0.5rem;
|
460
|
+
}
|
461
|
+
}
|
462
|
+
</style>
|
463
|
+
{% endblock %}
|
464
|
+
|
465
|
+
{% block content %}
|
466
|
+
<div class="page active" id="cost-analytics">
|
467
|
+
<div class="cost-analytics-container">
|
468
|
+
<!-- Header -->
|
469
|
+
<div class="cost-header">
|
470
|
+
<div class="cost-title">
|
471
|
+
<h1><i class="fas fa-dollar-sign"></i> Cost Analytics <span style="color: var(--warning-color, #f39c12); font-size: 0.75em; font-weight: normal;">(Experimental)</span></h1>
|
472
|
+
<a href="/metrics" class="back-button">
|
473
|
+
<i class="fas fa-arrow-left"></i> Back to Metrics
|
474
|
+
</a>
|
475
|
+
</div>
|
476
|
+
|
477
|
+
<div class="time-range-selector">
|
478
|
+
<span style="color: var(--text-secondary); margin-right: 0.5rem; font-size: 0.875rem;">Time Period:</span>
|
479
|
+
<button class="time-range-btn active" data-period="7d">7 Days</button>
|
480
|
+
<button class="time-range-btn" data-period="30d">30 Days</button>
|
481
|
+
<button class="time-range-btn" data-period="90d">3 Months</button>
|
482
|
+
<button class="time-range-btn" data-period="365d">1 Year</button>
|
483
|
+
<button class="time-range-btn" data-period="all">All Time</button>
|
484
|
+
</div>
|
485
|
+
</div>
|
486
|
+
|
487
|
+
<!-- Loading State -->
|
488
|
+
<div id="loading" class="loading">
|
489
|
+
<i class="fas fa-spinner fa-spin"></i>
|
490
|
+
<h3>Loading Cost Analytics...</h3>
|
491
|
+
<p>Calculating costs and generating insights</p>
|
492
|
+
</div>
|
493
|
+
|
494
|
+
<!-- Error State -->
|
495
|
+
<div id="error" class="error" style="display: none;">
|
496
|
+
<i class="fas fa-exclamation-triangle"></i>
|
497
|
+
<h3>Error Loading Cost Data</h3>
|
498
|
+
<p>Unable to load cost analytics. Please try again later.</p>
|
499
|
+
</div>
|
500
|
+
|
501
|
+
<!-- Cost Analytics Content -->
|
502
|
+
<div id="cost-content" style="display: none;">
|
503
|
+
<!-- Overview Cards -->
|
504
|
+
<div class="cost-grid">
|
505
|
+
<div class="cost-card">
|
506
|
+
<div class="cost-card-header">
|
507
|
+
<div class="cost-icon">
|
508
|
+
<i class="fas fa-coins"></i>
|
509
|
+
</div>
|
510
|
+
<div>
|
511
|
+
<h3 class="cost-card-title tooltip" data-tooltip="Estimated total cost for all research sessions in the selected time period. Based on current model pricing and token usage.">
|
512
|
+
Total Cost
|
513
|
+
<i class="fas fa-info-circle info-icon"></i>
|
514
|
+
</h3>
|
515
|
+
</div>
|
516
|
+
</div>
|
517
|
+
<div class="cost-value" id="total-cost">$0.00</div>
|
518
|
+
<p class="cost-subtitle">Estimated total spending</p>
|
519
|
+
</div>
|
520
|
+
|
521
|
+
<div class="cost-card">
|
522
|
+
<div class="cost-card-header">
|
523
|
+
<div class="cost-icon">
|
524
|
+
<i class="fas fa-chart-line"></i>
|
525
|
+
</div>
|
526
|
+
<div>
|
527
|
+
<h3 class="cost-card-title tooltip" data-tooltip="Average cost per individual research session. This helps you understand the typical expense of running a research query.">
|
528
|
+
Average Per Research
|
529
|
+
<i class="fas fa-info-circle info-icon"></i>
|
530
|
+
</h3>
|
531
|
+
</div>
|
532
|
+
</div>
|
533
|
+
<div class="cost-value" id="avg-research-cost">$0.00</div>
|
534
|
+
<p class="cost-subtitle">Cost per research session</p>
|
535
|
+
</div>
|
536
|
+
|
537
|
+
<div class="cost-card">
|
538
|
+
<div class="cost-card-header">
|
539
|
+
<div class="cost-icon">
|
540
|
+
<i class="fas fa-robot"></i>
|
541
|
+
</div>
|
542
|
+
<div>
|
543
|
+
<h3 class="cost-card-title tooltip" data-tooltip="The LLM model that has cost you the most money in total during this time period. Consider using more cost-effective alternatives for routine tasks.">
|
544
|
+
Most Expensive Model
|
545
|
+
<i class="fas fa-info-circle info-icon"></i>
|
546
|
+
</h3>
|
547
|
+
</div>
|
548
|
+
</div>
|
549
|
+
<div class="cost-value" id="most-expensive-model">-</div>
|
550
|
+
<p class="cost-subtitle" id="most-expensive-model-cost">No data</p>
|
551
|
+
</div>
|
552
|
+
|
553
|
+
<div class="cost-card">
|
554
|
+
<div class="cost-card-header">
|
555
|
+
<div class="cost-icon">
|
556
|
+
<i class="fas fa-leaf"></i>
|
557
|
+
</div>
|
558
|
+
<div>
|
559
|
+
<h3 class="cost-card-title tooltip" data-tooltip="Money saved by using local models instead of commercial alternatives. Local models like Ollama, LM Studio run for free.">
|
560
|
+
Local Models Savings
|
561
|
+
<i class="fas fa-info-circle info-icon"></i>
|
562
|
+
</h3>
|
563
|
+
</div>
|
564
|
+
</div>
|
565
|
+
<div class="cost-value" id="local-savings">$0.00</div>
|
566
|
+
<p class="cost-subtitle" id="local-savings-subtitle">Free local inference</p>
|
567
|
+
</div>
|
568
|
+
</div>
|
569
|
+
|
570
|
+
<!-- Cost Trends Chart -->
|
571
|
+
<div class="chart-container">
|
572
|
+
<h3 class="chart-title tooltip" data-tooltip="Shows how your research costs have changed over time. Use this to identify spending patterns and budget more effectively for future research.">
|
573
|
+
<i class="fas fa-chart-area"></i>
|
574
|
+
Cost Trends Over Time
|
575
|
+
<i class="fas fa-info-circle info-icon"></i>
|
576
|
+
</h3>
|
577
|
+
<div class="chart-canvas">
|
578
|
+
<canvas id="cost-trends-chart"></canvas>
|
579
|
+
</div>
|
580
|
+
</div>
|
581
|
+
|
582
|
+
<!-- Provider Breakdown Chart -->
|
583
|
+
<div class="chart-container">
|
584
|
+
<h3 class="chart-title tooltip" data-tooltip="Shows usage breakdown by provider (OpenAI, Anthropic, Ollama, etc). Helps you understand which providers you rely on most and identify opportunities to use more cost-effective local models.">
|
585
|
+
<i class="fas fa-chart-pie"></i>
|
586
|
+
Usage by Provider
|
587
|
+
<i class="fas fa-info-circle info-icon"></i>
|
588
|
+
</h3>
|
589
|
+
<div class="chart-canvas">
|
590
|
+
<canvas id="provider-chart"></canvas>
|
591
|
+
</div>
|
592
|
+
</div>
|
593
|
+
|
594
|
+
<!-- Model Cost Comparison Chart -->
|
595
|
+
<div class="chart-container">
|
596
|
+
<h3 class="chart-title tooltip" data-tooltip="Compares the total cost spent on each LLM model with provider information. Local models (Ollama, LM Studio) show as $0.00 while commercial models show actual costs.">
|
597
|
+
<i class="fas fa-chart-bar"></i>
|
598
|
+
Cost by Model & Provider
|
599
|
+
<i class="fas fa-info-circle info-icon"></i>
|
600
|
+
</h3>
|
601
|
+
<div class="chart-canvas">
|
602
|
+
<canvas id="model-cost-chart"></canvas>
|
603
|
+
</div>
|
604
|
+
</div>
|
605
|
+
|
606
|
+
<!-- Most Expensive Research Sessions -->
|
607
|
+
<div class="cost-table">
|
608
|
+
<div class="cost-table-header">
|
609
|
+
<h3 class="cost-table-title tooltip" data-tooltip="Your most expensive individual research sessions. Click on any session to view its detailed results and understand what drove the higher costs.">
|
610
|
+
<i class="fas fa-fire"></i>
|
611
|
+
Most Expensive Research Sessions
|
612
|
+
<i class="fas fa-info-circle info-icon"></i>
|
613
|
+
</h3>
|
614
|
+
</div>
|
615
|
+
<div class="cost-table-content" id="expensive-research-list">
|
616
|
+
<!-- Populated by JavaScript -->
|
617
|
+
</div>
|
618
|
+
</div>
|
619
|
+
|
620
|
+
<!-- Cost Optimization Tips -->
|
621
|
+
<div class="cost-optimization">
|
622
|
+
<h3><i class="fas fa-lightbulb"></i> Cost Optimization Insights</h3>
|
623
|
+
<ul id="optimization-tips">
|
624
|
+
<!-- Populated by JavaScript -->
|
625
|
+
</ul>
|
626
|
+
</div>
|
627
|
+
</div>
|
628
|
+
|
629
|
+
<!-- No Data State -->
|
630
|
+
<div id="no-data" class="no-data" style="display: none;">
|
631
|
+
<i class="fas fa-chart-pie"></i>
|
632
|
+
<h3>No Cost Data Available</h3>
|
633
|
+
<p>Start some research sessions to see cost analytics here.</p>
|
634
|
+
<a href="/research" style="color: var(--primary-color); text-decoration: none; font-weight: 500;">
|
635
|
+
Start Research Session →
|
636
|
+
</a>
|
637
|
+
</div>
|
638
|
+
|
639
|
+
<!-- Page Information Section -->
|
640
|
+
<div class="page-info">
|
641
|
+
<h3><i class="fas fa-info-circle"></i> Understanding Cost Analytics</h3>
|
642
|
+
|
643
|
+
<div class="info-grid">
|
644
|
+
<!-- What We Track -->
|
645
|
+
<div class="info-section">
|
646
|
+
<h4><i class="fas fa-chart-pie"></i> What We Track</h4>
|
647
|
+
<ul>
|
648
|
+
<li><strong>Token Usage:</strong> Input and output tokens for each LLM call</li>
|
649
|
+
<li><strong>Provider Information:</strong> Track which provider (OpenAI, Ollama, etc.) was used</li>
|
650
|
+
<li><strong>Model Pricing:</strong> Current market rates for each LLM provider</li>
|
651
|
+
<li><strong>Research Sessions:</strong> Individual costs per research query</li>
|
652
|
+
<li><strong>Local Model Savings:</strong> Estimated savings from using free local models</li>
|
653
|
+
<li><strong>Provider Breakdown:</strong> Usage distribution across different providers</li>
|
654
|
+
<li><strong>Time-based Analysis:</strong> Cost trends over different periods</li>
|
655
|
+
</ul>
|
656
|
+
</div>
|
657
|
+
|
658
|
+
<!-- How Costs Are Calculated -->
|
659
|
+
<div class="info-section">
|
660
|
+
<h4><i class="fas fa-calculator"></i> How Costs Are Calculated</h4>
|
661
|
+
<ul>
|
662
|
+
<li><strong>Input Tokens:</strong> Charged at prompt pricing rate (usually lower)</li>
|
663
|
+
<li><strong>Output Tokens:</strong> Charged at completion pricing rate (usually higher)</li>
|
664
|
+
<li><strong>Total Cost:</strong> (Input tokens ÷ 1000) × Input rate + (Output tokens ÷ 1000) × Output rate</li>
|
665
|
+
<li><strong>Provider-Aware Pricing:</strong> Uses both model name and provider for accurate pricing</li>
|
666
|
+
<li><strong>Local Models:</strong> Ollama, LM Studio, vLLM, and self-hosted models are free ($0.00)</li>
|
667
|
+
<li><strong>Savings Calculation:</strong> Estimates money saved by comparing local usage to commercial equivalents</li>
|
668
|
+
<li><strong>Currency Format:</strong> Shows appropriate decimal places based on amount</li>
|
669
|
+
</ul>
|
670
|
+
</div>
|
671
|
+
|
672
|
+
<!-- Pricing Sources -->
|
673
|
+
<div class="info-section">
|
674
|
+
<h4><i class="fas fa-database"></i> Pricing Sources</h4>
|
675
|
+
<ul>
|
676
|
+
<li><strong>OpenAI:</strong> GPT-4, GPT-4 Turbo, GPT-4o, GPT-3.5 Turbo pricing</li>
|
677
|
+
<li><strong>Anthropic:</strong> Claude-3 Opus, Sonnet, Haiku, Claude-3.5 pricing</li>
|
678
|
+
<li><strong>Google:</strong> Gemini Pro, Gemini 1.5 Pro/Flash pricing</li>
|
679
|
+
<li><strong>Local/Open Source:</strong> Ollama, LM Studio, vLLM, LlamaCpp (all free)</li>
|
680
|
+
<li><strong>Updates:</strong> Pricing data is updated regularly from official sources</li>
|
681
|
+
</ul>
|
682
|
+
</div>
|
683
|
+
|
684
|
+
<!-- Cost Optimization Tips -->
|
685
|
+
<div class="info-section">
|
686
|
+
<h4><i class="fas fa-lightbulb"></i> Cost Optimization Strategies</h4>
|
687
|
+
<ul>
|
688
|
+
<li><strong>Model Selection:</strong> Use smaller models for simple tasks</li>
|
689
|
+
<li><strong>Research Mode:</strong> Choose "Quick" mode for basic queries</li>
|
690
|
+
<li><strong>Local Models:</strong> Consider Ollama for privacy and zero cost</li>
|
691
|
+
<li><strong>Batch Queries:</strong> Combine related questions in one session</li>
|
692
|
+
<li><strong>Monitor Trends:</strong> Track spending patterns to identify opportunities</li>
|
693
|
+
</ul>
|
694
|
+
</div>
|
695
|
+
|
696
|
+
<!-- Understanding the Data -->
|
697
|
+
<div class="info-section">
|
698
|
+
<h4><i class="fas fa-chart-line"></i> Understanding the Data</h4>
|
699
|
+
<ul>
|
700
|
+
<li><strong>Estimates Only:</strong> Costs are estimates based on current pricing</li>
|
701
|
+
<li><strong>Real Usage:</strong> Data reflects your actual token consumption</li>
|
702
|
+
<li><strong>Time Filtering:</strong> All metrics update based on selected time period</li>
|
703
|
+
<li><strong>Research Links:</strong> Click session IDs to view detailed results</li>
|
704
|
+
<li><strong>Model Efficiency:</strong> Lower cost per token indicates better efficiency</li>
|
705
|
+
</ul>
|
706
|
+
</div>
|
707
|
+
|
708
|
+
<!-- Local Model Pricing Estimates -->
|
709
|
+
<div class="info-section">
|
710
|
+
<h4><i class="fas fa-home"></i> Local Model Pricing Estimates</h4>
|
711
|
+
<ul>
|
712
|
+
<li><strong>Zero API Costs:</strong> Local models (Ollama, LM Studio, vLLM) have no API fees</li>
|
713
|
+
<li><strong>Savings Calculation:</strong> Compares your usage against equivalent commercial models</li>
|
714
|
+
<li><strong>Baseline Pricing:</strong> Uses conservative estimates (GPT-3.5/Claude Haiku rates)</li>
|
715
|
+
<li><strong>Rough Estimates:</strong> Actual commercial costs could be higher or lower</li>
|
716
|
+
<li><strong>Quality Differences:</strong> Local vs commercial models have different capabilities</li>
|
717
|
+
<li><strong>Hidden Costs:</strong> Does not include hardware, electricity, or setup time</li>
|
718
|
+
</ul>
|
719
|
+
</div>
|
720
|
+
|
721
|
+
<!-- Privacy & Data -->
|
722
|
+
<div class="info-section">
|
723
|
+
<h4><i class="fas fa-shield-alt"></i> Privacy & Data</h4>
|
724
|
+
<ul>
|
725
|
+
<li><strong>Local Storage:</strong> All cost data is stored locally on your device</li>
|
726
|
+
<li><strong>No Sharing:</strong> Cost information is never shared or transmitted</li>
|
727
|
+
<li><strong>Real Costs:</strong> These are estimates - check provider bills for actual charges</li>
|
728
|
+
<li><strong>Accuracy:</strong> Pricing data is kept up-to-date but may vary</li>
|
729
|
+
<li><strong>Control:</strong> You have full control over your usage and spending</li>
|
730
|
+
</ul>
|
731
|
+
</div>
|
732
|
+
</div>
|
733
|
+
|
734
|
+
<!-- Important Note -->
|
735
|
+
<div class="info-note">
|
736
|
+
<p>
|
737
|
+
<i class="fas fa-exclamation-triangle" style="color: var(--primary-color); margin-right: 0.5rem;"></i>
|
738
|
+
<strong>Important:</strong> These cost estimates are based on current public pricing from LLM providers and your actual token usage.
|
739
|
+
Actual costs may vary due to pricing changes, promotional rates, or billing adjustments.
|
740
|
+
Always refer to your official provider bills for exact charges.
|
741
|
+
Local models (Ollama, self-hosted) show $0.00 as they do not incur API costs.
|
742
|
+
</p>
|
743
|
+
</div>
|
744
|
+
|
745
|
+
<!-- Local Model Pricing Disclaimer -->
|
746
|
+
<div class="info-note" style="margin-top: 1rem; border-left-color: #FF9800;">
|
747
|
+
<p>
|
748
|
+
<i class="fas fa-home" style="color: #FF9800; margin-right: 0.5rem;"></i>
|
749
|
+
<strong>Local Model Savings Disclaimer:</strong> The "Local Models Savings" calculation is a rough estimate comparing your local model usage to hypothetical commercial API costs.
|
750
|
+
This estimate uses conservative baseline pricing (~$0.0015 per 1K tokens) and should be viewed as an approximation only.
|
751
|
+
<br><br>
|
752
|
+
<strong>Important Caveats:</strong>
|
753
|
+
<br>• <strong>Quality Differences:</strong> Commercial models may provide different output quality, accuracy, or capabilities
|
754
|
+
<br>• <strong>Hidden Costs:</strong> Local models require hardware investment, electricity, maintenance, and setup time
|
755
|
+
<br>• <strong>Performance Variations:</strong> Speed, reliability, and availability differences between local and commercial models
|
756
|
+
<br>• <strong>Scale Considerations:</strong> Commercial APIs may be more cost-effective for very high or very low usage patterns
|
757
|
+
<br>• <strong>Feature Differences:</strong> Commercial services often include additional features, support, and guarantees
|
758
|
+
<br><br>
|
759
|
+
Use these estimates as a general guide only. The true value of local models includes privacy, control, and independence benefits beyond just cost savings.
|
760
|
+
</p>
|
761
|
+
</div>
|
762
|
+
</div>
|
763
|
+
</div>
|
764
|
+
</div>
|
765
|
+
|
766
|
+
<script>
|
767
|
+
// Cost Analytics JavaScript
|
768
|
+
(function() {
|
769
|
+
let currentPeriod = '7d';
|
770
|
+
let costData = null;
|
771
|
+
let trendsChart = null;
|
772
|
+
let modelChart = null;
|
773
|
+
|
774
|
+
// Initialize the page
|
775
|
+
document.addEventListener('DOMContentLoaded', function() {
|
776
|
+
setupEventListeners();
|
777
|
+
loadCostData();
|
778
|
+
});
|
779
|
+
|
780
|
+
function setupEventListeners() {
|
781
|
+
// Time period buttons
|
782
|
+
document.querySelectorAll('.time-range-btn').forEach(btn => {
|
783
|
+
btn.addEventListener('click', function() {
|
784
|
+
// Update active state
|
785
|
+
document.querySelectorAll('.time-range-btn').forEach(b => b.classList.remove('active'));
|
786
|
+
this.classList.add('active');
|
787
|
+
|
788
|
+
// Update period and reload data
|
789
|
+
currentPeriod = this.dataset.period;
|
790
|
+
loadCostData();
|
791
|
+
});
|
792
|
+
});
|
793
|
+
}
|
794
|
+
|
795
|
+
async function loadCostData() {
|
796
|
+
try {
|
797
|
+
// Temporarily disable cost analytics until pricing logic is optimized
|
798
|
+
showTemporarilyDisabled();
|
799
|
+
return;
|
800
|
+
|
801
|
+
showLoading();
|
802
|
+
|
803
|
+
const response = await fetch(`/metrics/api/cost-analytics?period=${currentPeriod}`);
|
804
|
+
if (!response.ok) {
|
805
|
+
throw new Error(`API failed: ${response.status}`);
|
806
|
+
}
|
807
|
+
|
808
|
+
const data = await response.json();
|
809
|
+
|
810
|
+
if (data.status === 'success') {
|
811
|
+
costData = data;
|
812
|
+
|
813
|
+
if (data.overview.total_calls > 0) {
|
814
|
+
displayCostData();
|
815
|
+
showContent();
|
816
|
+
} else {
|
817
|
+
showNoData();
|
818
|
+
}
|
819
|
+
} else {
|
820
|
+
throw new Error(data.message || 'Unknown error');
|
821
|
+
}
|
822
|
+
} catch (error) {
|
823
|
+
console.error('Error loading cost data:', error);
|
824
|
+
showError();
|
825
|
+
}
|
826
|
+
}
|
827
|
+
|
828
|
+
function displayCostData() {
|
829
|
+
const overview = costData.overview;
|
830
|
+
|
831
|
+
// Update overview cards
|
832
|
+
document.getElementById('total-cost').textContent = formatCurrency(overview.total_cost);
|
833
|
+
document.getElementById('avg-research-cost').textContent = formatCurrency(overview.avg_cost_per_call);
|
834
|
+
|
835
|
+
// Find most expensive model and calculate local savings
|
836
|
+
const models = Object.entries(overview.model_breakdown || {});
|
837
|
+
if (models.length > 0) {
|
838
|
+
// Most expensive by total cost
|
839
|
+
const mostExpensive = models.reduce((max, [name, data]) =>
|
840
|
+
data.total_cost > max[1].total_cost ? [name, data] : max
|
841
|
+
);
|
842
|
+
document.getElementById('most-expensive-model').textContent = mostExpensive[0];
|
843
|
+
document.getElementById('most-expensive-model-cost').textContent =
|
844
|
+
`${formatCurrency(mostExpensive[1].total_cost)} total`;
|
845
|
+
|
846
|
+
// Calculate local model savings
|
847
|
+
let localTokens = 0;
|
848
|
+
let localCalls = 0;
|
849
|
+
|
850
|
+
for (const [modelName, data] of models) {
|
851
|
+
if (data.total_cost === 0) { // Local models have zero cost
|
852
|
+
localTokens += data.prompt_tokens + data.completion_tokens;
|
853
|
+
localCalls += data.calls;
|
854
|
+
}
|
855
|
+
}
|
856
|
+
|
857
|
+
// Estimate savings using GPT-3.5 pricing as baseline
|
858
|
+
const estimatedSavings = (localTokens / 1000) * 0.0015; // ~$0.0015 per 1K tokens average
|
859
|
+
|
860
|
+
if (localTokens > 0) {
|
861
|
+
document.getElementById('local-savings').textContent = formatCurrency(estimatedSavings);
|
862
|
+
document.getElementById('local-savings-subtitle').textContent =
|
863
|
+
`${localTokens.toLocaleString()} tokens, ${localCalls} calls`;
|
864
|
+
} else {
|
865
|
+
document.getElementById('local-savings').textContent = '$0.00';
|
866
|
+
document.getElementById('local-savings-subtitle').textContent = 'No local model usage';
|
867
|
+
}
|
868
|
+
}
|
869
|
+
|
870
|
+
// Load additional data for charts
|
871
|
+
loadChartsData();
|
872
|
+
displayExpensiveResearch();
|
873
|
+
displayOptimizationTips();
|
874
|
+
}
|
875
|
+
|
876
|
+
async function loadChartsData() {
|
877
|
+
// For now, create sample chart data
|
878
|
+
// In a real implementation, you'd fetch time-series cost data
|
879
|
+
createCostTrendsChart();
|
880
|
+
createProviderChart();
|
881
|
+
createModelCostChart();
|
882
|
+
}
|
883
|
+
|
884
|
+
function createCostTrendsChart() {
|
885
|
+
const ctx = document.getElementById('cost-trends-chart');
|
886
|
+
if (!ctx) return;
|
887
|
+
|
888
|
+
if (trendsChart) {
|
889
|
+
trendsChart.destroy();
|
890
|
+
}
|
891
|
+
|
892
|
+
// Sample data - replace with real time-series data
|
893
|
+
const labels = ['Week 1', 'Week 2', 'Week 3', 'Week 4'];
|
894
|
+
const costs = [0.02, 0.035, 0.028, 0.041];
|
895
|
+
|
896
|
+
trendsChart = new Chart(ctx, {
|
897
|
+
type: 'line',
|
898
|
+
data: {
|
899
|
+
labels: labels,
|
900
|
+
datasets: [{
|
901
|
+
label: 'Weekly Cost',
|
902
|
+
data: costs,
|
903
|
+
borderColor: '#4CAF50',
|
904
|
+
backgroundColor: 'rgba(76, 175, 80, 0.1)',
|
905
|
+
borderWidth: 3,
|
906
|
+
fill: true,
|
907
|
+
tension: 0.4
|
908
|
+
}]
|
909
|
+
},
|
910
|
+
options: {
|
911
|
+
responsive: true,
|
912
|
+
maintainAspectRatio: false,
|
913
|
+
scales: {
|
914
|
+
y: {
|
915
|
+
beginAtZero: true,
|
916
|
+
ticks: {
|
917
|
+
callback: function(value) {
|
918
|
+
return formatCurrency(value);
|
919
|
+
}
|
920
|
+
}
|
921
|
+
}
|
922
|
+
},
|
923
|
+
plugins: {
|
924
|
+
tooltip: {
|
925
|
+
callbacks: {
|
926
|
+
label: function(context) {
|
927
|
+
return `Cost: ${formatCurrency(context.parsed.y)}`;
|
928
|
+
}
|
929
|
+
}
|
930
|
+
}
|
931
|
+
}
|
932
|
+
}
|
933
|
+
});
|
934
|
+
}
|
935
|
+
|
936
|
+
function createProviderChart() {
|
937
|
+
const ctx = document.getElementById('provider-chart');
|
938
|
+
if (!ctx) return;
|
939
|
+
|
940
|
+
if (window.providerChart) {
|
941
|
+
window.providerChart.destroy();
|
942
|
+
}
|
943
|
+
|
944
|
+
// Calculate provider usage from model breakdown
|
945
|
+
const models = Object.entries(costData.overview.model_breakdown || {});
|
946
|
+
const providerStats = {};
|
947
|
+
|
948
|
+
for (const [modelName, data] of models) {
|
949
|
+
// Determine provider from model cost (0 = local, >0 = commercial)
|
950
|
+
let provider = 'Unknown';
|
951
|
+
if (data.total_cost === 0) {
|
952
|
+
provider = 'Local (Ollama/LM Studio)';
|
953
|
+
} else if (modelName.toLowerCase().includes('gpt')) {
|
954
|
+
provider = 'OpenAI';
|
955
|
+
} else if (modelName.toLowerCase().includes('claude')) {
|
956
|
+
provider = 'Anthropic';
|
957
|
+
} else if (modelName.toLowerCase().includes('gemini')) {
|
958
|
+
provider = 'Google';
|
959
|
+
}
|
960
|
+
|
961
|
+
if (!providerStats[provider]) {
|
962
|
+
providerStats[provider] = { calls: 0, tokens: 0, cost: 0 };
|
963
|
+
}
|
964
|
+
|
965
|
+
providerStats[provider].calls += data.calls;
|
966
|
+
providerStats[provider].tokens += data.prompt_tokens + data.completion_tokens;
|
967
|
+
providerStats[provider].cost += data.total_cost;
|
968
|
+
}
|
969
|
+
|
970
|
+
const labels = Object.keys(providerStats);
|
971
|
+
const tokens = Object.values(providerStats).map(p => p.tokens);
|
972
|
+
const colors = {
|
973
|
+
'Local (Ollama/LM Studio)': '#4CAF50',
|
974
|
+
'OpenAI': '#00A67E',
|
975
|
+
'Anthropic': '#FF6B35',
|
976
|
+
'Google': '#4285F4',
|
977
|
+
'Unknown': '#9E9E9E'
|
978
|
+
};
|
979
|
+
|
980
|
+
window.providerChart = new Chart(ctx, {
|
981
|
+
type: 'doughnut',
|
982
|
+
data: {
|
983
|
+
labels: labels,
|
984
|
+
datasets: [{
|
985
|
+
label: 'Token Usage',
|
986
|
+
data: tokens,
|
987
|
+
backgroundColor: labels.map(label => colors[label] || '#9E9E9E'),
|
988
|
+
borderWidth: 2,
|
989
|
+
borderColor: '#fff'
|
990
|
+
}]
|
991
|
+
},
|
992
|
+
options: {
|
993
|
+
responsive: true,
|
994
|
+
maintainAspectRatio: false,
|
995
|
+
plugins: {
|
996
|
+
legend: {
|
997
|
+
position: 'bottom',
|
998
|
+
labels: {
|
999
|
+
padding: 20,
|
1000
|
+
usePointStyle: true
|
1001
|
+
}
|
1002
|
+
},
|
1003
|
+
tooltip: {
|
1004
|
+
callbacks: {
|
1005
|
+
label: function(context) {
|
1006
|
+
const provider = context.label;
|
1007
|
+
const stats = providerStats[provider];
|
1008
|
+
return [
|
1009
|
+
`${provider}`,
|
1010
|
+
`Tokens: ${stats.tokens.toLocaleString()}`,
|
1011
|
+
`Calls: ${stats.calls}`,
|
1012
|
+
`Cost: ${formatCurrency(stats.cost)}`
|
1013
|
+
];
|
1014
|
+
}
|
1015
|
+
}
|
1016
|
+
}
|
1017
|
+
}
|
1018
|
+
}
|
1019
|
+
});
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
function createModelCostChart() {
|
1023
|
+
const ctx = document.getElementById('model-cost-chart');
|
1024
|
+
if (!ctx) return;
|
1025
|
+
|
1026
|
+
if (modelChart) {
|
1027
|
+
modelChart.destroy();
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
const models = Object.entries(costData.overview.model_breakdown || {});
|
1031
|
+
const labels = models.map(([name, data]) => {
|
1032
|
+
// Add provider info to label
|
1033
|
+
let provider = data.total_cost === 0 ? '(Local)' : '(Commercial)';
|
1034
|
+
return `${name} ${provider}`;
|
1035
|
+
});
|
1036
|
+
const costs = models.map(([, data]) => data.total_cost);
|
1037
|
+
|
1038
|
+
modelChart = new Chart(ctx, {
|
1039
|
+
type: 'bar',
|
1040
|
+
data: {
|
1041
|
+
labels: labels,
|
1042
|
+
datasets: [{
|
1043
|
+
label: 'Total Cost',
|
1044
|
+
data: costs,
|
1045
|
+
backgroundColor: [
|
1046
|
+
'#4CAF50',
|
1047
|
+
'#2196F3',
|
1048
|
+
'#FF9800',
|
1049
|
+
'#9C27B0',
|
1050
|
+
'#F44336'
|
1051
|
+
].slice(0, labels.length),
|
1052
|
+
borderWidth: 1
|
1053
|
+
}]
|
1054
|
+
},
|
1055
|
+
options: {
|
1056
|
+
responsive: true,
|
1057
|
+
maintainAspectRatio: false,
|
1058
|
+
scales: {
|
1059
|
+
y: {
|
1060
|
+
beginAtZero: true,
|
1061
|
+
ticks: {
|
1062
|
+
callback: function(value) {
|
1063
|
+
return formatCurrency(value);
|
1064
|
+
}
|
1065
|
+
}
|
1066
|
+
}
|
1067
|
+
},
|
1068
|
+
plugins: {
|
1069
|
+
tooltip: {
|
1070
|
+
callbacks: {
|
1071
|
+
label: function(context) {
|
1072
|
+
return `Cost: ${formatCurrency(context.parsed.y)}`;
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
}
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
});
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
function displayExpensiveResearch() {
|
1082
|
+
const container = document.getElementById('expensive-research-list');
|
1083
|
+
const expensiveResearch = costData.top_expensive_research || [];
|
1084
|
+
|
1085
|
+
if (expensiveResearch.length === 0) {
|
1086
|
+
container.innerHTML = '<p style="text-align: center; color: var(--text-secondary); padding: 2rem;">No research cost data available</p>';
|
1087
|
+
return;
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
container.innerHTML = '';
|
1091
|
+
expensiveResearch.slice(0, 10).forEach((item, index) => {
|
1092
|
+
const div = document.createElement('div');
|
1093
|
+
div.className = 'cost-item';
|
1094
|
+
div.innerHTML = `
|
1095
|
+
<div class="cost-item-info">
|
1096
|
+
<div class="cost-item-name">
|
1097
|
+
<a href="/research/results/${item.research_id}" class="research-link">
|
1098
|
+
Research Session #${item.research_id}
|
1099
|
+
</a>
|
1100
|
+
</div>
|
1101
|
+
<div class="cost-item-details">Rank #${index + 1} most expensive</div>
|
1102
|
+
</div>
|
1103
|
+
<div class="cost-item-value">${formatCurrency(item.total_cost)}</div>
|
1104
|
+
`;
|
1105
|
+
container.appendChild(div);
|
1106
|
+
});
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
function displayOptimizationTips() {
|
1110
|
+
const container = document.getElementById('optimization-tips');
|
1111
|
+
const tips = generateOptimizationTips();
|
1112
|
+
|
1113
|
+
container.innerHTML = '';
|
1114
|
+
tips.forEach(tip => {
|
1115
|
+
const li = document.createElement('li');
|
1116
|
+
li.textContent = tip;
|
1117
|
+
container.appendChild(li);
|
1118
|
+
});
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
function generateOptimizationTips() {
|
1122
|
+
const tips = [];
|
1123
|
+
const overview = costData.overview;
|
1124
|
+
const models = Object.entries(overview.model_breakdown || {});
|
1125
|
+
|
1126
|
+
// Count local vs commercial usage
|
1127
|
+
let localTokens = 0;
|
1128
|
+
let commercialTokens = 0;
|
1129
|
+
let hasLocalModels = false;
|
1130
|
+
|
1131
|
+
for (const [modelName, data] of models) {
|
1132
|
+
if (data.total_cost === 0) {
|
1133
|
+
localTokens += data.prompt_tokens + data.completion_tokens;
|
1134
|
+
hasLocalModels = true;
|
1135
|
+
} else {
|
1136
|
+
commercialTokens += data.prompt_tokens + data.completion_tokens;
|
1137
|
+
}
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
// Generate informative tips (no judgmental cost warnings)
|
1141
|
+
const totalCost = overview.total_cost;
|
1142
|
+
const avgCostPerCall = overview.avg_cost_per_call;
|
1143
|
+
|
1144
|
+
// Informative tips for local model users
|
1145
|
+
if (hasLocalModels && totalCost === 0) {
|
1146
|
+
tips.push('✅ Excellent! You are using 100% local models with zero inference costs');
|
1147
|
+
tips.push('🔒 Local models provide privacy benefits while keeping costs at $0.00');
|
1148
|
+
tips.push('🌟 You have complete control over your AI infrastructure');
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
// Mixed usage insights
|
1152
|
+
if (hasLocalModels && commercialTokens > 0) {
|
1153
|
+
const localPercent = Math.round((localTokens / (localTokens + commercialTokens)) * 100);
|
1154
|
+
tips.push('📊 You are using ' + localPercent + '% local models and ' + (100-localPercent) + '% commercial models');
|
1155
|
+
tips.push('💡 Consider evaluating which workloads could be shifted to local models');
|
1156
|
+
}
|
1157
|
+
|
1158
|
+
// Pure commercial usage - neutral suggestion
|
1159
|
+
if (!hasLocalModels && totalCost > 0) {
|
1160
|
+
tips.push('💼 You are using commercial LLM APIs for all research');
|
1161
|
+
tips.push('🏠 Local models like Ollama are available as a zero-cost alternative');
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
// General optimization tips (no cost judgments)
|
1165
|
+
if (models.length > 1) {
|
1166
|
+
tips.push('⚖️ Compare model performance vs cost to optimize your model selection');
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
// Informative model breakdown
|
1170
|
+
if (models.length > 0 && totalCost > 0) {
|
1171
|
+
const mostUsed = models.reduce((max, [name, data]) =>
|
1172
|
+
(data.prompt_tokens + data.completion_tokens) > (max[1].prompt_tokens + max[1].completion_tokens) ? [name, data] : max
|
1173
|
+
);
|
1174
|
+
tips.push('📈 "' + mostUsed[0] + '" is your most used model (' + mostUsed[1].calls + ' calls)');
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
// Default neutral tips
|
1178
|
+
if (tips.length === 0) {
|
1179
|
+
tips.push('📊 Track your research costs and model usage over time');
|
1180
|
+
tips.push('💡 Explore different models to find the best fit for your use case');
|
1181
|
+
}
|
1182
|
+
|
1183
|
+
return tips;
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
function formatCurrency(amount) {
|
1187
|
+
if (amount < 0.001) {
|
1188
|
+
return `$${amount.toFixed(6)}`;
|
1189
|
+
} else if (amount < 0.1) {
|
1190
|
+
return `$${amount.toFixed(4)}`;
|
1191
|
+
} else {
|
1192
|
+
return `$${amount.toFixed(2)}`;
|
1193
|
+
}
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
function showLoading() {
|
1197
|
+
document.getElementById('loading').style.display = 'block';
|
1198
|
+
document.getElementById('cost-content').style.display = 'none';
|
1199
|
+
document.getElementById('error').style.display = 'none';
|
1200
|
+
document.getElementById('no-data').style.display = 'none';
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
function showContent() {
|
1204
|
+
document.getElementById('loading').style.display = 'none';
|
1205
|
+
document.getElementById('cost-content').style.display = 'block';
|
1206
|
+
document.getElementById('error').style.display = 'none';
|
1207
|
+
document.getElementById('no-data').style.display = 'none';
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
function showError() {
|
1211
|
+
document.getElementById('loading').style.display = 'none';
|
1212
|
+
document.getElementById('cost-content').style.display = 'none';
|
1213
|
+
document.getElementById('error').style.display = 'block';
|
1214
|
+
document.getElementById('no-data').style.display = 'none';
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
function showNoData() {
|
1218
|
+
document.getElementById('loading').style.display = 'none';
|
1219
|
+
document.getElementById('cost-content').style.display = 'none';
|
1220
|
+
document.getElementById('error').style.display = 'none';
|
1221
|
+
document.getElementById('no-data').style.display = 'block';
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
function showTemporarilyDisabled() {
|
1225
|
+
document.getElementById('loading').style.display = 'none';
|
1226
|
+
document.getElementById('cost-content').style.display = 'none';
|
1227
|
+
document.getElementById('error').style.display = 'none';
|
1228
|
+
document.getElementById('no-data').style.display = 'block';
|
1229
|
+
|
1230
|
+
// Update the no-data message to indicate temporary disable
|
1231
|
+
const noDataContainer = document.getElementById('no-data');
|
1232
|
+
if (noDataContainer) {
|
1233
|
+
noDataContainer.innerHTML = `
|
1234
|
+
<div class="no-data-container">
|
1235
|
+
<div class="no-data-icon">⚠️</div>
|
1236
|
+
<h3>Cost Analytics Temporarily Disabled</h3>
|
1237
|
+
<p>Cost calculation is temporarily disabled while we optimize the pricing logic to ensure accuracy.</p>
|
1238
|
+
<p>This prevents showing misleading cost information. The feature will be re-enabled once the pricing system is improved.</p>
|
1239
|
+
</div>
|
1240
|
+
`;
|
1241
|
+
}
|
1242
|
+
}
|
1243
|
+
})();
|
1244
|
+
</script>
|
1245
|
+
{% endblock %}
|