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.
Files changed (220) hide show
  1. local_deep_research/__init__.py +7 -0
  2. local_deep_research/__version__.py +1 -1
  3. local_deep_research/advanced_search_system/answer_decoding/__init__.py +5 -0
  4. local_deep_research/advanced_search_system/answer_decoding/browsecomp_answer_decoder.py +421 -0
  5. local_deep_research/advanced_search_system/candidate_exploration/README.md +219 -0
  6. local_deep_research/advanced_search_system/candidate_exploration/__init__.py +25 -0
  7. local_deep_research/advanced_search_system/candidate_exploration/adaptive_explorer.py +329 -0
  8. local_deep_research/advanced_search_system/candidate_exploration/base_explorer.py +341 -0
  9. local_deep_research/advanced_search_system/candidate_exploration/constraint_guided_explorer.py +436 -0
  10. local_deep_research/advanced_search_system/candidate_exploration/diversity_explorer.py +457 -0
  11. local_deep_research/advanced_search_system/candidate_exploration/parallel_explorer.py +250 -0
  12. local_deep_research/advanced_search_system/candidate_exploration/progressive_explorer.py +255 -0
  13. local_deep_research/advanced_search_system/candidates/__init__.py +5 -0
  14. local_deep_research/advanced_search_system/candidates/base_candidate.py +59 -0
  15. local_deep_research/advanced_search_system/constraint_checking/README.md +150 -0
  16. local_deep_research/advanced_search_system/constraint_checking/__init__.py +35 -0
  17. local_deep_research/advanced_search_system/constraint_checking/base_constraint_checker.py +122 -0
  18. local_deep_research/advanced_search_system/constraint_checking/constraint_checker.py +223 -0
  19. local_deep_research/advanced_search_system/constraint_checking/constraint_satisfaction_tracker.py +387 -0
  20. local_deep_research/advanced_search_system/constraint_checking/dual_confidence_checker.py +424 -0
  21. local_deep_research/advanced_search_system/constraint_checking/evidence_analyzer.py +174 -0
  22. local_deep_research/advanced_search_system/constraint_checking/intelligent_constraint_relaxer.py +503 -0
  23. local_deep_research/advanced_search_system/constraint_checking/rejection_engine.py +143 -0
  24. local_deep_research/advanced_search_system/constraint_checking/strict_checker.py +259 -0
  25. local_deep_research/advanced_search_system/constraint_checking/threshold_checker.py +213 -0
  26. local_deep_research/advanced_search_system/constraints/__init__.py +6 -0
  27. local_deep_research/advanced_search_system/constraints/base_constraint.py +58 -0
  28. local_deep_research/advanced_search_system/constraints/constraint_analyzer.py +143 -0
  29. local_deep_research/advanced_search_system/evidence/__init__.py +12 -0
  30. local_deep_research/advanced_search_system/evidence/base_evidence.py +57 -0
  31. local_deep_research/advanced_search_system/evidence/evaluator.py +159 -0
  32. local_deep_research/advanced_search_system/evidence/requirements.py +122 -0
  33. local_deep_research/advanced_search_system/filters/base_filter.py +3 -1
  34. local_deep_research/advanced_search_system/filters/cross_engine_filter.py +8 -2
  35. local_deep_research/advanced_search_system/filters/journal_reputation_filter.py +43 -29
  36. local_deep_research/advanced_search_system/findings/repository.py +54 -17
  37. local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +3 -1
  38. local_deep_research/advanced_search_system/query_generation/adaptive_query_generator.py +405 -0
  39. local_deep_research/advanced_search_system/questions/__init__.py +16 -0
  40. local_deep_research/advanced_search_system/questions/atomic_fact_question.py +171 -0
  41. local_deep_research/advanced_search_system/questions/browsecomp_question.py +287 -0
  42. local_deep_research/advanced_search_system/questions/decomposition_question.py +13 -4
  43. local_deep_research/advanced_search_system/questions/entity_aware_question.py +184 -0
  44. local_deep_research/advanced_search_system/questions/standard_question.py +9 -3
  45. local_deep_research/advanced_search_system/search_optimization/cross_constraint_manager.py +624 -0
  46. local_deep_research/advanced_search_system/source_management/diversity_manager.py +613 -0
  47. local_deep_research/advanced_search_system/strategies/__init__.py +42 -0
  48. local_deep_research/advanced_search_system/strategies/adaptive_decomposition_strategy.py +564 -0
  49. local_deep_research/advanced_search_system/strategies/base_strategy.py +4 -4
  50. local_deep_research/advanced_search_system/strategies/browsecomp_entity_strategy.py +1031 -0
  51. local_deep_research/advanced_search_system/strategies/browsecomp_optimized_strategy.py +778 -0
  52. local_deep_research/advanced_search_system/strategies/concurrent_dual_confidence_strategy.py +446 -0
  53. local_deep_research/advanced_search_system/strategies/constrained_search_strategy.py +1348 -0
  54. local_deep_research/advanced_search_system/strategies/constraint_parallel_strategy.py +522 -0
  55. local_deep_research/advanced_search_system/strategies/direct_search_strategy.py +217 -0
  56. local_deep_research/advanced_search_system/strategies/dual_confidence_strategy.py +320 -0
  57. local_deep_research/advanced_search_system/strategies/dual_confidence_with_rejection.py +219 -0
  58. local_deep_research/advanced_search_system/strategies/early_stop_constrained_strategy.py +369 -0
  59. local_deep_research/advanced_search_system/strategies/entity_aware_source_strategy.py +140 -0
  60. local_deep_research/advanced_search_system/strategies/evidence_based_strategy.py +1248 -0
  61. local_deep_research/advanced_search_system/strategies/evidence_based_strategy_v2.py +1337 -0
  62. local_deep_research/advanced_search_system/strategies/focused_iteration_strategy.py +537 -0
  63. local_deep_research/advanced_search_system/strategies/improved_evidence_based_strategy.py +782 -0
  64. local_deep_research/advanced_search_system/strategies/iterative_reasoning_strategy.py +760 -0
  65. local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +55 -21
  66. local_deep_research/advanced_search_system/strategies/llm_driven_modular_strategy.py +865 -0
  67. local_deep_research/advanced_search_system/strategies/modular_strategy.py +1142 -0
  68. local_deep_research/advanced_search_system/strategies/parallel_constrained_strategy.py +506 -0
  69. local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +34 -16
  70. local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +29 -9
  71. local_deep_research/advanced_search_system/strategies/recursive_decomposition_strategy.py +492 -0
  72. local_deep_research/advanced_search_system/strategies/smart_decomposition_strategy.py +284 -0
  73. local_deep_research/advanced_search_system/strategies/smart_query_strategy.py +515 -0
  74. local_deep_research/advanced_search_system/strategies/source_based_strategy.py +48 -24
  75. local_deep_research/advanced_search_system/strategies/standard_strategy.py +34 -14
  76. local_deep_research/advanced_search_system/tools/base_tool.py +7 -2
  77. local_deep_research/api/benchmark_functions.py +6 -2
  78. local_deep_research/api/research_functions.py +10 -4
  79. local_deep_research/benchmarks/__init__.py +9 -7
  80. local_deep_research/benchmarks/benchmark_functions.py +6 -2
  81. local_deep_research/benchmarks/cli/benchmark_commands.py +27 -10
  82. local_deep_research/benchmarks/cli.py +38 -13
  83. local_deep_research/benchmarks/comparison/__init__.py +4 -2
  84. local_deep_research/benchmarks/comparison/evaluator.py +316 -239
  85. local_deep_research/benchmarks/datasets/__init__.py +1 -1
  86. local_deep_research/benchmarks/datasets/base.py +91 -72
  87. local_deep_research/benchmarks/datasets/browsecomp.py +54 -33
  88. local_deep_research/benchmarks/datasets/custom_dataset_template.py +19 -19
  89. local_deep_research/benchmarks/datasets/simpleqa.py +14 -14
  90. local_deep_research/benchmarks/datasets/utils.py +48 -29
  91. local_deep_research/benchmarks/datasets.py +4 -11
  92. local_deep_research/benchmarks/efficiency/__init__.py +8 -4
  93. local_deep_research/benchmarks/efficiency/resource_monitor.py +223 -171
  94. local_deep_research/benchmarks/efficiency/speed_profiler.py +62 -48
  95. local_deep_research/benchmarks/evaluators/browsecomp.py +3 -1
  96. local_deep_research/benchmarks/evaluators/composite.py +6 -2
  97. local_deep_research/benchmarks/evaluators/simpleqa.py +36 -13
  98. local_deep_research/benchmarks/graders.py +32 -10
  99. local_deep_research/benchmarks/metrics/README.md +1 -1
  100. local_deep_research/benchmarks/metrics/calculation.py +25 -10
  101. local_deep_research/benchmarks/metrics/reporting.py +7 -3
  102. local_deep_research/benchmarks/metrics/visualization.py +42 -23
  103. local_deep_research/benchmarks/metrics.py +1 -1
  104. local_deep_research/benchmarks/optimization/__init__.py +3 -1
  105. local_deep_research/benchmarks/optimization/api.py +7 -1
  106. local_deep_research/benchmarks/optimization/optuna_optimizer.py +75 -26
  107. local_deep_research/benchmarks/runners.py +48 -15
  108. local_deep_research/citation_handler.py +65 -92
  109. local_deep_research/citation_handlers/__init__.py +15 -0
  110. local_deep_research/citation_handlers/base_citation_handler.py +70 -0
  111. local_deep_research/citation_handlers/forced_answer_citation_handler.py +179 -0
  112. local_deep_research/citation_handlers/precision_extraction_handler.py +550 -0
  113. local_deep_research/citation_handlers/standard_citation_handler.py +80 -0
  114. local_deep_research/config/llm_config.py +271 -169
  115. local_deep_research/config/search_config.py +14 -5
  116. local_deep_research/defaults/__init__.py +0 -1
  117. local_deep_research/metrics/__init__.py +13 -0
  118. local_deep_research/metrics/database.py +58 -0
  119. local_deep_research/metrics/db_models.py +115 -0
  120. local_deep_research/metrics/migrate_add_provider_to_token_usage.py +148 -0
  121. local_deep_research/metrics/migrate_call_stack_tracking.py +105 -0
  122. local_deep_research/metrics/migrate_enhanced_tracking.py +75 -0
  123. local_deep_research/metrics/migrate_research_ratings.py +31 -0
  124. local_deep_research/metrics/models.py +61 -0
  125. local_deep_research/metrics/pricing/__init__.py +12 -0
  126. local_deep_research/metrics/pricing/cost_calculator.py +237 -0
  127. local_deep_research/metrics/pricing/pricing_cache.py +143 -0
  128. local_deep_research/metrics/pricing/pricing_fetcher.py +240 -0
  129. local_deep_research/metrics/query_utils.py +51 -0
  130. local_deep_research/metrics/search_tracker.py +380 -0
  131. local_deep_research/metrics/token_counter.py +1078 -0
  132. local_deep_research/migrate_db.py +3 -1
  133. local_deep_research/report_generator.py +22 -8
  134. local_deep_research/search_system.py +390 -9
  135. local_deep_research/test_migration.py +15 -5
  136. local_deep_research/utilities/db_utils.py +7 -4
  137. local_deep_research/utilities/es_utils.py +115 -104
  138. local_deep_research/utilities/llm_utils.py +15 -5
  139. local_deep_research/utilities/log_utils.py +151 -0
  140. local_deep_research/utilities/search_cache.py +387 -0
  141. local_deep_research/utilities/search_utilities.py +14 -6
  142. local_deep_research/utilities/threading_utils.py +92 -0
  143. local_deep_research/utilities/url_utils.py +6 -0
  144. local_deep_research/web/api.py +347 -0
  145. local_deep_research/web/app.py +13 -17
  146. local_deep_research/web/app_factory.py +71 -66
  147. local_deep_research/web/database/migrate_to_ldr_db.py +12 -4
  148. local_deep_research/web/database/migrations.py +20 -3
  149. local_deep_research/web/database/models.py +74 -25
  150. local_deep_research/web/database/schema_upgrade.py +49 -29
  151. local_deep_research/web/models/database.py +63 -83
  152. local_deep_research/web/routes/api_routes.py +56 -22
  153. local_deep_research/web/routes/benchmark_routes.py +4 -1
  154. local_deep_research/web/routes/globals.py +22 -0
  155. local_deep_research/web/routes/history_routes.py +71 -46
  156. local_deep_research/web/routes/metrics_routes.py +1155 -0
  157. local_deep_research/web/routes/research_routes.py +192 -54
  158. local_deep_research/web/routes/settings_routes.py +156 -55
  159. local_deep_research/web/services/research_service.py +412 -251
  160. local_deep_research/web/services/resource_service.py +36 -11
  161. local_deep_research/web/services/settings_manager.py +55 -17
  162. local_deep_research/web/services/settings_service.py +12 -4
  163. local_deep_research/web/services/socket_service.py +295 -188
  164. local_deep_research/web/static/css/custom_dropdown.css +180 -0
  165. local_deep_research/web/static/css/styles.css +39 -1
  166. local_deep_research/web/static/js/components/detail.js +633 -267
  167. local_deep_research/web/static/js/components/details.js +751 -0
  168. local_deep_research/web/static/js/components/fallback/formatting.js +11 -11
  169. local_deep_research/web/static/js/components/fallback/ui.js +23 -23
  170. local_deep_research/web/static/js/components/history.js +76 -76
  171. local_deep_research/web/static/js/components/logpanel.js +61 -13
  172. local_deep_research/web/static/js/components/progress.js +13 -2
  173. local_deep_research/web/static/js/components/research.js +99 -12
  174. local_deep_research/web/static/js/components/results.js +239 -106
  175. local_deep_research/web/static/js/main.js +40 -40
  176. local_deep_research/web/static/js/services/audio.js +1 -1
  177. local_deep_research/web/static/js/services/formatting.js +11 -11
  178. local_deep_research/web/static/js/services/keyboard.js +157 -0
  179. local_deep_research/web/static/js/services/pdf.js +80 -80
  180. local_deep_research/web/static/sounds/README.md +1 -1
  181. local_deep_research/web/templates/base.html +1 -0
  182. local_deep_research/web/templates/components/log_panel.html +7 -1
  183. local_deep_research/web/templates/components/mobile_nav.html +1 -1
  184. local_deep_research/web/templates/components/sidebar.html +3 -0
  185. local_deep_research/web/templates/pages/cost_analytics.html +1245 -0
  186. local_deep_research/web/templates/pages/details.html +325 -24
  187. local_deep_research/web/templates/pages/history.html +1 -1
  188. local_deep_research/web/templates/pages/metrics.html +1929 -0
  189. local_deep_research/web/templates/pages/progress.html +2 -2
  190. local_deep_research/web/templates/pages/research.html +53 -17
  191. local_deep_research/web/templates/pages/results.html +12 -1
  192. local_deep_research/web/templates/pages/star_reviews.html +803 -0
  193. local_deep_research/web/utils/formatters.py +9 -3
  194. local_deep_research/web_search_engines/default_search_engines.py +5 -3
  195. local_deep_research/web_search_engines/engines/full_search.py +8 -2
  196. local_deep_research/web_search_engines/engines/meta_search_engine.py +59 -20
  197. local_deep_research/web_search_engines/engines/search_engine_arxiv.py +19 -6
  198. local_deep_research/web_search_engines/engines/search_engine_brave.py +6 -2
  199. local_deep_research/web_search_engines/engines/search_engine_ddg.py +3 -1
  200. local_deep_research/web_search_engines/engines/search_engine_elasticsearch.py +81 -58
  201. local_deep_research/web_search_engines/engines/search_engine_github.py +46 -15
  202. local_deep_research/web_search_engines/engines/search_engine_google_pse.py +16 -6
  203. local_deep_research/web_search_engines/engines/search_engine_guardian.py +39 -15
  204. local_deep_research/web_search_engines/engines/search_engine_local.py +58 -25
  205. local_deep_research/web_search_engines/engines/search_engine_local_all.py +15 -5
  206. local_deep_research/web_search_engines/engines/search_engine_pubmed.py +63 -21
  207. local_deep_research/web_search_engines/engines/search_engine_searxng.py +37 -11
  208. local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +27 -9
  209. local_deep_research/web_search_engines/engines/search_engine_serpapi.py +12 -4
  210. local_deep_research/web_search_engines/engines/search_engine_wayback.py +31 -10
  211. local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +12 -3
  212. local_deep_research/web_search_engines/search_engine_base.py +83 -35
  213. local_deep_research/web_search_engines/search_engine_factory.py +25 -8
  214. local_deep_research/web_search_engines/search_engines_config.py +9 -3
  215. {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/METADATA +7 -1
  216. local_deep_research-0.5.2.dist-info/RECORD +265 -0
  217. local_deep_research-0.4.4.dist-info/RECORD +0 -177
  218. {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/WHEEL +0 -0
  219. {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/entry_points.txt +0 -0
  220. {local_deep_research-0.4.4.dist-info → local_deep_research-0.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,803 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Star Reviews Analytics{% endblock %}
4
+
5
+ {% block extra_head %}
6
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
7
+ <style>
8
+ .star-reviews-container {
9
+ max-width: 1200px;
10
+ margin: 0 auto;
11
+ padding: 2rem;
12
+ }
13
+
14
+ .metrics-header {
15
+ background: var(--gradient-bg);
16
+ color: var(--text-primary);
17
+ padding: 2rem;
18
+ border-radius: 0.75rem;
19
+ margin-bottom: 2rem;
20
+ text-align: center;
21
+ border: 1px solid var(--border-color);
22
+ box-shadow: var(--card-shadow);
23
+ }
24
+
25
+ .metrics-grid {
26
+ display: grid;
27
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
28
+ gap: 1.5rem;
29
+ margin-bottom: 2rem;
30
+ }
31
+
32
+ .metric-card {
33
+ background: var(--bg-secondary);
34
+ border-radius: 0.75rem;
35
+ padding: 1.5rem;
36
+ box-shadow: var(--card-shadow);
37
+ border: 1px solid var(--border-color);
38
+ transition: transform 0.2s ease;
39
+ }
40
+
41
+ .metric-card:hover {
42
+ transform: translateY(-2px);
43
+ }
44
+
45
+ .metric-card h3 {
46
+ margin-top: 0;
47
+ color: var(--text-primary);
48
+ border-bottom: 2px solid var(--border-color);
49
+ padding-bottom: 0.75rem;
50
+ margin-bottom: 1rem;
51
+ font-size: 1.125rem;
52
+ }
53
+
54
+ .chart-container {
55
+ position: relative;
56
+ height: 400px;
57
+ margin-bottom: 1rem;
58
+ }
59
+
60
+ .overall-stats {
61
+ display: grid;
62
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
63
+ gap: 1.25rem;
64
+ margin-bottom: 2rem;
65
+ }
66
+
67
+ .stat-item {
68
+ text-align: center;
69
+ padding: 1rem;
70
+ background: var(--bg-tertiary);
71
+ border-radius: 0.5rem;
72
+ border: 1px solid var(--border-color);
73
+ }
74
+
75
+ .stat-value {
76
+ font-size: 1.5rem;
77
+ font-weight: bold;
78
+ color: var(--accent-primary);
79
+ display: block;
80
+ }
81
+
82
+ .stat-label {
83
+ font-size: 0.75rem;
84
+ color: var(--text-secondary);
85
+ margin-top: 0.25rem;
86
+ text-transform: uppercase;
87
+ letter-spacing: 0.05em;
88
+ }
89
+
90
+ .star-rating {
91
+ color: var(--warning-color);
92
+ font-size: 1.2em;
93
+ }
94
+
95
+ .rating-distribution {
96
+ margin: 1rem 0;
97
+ }
98
+
99
+ .rating-distribution h4 {
100
+ color: var(--text-primary);
101
+ margin-bottom: 1rem;
102
+ text-align: center;
103
+ }
104
+
105
+ .rating-bar {
106
+ display: flex;
107
+ align-items: center;
108
+ margin: 0.5rem 0;
109
+ gap: 0.75rem;
110
+ }
111
+
112
+ .rating-label {
113
+ min-width: 60px;
114
+ font-weight: 500;
115
+ color: var(--text-secondary);
116
+ font-size: 0.875rem;
117
+ }
118
+
119
+ .rating-progress {
120
+ flex: 1;
121
+ height: 16px;
122
+ background: var(--bg-tertiary);
123
+ border-radius: 0.5rem;
124
+ overflow: hidden;
125
+ }
126
+
127
+ .rating-fill {
128
+ height: 100%;
129
+ background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
130
+ transition: width 0.3s ease;
131
+ border-radius: 0.5rem;
132
+ }
133
+
134
+ .rating-count {
135
+ font-weight: 500;
136
+ min-width: 30px;
137
+ text-align: right;
138
+ color: var(--text-secondary);
139
+ font-size: 0.875rem;
140
+ }
141
+
142
+ .period-selector {
143
+ margin-bottom: 1.5rem;
144
+ }
145
+
146
+ .period-selector label {
147
+ color: var(--text-secondary);
148
+ margin-right: 0.5rem;
149
+ font-weight: 500;
150
+ }
151
+
152
+ .period-selector select {
153
+ padding: 0.5rem 1rem;
154
+ border: 1px solid var(--border-color);
155
+ border-radius: 0.375rem;
156
+ background: var(--bg-secondary);
157
+ color: var(--text-primary);
158
+ cursor: pointer;
159
+ transition: border-color 0.2s ease;
160
+ }
161
+
162
+ .period-selector select:focus {
163
+ outline: none;
164
+ border-color: var(--accent-primary);
165
+ box-shadow: 0 0 0 3px rgba(110, 79, 246, 0.1);
166
+ }
167
+
168
+ .recent-ratings {
169
+ max-height: 500px;
170
+ overflow-y: auto;
171
+ }
172
+
173
+ .rating-item {
174
+ display: flex;
175
+ justify-content: space-between;
176
+ align-items: center;
177
+ padding: 0.75rem;
178
+ border-bottom: 1px solid var(--border-color);
179
+ transition: background-color 0.2s ease;
180
+ }
181
+
182
+ .rating-item:hover {
183
+ background-color: var(--bg-tertiary);
184
+ }
185
+
186
+ .rating-item:last-child {
187
+ border-bottom: none;
188
+ }
189
+
190
+ .rating-details {
191
+ flex: 1;
192
+ }
193
+
194
+ .rating-query {
195
+ font-weight: 500;
196
+ color: var(--text-primary);
197
+ margin-bottom: 0.25rem;
198
+ }
199
+
200
+ .rating-meta {
201
+ font-size: 0.8125rem;
202
+ color: var(--text-muted);
203
+ }
204
+
205
+ .rating-score {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 0.375rem;
209
+ color: var(--text-primary);
210
+ }
211
+
212
+ .rating-link {
213
+ color: var(--accent-tertiary);
214
+ text-decoration: none;
215
+ font-weight: 500;
216
+ transition: color 0.2s ease;
217
+ }
218
+
219
+ .rating-link:hover {
220
+ color: var(--accent-secondary);
221
+ text-decoration: underline;
222
+ }
223
+
224
+ .info-section {
225
+ margin-bottom: 2rem;
226
+ }
227
+
228
+ .info-card {
229
+ background: var(--bg-secondary);
230
+ border: 1px solid var(--border-color);
231
+ border-radius: 0.75rem;
232
+ padding: 1.5rem;
233
+ margin-bottom: 1.5rem;
234
+ display: flex;
235
+ align-items: flex-start;
236
+ gap: 1rem;
237
+ box-shadow: var(--card-shadow);
238
+ }
239
+
240
+ .info-icon {
241
+ font-size: 2rem;
242
+ display: flex;
243
+ align-items: center;
244
+ justify-content: center;
245
+ width: 60px;
246
+ height: 60px;
247
+ background: var(--bg-tertiary);
248
+ border-radius: 50%;
249
+ flex-shrink: 0;
250
+ }
251
+
252
+ .info-content h3 {
253
+ margin: 0 0 0.75rem 0;
254
+ color: var(--accent-primary);
255
+ font-size: 1.25rem;
256
+ }
257
+
258
+ .info-content p {
259
+ margin: 0;
260
+ color: var(--text-secondary);
261
+ line-height: 1.6;
262
+ }
263
+
264
+ .info-grid {
265
+ display: grid;
266
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
267
+ gap: 1.25rem;
268
+ }
269
+
270
+ .info-item {
271
+ background: var(--bg-secondary);
272
+ border: 1px solid var(--border-color);
273
+ border-radius: 0.5rem;
274
+ padding: 1.25rem;
275
+ text-align: center;
276
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
277
+ }
278
+
279
+ .info-item:hover {
280
+ transform: translateY(-2px);
281
+ box-shadow: var(--card-shadow);
282
+ }
283
+
284
+ .info-item-icon {
285
+ font-size: 1.75rem;
286
+ margin-bottom: 0.75rem;
287
+ }
288
+
289
+ .info-item h4 {
290
+ margin: 0 0 0.5rem 0;
291
+ color: var(--text-primary);
292
+ font-size: 1rem;
293
+ }
294
+
295
+ .info-item p {
296
+ margin: 0;
297
+ color: var(--text-secondary);
298
+ font-size: 0.875rem;
299
+ line-height: 1.5;
300
+ }
301
+
302
+ .loading {
303
+ text-align: center;
304
+ padding: 2.5rem;
305
+ color: var(--text-secondary);
306
+ background: var(--bg-secondary);
307
+ border-radius: 0.5rem;
308
+ border: 1px solid var(--border-color);
309
+ }
310
+
311
+ .error {
312
+ background: rgba(250, 92, 124, 0.1);
313
+ color: var(--error-color);
314
+ padding: 1rem;
315
+ border-radius: 0.5rem;
316
+ margin: 1.25rem 0;
317
+ border: 1px solid rgba(250, 92, 124, 0.2);
318
+ }
319
+
320
+ @media (max-width: 768px) {
321
+ .metrics-grid {
322
+ grid-template-columns: 1fr;
323
+ }
324
+
325
+ .overall-stats {
326
+ grid-template-columns: repeat(2, 1fr);
327
+ }
328
+
329
+ .info-card {
330
+ flex-direction: column;
331
+ text-align: center;
332
+ }
333
+
334
+ .info-grid {
335
+ grid-template-columns: 1fr;
336
+ }
337
+
338
+ .star-reviews-container {
339
+ padding: 1rem;
340
+ }
341
+ }
342
+ </style>
343
+ {% endblock %}
344
+
345
+ {% block content %}
346
+ <div class="star-reviews-container">
347
+ <div class="metrics-header">
348
+ <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
349
+ <h1>⭐ Star Reviews Analytics</h1>
350
+ <a href="/metrics/" style="background: var(--bg-tertiary); color: var(--text-primary); padding: 0.5rem 1rem; border-radius: 0.375rem; text-decoration: none; font-size: 0.875rem; border: 1px solid var(--border-color); transition: background-color 0.2s ease;">
351
+ ← Back to Metrics
352
+ </a>
353
+ </div>
354
+ <p>Comprehensive analysis of user satisfaction ratings</p>
355
+ </div>
356
+
357
+ <div class="period-selector">
358
+ <label for="period-select">Time Period: </label>
359
+ <select id="period-select">
360
+ <option value="7d">Last 7 days</option>
361
+ <option value="30d" selected>Last 30 days</option>
362
+ <option value="3m">Last 3 months</option>
363
+ <option value="1y">Last year</option>
364
+ <option value="all">All time</option>
365
+ </select>
366
+ </div>
367
+
368
+ <div id="loading" class="loading">
369
+ <div>Loading star reviews data...</div>
370
+ </div>
371
+
372
+ <div id="error" class="error" style="display: none;"></div>
373
+
374
+ <div id="content" style="display: none;">
375
+ <!-- Overall Statistics -->
376
+ <div class="metric-card">
377
+ <h3>📊 Overall Satisfaction</h3>
378
+ <div class="overall-stats">
379
+ <div class="stat-item">
380
+ <span class="stat-value" id="avg-rating">0.0</span>
381
+ <div class="stat-label">Average Rating</div>
382
+ </div>
383
+ <div class="stat-item">
384
+ <span class="stat-value" id="total-ratings">0</span>
385
+ <div class="stat-label">Total Ratings</div>
386
+ </div>
387
+ <div class="stat-item">
388
+ <span class="stat-value" id="satisfaction-rate">0%</span>
389
+ <div class="stat-label">Satisfaction Rate</div>
390
+ </div>
391
+ </div>
392
+
393
+ <div class="rating-distribution">
394
+ <h4>Rating Distribution</h4>
395
+ <div class="rating-bar">
396
+ <div class="rating-label">5 ⭐</div>
397
+ <div class="rating-progress">
398
+ <div class="rating-fill" id="rating-5" style="width: 0%;"></div>
399
+ </div>
400
+ <div class="rating-count" id="count-5">0</div>
401
+ </div>
402
+ <div class="rating-bar">
403
+ <div class="rating-label">4 ⭐</div>
404
+ <div class="rating-progress">
405
+ <div class="rating-fill" id="rating-4" style="width: 0%;"></div>
406
+ </div>
407
+ <div class="rating-count" id="count-4">0</div>
408
+ </div>
409
+ <div class="rating-bar">
410
+ <div class="rating-label">3 ⭐</div>
411
+ <div class="rating-progress">
412
+ <div class="rating-fill" id="rating-3" style="width: 0%;"></div>
413
+ </div>
414
+ <div class="rating-count" id="count-3">0</div>
415
+ </div>
416
+ <div class="rating-bar">
417
+ <div class="rating-label">2 ⭐</div>
418
+ <div class="rating-progress">
419
+ <div class="rating-fill" id="rating-2" style="width: 0%;"></div>
420
+ </div>
421
+ <div class="rating-count" id="count-2">0</div>
422
+ </div>
423
+ <div class="rating-bar">
424
+ <div class="rating-label">1 ⭐</div>
425
+ <div class="rating-progress">
426
+ <div class="rating-fill" id="rating-1" style="width: 0%;"></div>
427
+ </div>
428
+ <div class="rating-count" id="count-1">0</div>
429
+ </div>
430
+ </div>
431
+ </div>
432
+
433
+ <div class="metrics-grid">
434
+ <!-- LLM Model Ratings Chart -->
435
+ <div class="metric-card">
436
+ <h3>🤖 LLM Model Performance</h3>
437
+ <div class="chart-container">
438
+ <canvas id="llm-ratings-chart"></canvas>
439
+ </div>
440
+ </div>
441
+
442
+ <!-- Search Engine Ratings Chart -->
443
+ <div class="metric-card">
444
+ <h3>🔍 Search Engine Performance</h3>
445
+ <div class="chart-container">
446
+ <canvas id="search-engine-ratings-chart"></canvas>
447
+ </div>
448
+ </div>
449
+
450
+ <!-- Rating Trends Over Time -->
451
+ <div class="metric-card">
452
+ <h3>📈 Rating Trends</h3>
453
+ <div class="chart-container">
454
+ <canvas id="rating-trends-chart"></canvas>
455
+ </div>
456
+ </div>
457
+
458
+ <!-- Recent Ratings -->
459
+ <div class="metric-card">
460
+ <h3>🕐 Recent Ratings</h3>
461
+ <div class="recent-ratings" id="recent-ratings">
462
+ <!-- Recent ratings will be populated here -->
463
+ </div>
464
+ </div>
465
+ </div>
466
+ </div>
467
+
468
+ <div class="info-section">
469
+ <div class="info-card">
470
+ <div class="info-icon">📊</div>
471
+ <div class="info-content">
472
+ <h3>Data-Driven Research Optimization</h3>
473
+ <p>Use your personal rating history to optimize your research workflow. Instead of relying on intuition alone, leverage actual performance statistics to identify which LLM models, search engines, and research approaches deliver the best results for your specific needs.</p>
474
+ </div>
475
+ </div>
476
+
477
+ <div class="info-grid">
478
+ <div class="info-item">
479
+ <div class="info-item-icon">🤖</div>
480
+ <h4>Model Performance</h4>
481
+ <p>Compare LLM models based on your actual satisfaction ratings to choose the best performing one for your research style.</p>
482
+ </div>
483
+
484
+ <div class="info-item">
485
+ <div class="info-item-icon">🔍</div>
486
+ <h4>Search Engine Insights</h4>
487
+ <p>Discover which search engines consistently deliver higher-quality results for your research topics and preferences.</p>
488
+ </div>
489
+
490
+ <div class="info-item">
491
+ <div class="info-item-icon">📈</div>
492
+ <h4>Trend Analysis</h4>
493
+ <p>Track your satisfaction trends over time to understand how your research effectiveness evolves and identify optimization opportunities.</p>
494
+ </div>
495
+
496
+ <div class="info-item">
497
+ <div class="info-item-icon">🎯</div>
498
+ <h4>Personalized Recommendations</h4>
499
+ <p>Make informed decisions about your research configuration based on your personal usage patterns and satisfaction data.</p>
500
+ </div>
501
+ </div>
502
+ </div>
503
+ </div>
504
+
505
+ <script>
506
+ let llmChart, searchEngineChart, trendsChart;
507
+
508
+ // Initialize page
509
+ document.addEventListener('DOMContentLoaded', function() {
510
+ loadStarReviews();
511
+
512
+ // Period selector change handler
513
+ document.getElementById('period-select').addEventListener('change', loadStarReviews);
514
+ });
515
+
516
+ async function loadStarReviews() {
517
+ console.log('Loading star reviews...');
518
+ const period = document.getElementById('period-select').value;
519
+
520
+ showLoading();
521
+
522
+ try {
523
+ console.log('Fetching data for period:', period);
524
+ const response = await fetch(`/metrics/api/star-reviews?period=${period}`);
525
+
526
+ if (!response.ok) {
527
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
528
+ }
529
+
530
+ const data = await response.json();
531
+ console.log('Received data:', data);
532
+
533
+ if (data.error) {
534
+ showError(data.error);
535
+ return;
536
+ }
537
+
538
+ console.log('Updating charts and stats...');
539
+ updateOverallStats(data.overall_stats);
540
+ updateLLMChart(data.llm_ratings);
541
+ updateSearchEngineChart(data.search_engine_ratings);
542
+ updateTrendsChart(data.rating_trends);
543
+ updateRecentRatings(data.recent_ratings);
544
+
545
+ showContent();
546
+ console.log('Star reviews loaded successfully');
547
+
548
+ } catch (error) {
549
+ console.error('Error loading star reviews:', error);
550
+ showError('Failed to load star reviews data: ' + error.message);
551
+ }
552
+ }
553
+
554
+ function showLoading() {
555
+ document.getElementById('loading').style.display = 'block';
556
+ document.getElementById('content').style.display = 'none';
557
+ document.getElementById('error').style.display = 'none';
558
+ }
559
+
560
+ function showContent() {
561
+ document.getElementById('loading').style.display = 'none';
562
+ document.getElementById('content').style.display = 'block';
563
+ document.getElementById('error').style.display = 'none';
564
+ }
565
+
566
+ function showError(message) {
567
+ document.getElementById('loading').style.display = 'none';
568
+ document.getElementById('content').style.display = 'none';
569
+ document.getElementById('error').style.display = 'block';
570
+ document.getElementById('error').textContent = message;
571
+ }
572
+
573
+ function updateOverallStats(stats) {
574
+ document.getElementById('avg-rating').textContent = stats.avg_rating;
575
+ document.getElementById('total-ratings').textContent = stats.total_ratings;
576
+
577
+ // Calculate satisfaction rate (4+ stars)
578
+ const satisfactionRate = stats.total_ratings > 0 ?
579
+ Math.round(((stats.rating_distribution['4'] + stats.rating_distribution['5']) / stats.total_ratings) * 100) : 0;
580
+ document.getElementById('satisfaction-rate').textContent = satisfactionRate + '%';
581
+
582
+ // Update rating distribution
583
+ const total = stats.total_ratings || 1;
584
+ for (let i = 1; i <= 5; i++) {
585
+ const count = stats.rating_distribution[i.toString()] || 0;
586
+ const percentage = Math.round((count / total) * 100);
587
+
588
+ document.getElementById(`rating-${i}`).style.width = percentage + '%';
589
+ document.getElementById(`count-${i}`).textContent = count;
590
+ }
591
+ }
592
+
593
+ function updateLLMChart(llmRatings) {
594
+ const ctx = document.getElementById('llm-ratings-chart').getContext('2d');
595
+
596
+ if (llmChart) {
597
+ llmChart.destroy();
598
+ }
599
+
600
+ // Sort by rating and take top 10
601
+ const sortedData = llmRatings.sort((a, b) => b.avg_rating - a.avg_rating).slice(0, 10);
602
+
603
+ llmChart = new Chart(ctx, {
604
+ type: 'bar',
605
+ data: {
606
+ labels: sortedData.map(item => item.model || 'Unknown'),
607
+ datasets: [{
608
+ label: 'Average Rating',
609
+ data: sortedData.map(item => item.avg_rating),
610
+ backgroundColor: 'rgba(54, 162, 235, 0.8)',
611
+ borderColor: 'rgba(54, 162, 235, 1)',
612
+ borderWidth: 1
613
+ }]
614
+ },
615
+ options: {
616
+ responsive: true,
617
+ maintainAspectRatio: false,
618
+ scales: {
619
+ y: {
620
+ beginAtZero: true,
621
+ max: 5,
622
+ title: {
623
+ display: true,
624
+ text: 'Average Rating (Stars)'
625
+ }
626
+ },
627
+ x: {
628
+ title: {
629
+ display: true,
630
+ text: 'LLM Models'
631
+ }
632
+ }
633
+ },
634
+ plugins: {
635
+ legend: {
636
+ display: false
637
+ },
638
+ tooltip: {
639
+ callbacks: {
640
+ afterLabel: function(context) {
641
+ const index = context.dataIndex;
642
+ const item = sortedData[index];
643
+ return [
644
+ `Ratings: ${item.rating_count}`,
645
+ `Satisfaction: ${item.satisfaction_rate}%`
646
+ ];
647
+ }
648
+ }
649
+ }
650
+ }
651
+ }
652
+ });
653
+ }
654
+
655
+ function updateSearchEngineChart(searchEngineRatings) {
656
+ const ctx = document.getElementById('search-engine-ratings-chart').getContext('2d');
657
+
658
+ if (searchEngineChart) {
659
+ searchEngineChart.destroy();
660
+ }
661
+
662
+ // Sort by rating and take top 10
663
+ const sortedData = searchEngineRatings.sort((a, b) => b.avg_rating - a.avg_rating).slice(0, 10);
664
+
665
+ searchEngineChart = new Chart(ctx, {
666
+ type: 'bar',
667
+ data: {
668
+ labels: sortedData.map(item => item.search_engine || 'Unknown'),
669
+ datasets: [{
670
+ label: 'Average Rating',
671
+ data: sortedData.map(item => item.avg_rating),
672
+ backgroundColor: 'rgba(255, 99, 132, 0.8)',
673
+ borderColor: 'rgba(255, 99, 132, 1)',
674
+ borderWidth: 1
675
+ }]
676
+ },
677
+ options: {
678
+ responsive: true,
679
+ maintainAspectRatio: false,
680
+ scales: {
681
+ y: {
682
+ beginAtZero: true,
683
+ max: 5,
684
+ title: {
685
+ display: true,
686
+ text: 'Average Rating (Stars)'
687
+ }
688
+ },
689
+ x: {
690
+ title: {
691
+ display: true,
692
+ text: 'Search Engines'
693
+ }
694
+ }
695
+ },
696
+ plugins: {
697
+ legend: {
698
+ display: false
699
+ },
700
+ tooltip: {
701
+ callbacks: {
702
+ afterLabel: function(context) {
703
+ const index = context.dataIndex;
704
+ const item = sortedData[index];
705
+ return [
706
+ `Ratings: ${item.rating_count}`,
707
+ `Satisfaction: ${item.satisfaction_rate}%`
708
+ ];
709
+ }
710
+ }
711
+ }
712
+ }
713
+ }
714
+ });
715
+ }
716
+
717
+ function updateTrendsChart(ratingTrends) {
718
+ const ctx = document.getElementById('rating-trends-chart').getContext('2d');
719
+
720
+ if (trendsChart) {
721
+ trendsChart.destroy();
722
+ }
723
+
724
+ trendsChart = new Chart(ctx, {
725
+ type: 'line',
726
+ data: {
727
+ labels: ratingTrends.map(item => new Date(item.date).toLocaleDateString()),
728
+ datasets: [{
729
+ label: 'Average Rating',
730
+ data: ratingTrends.map(item => item.avg_rating),
731
+ borderColor: 'rgba(75, 192, 192, 1)',
732
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
733
+ borderWidth: 2,
734
+ fill: true,
735
+ tension: 0.4
736
+ }]
737
+ },
738
+ options: {
739
+ responsive: true,
740
+ maintainAspectRatio: false,
741
+ scales: {
742
+ y: {
743
+ beginAtZero: true,
744
+ max: 5,
745
+ title: {
746
+ display: true,
747
+ text: 'Average Rating'
748
+ }
749
+ },
750
+ x: {
751
+ title: {
752
+ display: true,
753
+ text: 'Date'
754
+ }
755
+ }
756
+ },
757
+ plugins: {
758
+ legend: {
759
+ display: false
760
+ }
761
+ }
762
+ }
763
+ });
764
+ }
765
+
766
+ function updateRecentRatings(recentRatings) {
767
+ const container = document.getElementById('recent-ratings');
768
+ container.innerHTML = '';
769
+
770
+ if (recentRatings.length === 0) {
771
+ container.innerHTML = '<div style="text-align: center; padding: 20px; color: #718096;">No recent ratings found</div>';
772
+ return;
773
+ }
774
+
775
+ recentRatings.forEach(rating => {
776
+ const item = document.createElement('div');
777
+ item.className = 'rating-item';
778
+
779
+ const stars = '⭐'.repeat(rating.rating);
780
+ const date = new Date(rating.rated_at).toLocaleDateString();
781
+
782
+ item.innerHTML = `
783
+ <div class="rating-details">
784
+ <div class="rating-query">
785
+ <a href="/research/results/${rating.research_id}" class="rating-link">
786
+ ${rating.query}
787
+ </a>
788
+ </div>
789
+ <div class="rating-meta">
790
+ ${rating.llm_model} • ${rating.mode} • ${date}
791
+ </div>
792
+ </div>
793
+ <div class="rating-score">
794
+ <span class="star-rating">${stars}</span>
795
+ <span>${rating.rating}/5</span>
796
+ </div>
797
+ `;
798
+
799
+ container.appendChild(item);
800
+ });
801
+ }
802
+ </script>
803
+ {% endblock %}