local-deep-research 0.1.26__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. local_deep_research/__init__.py +23 -22
  2. local_deep_research/__main__.py +16 -0
  3. local_deep_research/advanced_search_system/__init__.py +7 -0
  4. local_deep_research/advanced_search_system/filters/__init__.py +8 -0
  5. local_deep_research/advanced_search_system/filters/base_filter.py +38 -0
  6. local_deep_research/advanced_search_system/filters/cross_engine_filter.py +200 -0
  7. local_deep_research/advanced_search_system/findings/base_findings.py +81 -0
  8. local_deep_research/advanced_search_system/findings/repository.py +452 -0
  9. local_deep_research/advanced_search_system/knowledge/__init__.py +1 -0
  10. local_deep_research/advanced_search_system/knowledge/base_knowledge.py +151 -0
  11. local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +159 -0
  12. local_deep_research/advanced_search_system/questions/__init__.py +1 -0
  13. local_deep_research/advanced_search_system/questions/base_question.py +64 -0
  14. local_deep_research/advanced_search_system/questions/decomposition_question.py +445 -0
  15. local_deep_research/advanced_search_system/questions/standard_question.py +119 -0
  16. local_deep_research/advanced_search_system/repositories/__init__.py +7 -0
  17. local_deep_research/advanced_search_system/strategies/__init__.py +1 -0
  18. local_deep_research/advanced_search_system/strategies/base_strategy.py +118 -0
  19. local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +450 -0
  20. local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +312 -0
  21. local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +270 -0
  22. local_deep_research/advanced_search_system/strategies/standard_strategy.py +300 -0
  23. local_deep_research/advanced_search_system/tools/__init__.py +1 -0
  24. local_deep_research/advanced_search_system/tools/base_tool.py +100 -0
  25. local_deep_research/advanced_search_system/tools/knowledge_tools/__init__.py +1 -0
  26. local_deep_research/advanced_search_system/tools/question_tools/__init__.py +1 -0
  27. local_deep_research/advanced_search_system/tools/search_tools/__init__.py +1 -0
  28. local_deep_research/api/__init__.py +5 -5
  29. local_deep_research/api/research_functions.py +96 -84
  30. local_deep_research/app.py +8 -0
  31. local_deep_research/citation_handler.py +25 -16
  32. local_deep_research/{config.py → config/config_files.py} +102 -110
  33. local_deep_research/config/llm_config.py +472 -0
  34. local_deep_research/config/search_config.py +77 -0
  35. local_deep_research/defaults/__init__.py +10 -5
  36. local_deep_research/defaults/main.toml +2 -2
  37. local_deep_research/defaults/search_engines.toml +60 -34
  38. local_deep_research/main.py +121 -19
  39. local_deep_research/migrate_db.py +147 -0
  40. local_deep_research/report_generator.py +72 -44
  41. local_deep_research/search_system.py +147 -283
  42. local_deep_research/setup_data_dir.py +35 -0
  43. local_deep_research/test_migration.py +178 -0
  44. local_deep_research/utilities/__init__.py +0 -0
  45. local_deep_research/utilities/db_utils.py +49 -0
  46. local_deep_research/{utilties → utilities}/enums.py +2 -2
  47. local_deep_research/{utilties → utilities}/llm_utils.py +63 -29
  48. local_deep_research/utilities/search_utilities.py +242 -0
  49. local_deep_research/{utilties → utilities}/setup_utils.py +4 -2
  50. local_deep_research/web/__init__.py +0 -1
  51. local_deep_research/web/app.py +86 -1709
  52. local_deep_research/web/app_factory.py +289 -0
  53. local_deep_research/web/database/README.md +70 -0
  54. local_deep_research/web/database/migrate_to_ldr_db.py +289 -0
  55. local_deep_research/web/database/migrations.py +447 -0
  56. local_deep_research/web/database/models.py +117 -0
  57. local_deep_research/web/database/schema_upgrade.py +107 -0
  58. local_deep_research/web/models/database.py +294 -0
  59. local_deep_research/web/models/settings.py +94 -0
  60. local_deep_research/web/routes/api_routes.py +559 -0
  61. local_deep_research/web/routes/history_routes.py +354 -0
  62. local_deep_research/web/routes/research_routes.py +715 -0
  63. local_deep_research/web/routes/settings_routes.py +1592 -0
  64. local_deep_research/web/services/research_service.py +947 -0
  65. local_deep_research/web/services/resource_service.py +149 -0
  66. local_deep_research/web/services/settings_manager.py +669 -0
  67. local_deep_research/web/services/settings_service.py +187 -0
  68. local_deep_research/web/services/socket_service.py +210 -0
  69. local_deep_research/web/static/css/custom_dropdown.css +277 -0
  70. local_deep_research/web/static/css/settings.css +1223 -0
  71. local_deep_research/web/static/css/styles.css +525 -48
  72. local_deep_research/web/static/js/components/custom_dropdown.js +428 -0
  73. local_deep_research/web/static/js/components/detail.js +348 -0
  74. local_deep_research/web/static/js/components/fallback/formatting.js +122 -0
  75. local_deep_research/web/static/js/components/fallback/ui.js +215 -0
  76. local_deep_research/web/static/js/components/history.js +487 -0
  77. local_deep_research/web/static/js/components/logpanel.js +949 -0
  78. local_deep_research/web/static/js/components/progress.js +1107 -0
  79. local_deep_research/web/static/js/components/research.js +1865 -0
  80. local_deep_research/web/static/js/components/results.js +766 -0
  81. local_deep_research/web/static/js/components/settings.js +3981 -0
  82. local_deep_research/web/static/js/components/settings_sync.js +106 -0
  83. local_deep_research/web/static/js/main.js +226 -0
  84. local_deep_research/web/static/js/services/api.js +253 -0
  85. local_deep_research/web/static/js/services/audio.js +31 -0
  86. local_deep_research/web/static/js/services/formatting.js +119 -0
  87. local_deep_research/web/static/js/services/pdf.js +622 -0
  88. local_deep_research/web/static/js/services/socket.js +882 -0
  89. local_deep_research/web/static/js/services/ui.js +546 -0
  90. local_deep_research/web/templates/base.html +72 -0
  91. local_deep_research/web/templates/components/custom_dropdown.html +47 -0
  92. local_deep_research/web/templates/components/log_panel.html +32 -0
  93. local_deep_research/web/templates/components/mobile_nav.html +22 -0
  94. local_deep_research/web/templates/components/settings_form.html +299 -0
  95. local_deep_research/web/templates/components/sidebar.html +21 -0
  96. local_deep_research/web/templates/pages/details.html +73 -0
  97. local_deep_research/web/templates/pages/history.html +51 -0
  98. local_deep_research/web/templates/pages/progress.html +57 -0
  99. local_deep_research/web/templates/pages/research.html +139 -0
  100. local_deep_research/web/templates/pages/results.html +59 -0
  101. local_deep_research/web/templates/settings_dashboard.html +78 -192
  102. local_deep_research/web/utils/__init__.py +0 -0
  103. local_deep_research/web/utils/formatters.py +76 -0
  104. local_deep_research/web_search_engines/engines/full_search.py +18 -16
  105. local_deep_research/web_search_engines/engines/meta_search_engine.py +182 -131
  106. local_deep_research/web_search_engines/engines/search_engine_arxiv.py +224 -139
  107. local_deep_research/web_search_engines/engines/search_engine_brave.py +88 -71
  108. local_deep_research/web_search_engines/engines/search_engine_ddg.py +48 -39
  109. local_deep_research/web_search_engines/engines/search_engine_github.py +415 -204
  110. local_deep_research/web_search_engines/engines/search_engine_google_pse.py +123 -90
  111. local_deep_research/web_search_engines/engines/search_engine_guardian.py +210 -157
  112. local_deep_research/web_search_engines/engines/search_engine_local.py +532 -369
  113. local_deep_research/web_search_engines/engines/search_engine_local_all.py +42 -36
  114. local_deep_research/web_search_engines/engines/search_engine_pubmed.py +358 -266
  115. local_deep_research/web_search_engines/engines/search_engine_searxng.py +211 -159
  116. local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +213 -170
  117. local_deep_research/web_search_engines/engines/search_engine_serpapi.py +84 -68
  118. local_deep_research/web_search_engines/engines/search_engine_wayback.py +186 -154
  119. local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +115 -77
  120. local_deep_research/web_search_engines/search_engine_base.py +174 -99
  121. local_deep_research/web_search_engines/search_engine_factory.py +192 -102
  122. local_deep_research/web_search_engines/search_engines_config.py +22 -15
  123. {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/METADATA +177 -97
  124. local_deep_research-0.2.0.dist-info/RECORD +135 -0
  125. {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/WHEEL +1 -2
  126. {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/entry_points.txt +3 -0
  127. local_deep_research/defaults/llm_config.py +0 -338
  128. local_deep_research/utilties/search_utilities.py +0 -114
  129. local_deep_research/web/static/js/app.js +0 -3763
  130. local_deep_research/web/templates/api_keys_config.html +0 -82
  131. local_deep_research/web/templates/collections_config.html +0 -90
  132. local_deep_research/web/templates/index.html +0 -348
  133. local_deep_research/web/templates/llm_config.html +0 -120
  134. local_deep_research/web/templates/main_config.html +0 -89
  135. local_deep_research/web/templates/search_engines_config.html +0 -154
  136. local_deep_research/web/templates/settings.html +0 -519
  137. local_deep_research-0.1.26.dist-info/RECORD +0 -61
  138. local_deep_research-0.1.26.dist-info/top_level.txt +0 -1
  139. /local_deep_research/{utilties → config}/__init__.py +0 -0
  140. {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,22 @@
1
+ <nav class="mobile-tab-bar">
2
+ <ul>
3
+ <li {% if active_page == 'new-research' %}class="active"{% endif %} data-page="new-research">
4
+ <a href="{{ url_for('research.index') }}">
5
+ <i class="fas fa-search"></i>
6
+ <span>Research</span>
7
+ </a>
8
+ </li>
9
+ <li {% if active_page == 'history' %}class="active"{% endif %} data-page="history">
10
+ <a href="{{ url_for('research.history_page') }}">
11
+ <i class="fas fa-history"></i>
12
+ <span>History</span>
13
+ </a>
14
+ </li>
15
+ <li {% if active_page == 'settings' %}class="active"{% endif %} data-page="settings">
16
+ <a href="{{ url_for('research.settings_page') }}">
17
+ <i class="fas fa-cog"></i>
18
+ <span>Settings</span>
19
+ </a>
20
+ </li>
21
+ </ul>
22
+ </nav>
@@ -0,0 +1,299 @@
1
+ {% macro render_setting(setting, id_prefix="") %}
2
+ {% set setting_id = (id_prefix ~ "-" if id_prefix else "") ~ setting.key|replace(".", "-") %}
3
+
4
+ <div class="settings-item form-group" data-key="{{ setting.key }}">
5
+ <div class="settings-item-header">
6
+ <label for="{{ setting_id }}">{{ setting.name }}</label>
7
+ {% if setting.description %}
8
+ <span class="settings-tooltip" title="{{ setting.description }}">
9
+ <i class="fas fa-info-circle"></i>
10
+ </span>
11
+ {% endif %}
12
+ </div>
13
+
14
+ {% if setting.ui_element == "textarea" %}
15
+ {# Check if this is JSON content that should be expanded into controls #}
16
+ {% if setting.value is mapping or (setting.value is string and (setting.value.startswith('{') and setting.value.endswith('}'))) %}
17
+ <div class="json-expanded-controls">
18
+ {% if setting.value is string %}
19
+ {% set json_value = setting.value|tojson %}
20
+ {% else %}
21
+ {% set json_value = setting.value %}
22
+ {% endif %}
23
+
24
+ {# Store the original JSON in a hidden field #}
25
+ <input type="hidden" id="{{ setting_id }}_original" name="{{ setting.key }}_original" value="{{ setting.value|tojson }}">
26
+
27
+ {# Create individual form controls for each JSON property #}
28
+ <div class="json-property-controls">
29
+ {% for key, value in json_value.items() %}
30
+ <div class="json-property-item">
31
+ <label for="{{ setting_id }}_{{ key }}">{{ key|replace("_", " ")|title }}</label>
32
+
33
+ {% if value is boolean %}
34
+ <div class="checkbox-label">
35
+ <input type="checkbox"
36
+ id="{{ setting_id }}_{{ key }}"
37
+ name="{{ setting.key }}_{{ key }}"
38
+ class="json-property-control"
39
+ data-property="{{ key }}"
40
+ data-parent-key="{{ setting.key }}"
41
+ {% if value %}checked{% endif %}
42
+ {% if not setting.editable %}disabled{% endif %}>
43
+ <span class="checkbox-text">{{ key|replace("_", " ")|title }}</span>
44
+ </div>
45
+ {% elif value is number %}
46
+ <input type="number"
47
+ id="{{ setting_id }}_{{ key }}"
48
+ name="{{ setting.key }}_{{ key }}"
49
+ class="settings-input form-control json-property-control"
50
+ data-property="{{ key }}"
51
+ data-parent-key="{{ setting.key }}"
52
+ value="{{ value }}"
53
+ {% if not setting.editable %}disabled{% endif %}>
54
+ {% elif value is string and value in ["ITERATION", "NONE"] %}
55
+ <select id="{{ setting_id }}_{{ key }}"
56
+ name="{{ setting.key }}_{{ key }}"
57
+ class="settings-select form-control json-property-control"
58
+ data-property="{{ key }}"
59
+ data-parent-key="{{ setting.key }}"
60
+ {% if not setting.editable %}disabled{% endif %}>
61
+ <option value="ITERATION" {% if value == "ITERATION" %}selected{% endif %}>Iteration</option>
62
+ <option value="NONE" {% if value == "NONE" %}selected{% endif %}>None</option>
63
+ </select>
64
+ {% else %}
65
+ <input type="text"
66
+ id="{{ setting_id }}_{{ key }}"
67
+ name="{{ setting.key }}_{{ key }}"
68
+ class="settings-input form-control json-property-control"
69
+ data-property="{{ key }}"
70
+ data-parent-key="{{ setting.key }}"
71
+ value="{{ value }}"
72
+ {% if not setting.editable %}disabled{% endif %}>
73
+ {% endif %}
74
+
75
+ <div class="input-help">{{ key|replace("_", " ")|title }}</div>
76
+ </div>
77
+ {% endfor %}
78
+ </div>
79
+ </div>
80
+ {% else %}
81
+ <textarea
82
+ id="{{ setting_id }}"
83
+ name="{{ setting.key }}"
84
+ class="settings-textarea form-control"
85
+ {% if not setting.editable %}disabled{% endif %}
86
+ >{{ setting.value if setting.value is not none else "" }}</textarea>
87
+ {% endif %}
88
+
89
+ {% elif setting.ui_element == "select" %}
90
+ {% if setting.key == "llm.provider" %}
91
+ {% from "components/custom_dropdown.html" import render_dropdown %}
92
+ {{ render_dropdown(
93
+ input_id=setting.key,
94
+ dropdown_id=setting_id + "-dropdown",
95
+ placeholder="Select a provider",
96
+ label=None,
97
+ help_text=setting.description if setting.description else None,
98
+ allow_custom=False,
99
+ show_refresh=True,
100
+ data_setting_key=setting.key
101
+ ) }}
102
+ {% else %}
103
+ <select
104
+ id="{{ setting_id }}"
105
+ name="{{ setting.key }}"
106
+ class="settings-select form-control"
107
+ {% if not setting.editable %}disabled{% endif %}
108
+ >
109
+ {% for option in setting.options %}
110
+ <option
111
+ value="{{ option.value }}"
112
+ {% if option.value == setting.value %}selected{% endif %}
113
+ >
114
+ {{ option.label if option.label else option.value }}
115
+ </option>
116
+ {% endfor %}
117
+ </select>
118
+ {% endif %}
119
+
120
+ {% elif setting.ui_element == "checkbox" %}
121
+ <div class="checkbox-label">
122
+ <input
123
+ type="checkbox"
124
+ id="{{ setting_id }}"
125
+ name="{{ setting.key }}"
126
+ {% if setting.value == true or setting.value == "true" %}checked{% endif %}
127
+ {% if not setting.editable %}disabled{% endif %}
128
+ >
129
+ <span class="checkbox-text">{{ setting.name }}</span>
130
+ </div>
131
+
132
+ {% elif setting.ui_element == "slider" or setting.ui_element == "range" %}
133
+ {% set min_value = setting.min_value if setting.min_value is not none else 0 %}
134
+ {% set max_value = setting.max_value if setting.max_value is not none else 100 %}
135
+ {% set step = setting.step if setting.step is not none else 1 %}
136
+
137
+ <div class="settings-range-container">
138
+ <input
139
+ type="range"
140
+ id="{{ setting_id }}"
141
+ name="{{ setting.key }}"
142
+ class="settings-range form-control"
143
+ value="{{ setting.value if setting.value is not none else min_value }}"
144
+ min="{{ min_value }}"
145
+ max="{{ max_value }}"
146
+ step="{{ step }}"
147
+ {% if not setting.editable %}disabled{% endif %}
148
+ >
149
+ <span class="settings-range-value" id="{{ setting_id }}-value">{{ setting.value if setting.value is not none else min_value }}</span>
150
+ </div>
151
+
152
+ {% elif setting.ui_element == "number" %}
153
+ {% set min_value = setting.min_value if setting.min_value is not none else "" %}
154
+ {% set max_value = setting.max_value if setting.max_value is not none else "" %}
155
+ {% set step = setting.step if setting.step is not none else 1 %}
156
+
157
+ <input
158
+ type="number"
159
+ id="{{ setting_id }}"
160
+ name="{{ setting.key }}"
161
+ class="settings-input form-control"
162
+ value="{{ setting.value if setting.value is not none else '' }}"
163
+ min="{{ min_value }}"
164
+ max="{{ max_value }}"
165
+ step="{{ step }}"
166
+ {% if not setting.editable %}disabled{% endif %}
167
+ >
168
+
169
+ {% elif setting.ui_element == "password" %}
170
+ <input
171
+ type="password"
172
+ id="{{ setting_id }}"
173
+ name="{{ setting.key }}"
174
+ class="settings-input form-control"
175
+ value="{{ setting.value if setting.value is not none else '' }}"
176
+ {% if not setting.editable %}disabled{% endif %}
177
+ >
178
+
179
+ {% elif setting.key == "llm.model" or setting.key == "search.tool" %}
180
+ {% from "components/custom_dropdown.html" import render_dropdown %}
181
+ {{ render_dropdown(
182
+ input_id=setting.key,
183
+ dropdown_id=setting_id + "-dropdown",
184
+ placeholder="Select or enter a value",
185
+ label=None,
186
+ help_text=setting.description if setting.description else None,
187
+ allow_custom=setting.key == "llm.model",
188
+ show_refresh=True,
189
+ refresh_aria_label="Refresh model list" if setting.key == "llm.model" else "Refresh search engine list",
190
+ data_setting_key=setting.key
191
+ ) }}
192
+
193
+ {% else %}
194
+ {% if setting.value is mapping or (setting.value is string and (setting.value.startswith('{') and setting.value.endswith('}'))) %}
195
+ <div class="json-expanded-controls">
196
+ {% if setting.value is string %}
197
+ {% set json_value = setting.value|tojson %}
198
+ {% else %}
199
+ {% set json_value = setting.value %}
200
+ {% endif %}
201
+
202
+ {# Store the original JSON in a hidden field #}
203
+ <input type="hidden" id="{{ setting_id }}_original" name="{{ setting.key }}_original" value="{{ setting.value|tojson }}">
204
+
205
+ {# Create individual form controls for each JSON property #}
206
+ <div class="json-property-controls">
207
+ {% for key, value in json_value.items() %}
208
+ <div class="json-property-item">
209
+ <label for="{{ setting_id }}_{{ key }}">{{ key|replace("_", " ")|title }}</label>
210
+
211
+ {% if value is boolean %}
212
+ <div class="checkbox-label">
213
+ <input type="checkbox"
214
+ id="{{ setting_id }}_{{ key }}"
215
+ name="{{ setting.key }}_{{ key }}"
216
+ class="json-property-control"
217
+ data-property="{{ key }}"
218
+ data-parent-key="{{ setting.key }}"
219
+ {% if value %}checked{% endif %}
220
+ {% if not setting.editable %}disabled{% endif %}>
221
+ <span class="checkbox-text">{{ key|replace("_", " ")|title }}</span>
222
+ </div>
223
+ {% elif value is number %}
224
+ <input type="number"
225
+ id="{{ setting_id }}_{{ key }}"
226
+ name="{{ setting.key }}_{{ key }}"
227
+ class="settings-input form-control json-property-control"
228
+ data-property="{{ key }}"
229
+ data-parent-key="{{ setting.key }}"
230
+ value="{{ value }}"
231
+ {% if not setting.editable %}disabled{% endif %}>
232
+ {% else %}
233
+ <input type="text"
234
+ id="{{ setting_id }}_{{ key }}"
235
+ name="{{ setting.key }}_{{ key }}"
236
+ class="settings-input form-control json-property-control"
237
+ data-property="{{ key }}"
238
+ data-parent-key="{{ setting.key }}"
239
+ value="{{ value }}"
240
+ {% if not setting.editable %}disabled{% endif %}>
241
+ {% endif %}
242
+
243
+ <div class="input-help">{{ key|replace("_", " ")|title }}</div>
244
+ </div>
245
+ {% endfor %}
246
+ </div>
247
+ </div>
248
+ {% else %}
249
+ <input
250
+ type="text"
251
+ id="{{ setting_id }}"
252
+ name="{{ setting.key }}"
253
+ class="settings-input form-control"
254
+ value="{{ setting.value if setting.value is not none else '' }}"
255
+ {% if not setting.editable %}disabled{% endif %}
256
+ >
257
+ {% endif %}
258
+ {% endif %}
259
+
260
+ {% if setting.description and setting.key != "llm.model" and setting.key != "search.tool" and setting.key != "llm.provider" %}
261
+ <div class="input-help">{{ setting.description }}</div>
262
+ {% endif %}
263
+ </div>
264
+ {% endmacro %}
265
+
266
+ {% macro render_settings_section(section_title, section_id, settings, form_id='settings-form') %}
267
+ <div class="settings-section">
268
+ <div class="settings-section-header" data-target="{{ section_id }}">
269
+ <div class="settings-section-title">
270
+ {{ section_title }}
271
+ </div>
272
+ <div class="settings-toggle-icon">
273
+ <i class="fas fa-chevron-down"></i>
274
+ </div>
275
+ </div>
276
+ <div id="{{ section_id }}" class="settings-section-body">
277
+ {% for setting in settings %}
278
+ {{ render_setting(setting, form_id) }}
279
+ {% endfor %}
280
+ </div>
281
+ </div>
282
+ {% endmacro %}
283
+
284
+ {% macro render_settings_form(settings_by_category, form_id, form_action) %}
285
+ <form id="{{ form_id }}" action="{{ form_action }}" method="POST" class="settings-form">
286
+ {% for category, settings in settings_by_category.items() %}
287
+ {{ render_settings_section(category, category|lower|replace(' ', '-'), settings, form_id) }}
288
+ {% endfor %}
289
+
290
+ <div class="form-actions">
291
+ <button type="reset" class="btn btn-outline">
292
+ <i class="fas fa-undo"></i> Reset Changes
293
+ </button>
294
+ <button type="submit" class="btn btn-primary">
295
+ <i class="fas fa-save"></i> Save Changes
296
+ </button>
297
+ </div>
298
+ </form>
299
+ {% endmacro %}
@@ -0,0 +1,21 @@
1
+ <aside class="sidebar">
2
+ <div class="sidebar-header">
3
+ <h2 id="logo-link" style="cursor: pointer;"><i class="fas fa-atom"></i> Deep Research</h2>
4
+ </div>
5
+ <nav class="sidebar-nav">
6
+ <ul>
7
+ <li {% if active_page == 'new-research' %}class="active"{% endif %} data-page="new-research">
8
+ <a href="{{ url_for('research.index') }}"><i class="fas fa-search"></i> New Research</a>
9
+ </li>
10
+ <li {% if active_page == 'history' %}class="active"{% endif %} data-page="history">
11
+ <a href="{{ url_for('research.history_page') }}"><i class="fas fa-history"></i> History</a>
12
+ </li>
13
+ <li {% if active_page == 'settings' %}class="active"{% endif %} data-page="settings">
14
+ <a href="{{ url_for('research.settings_page') }}"><i class="fas fa-cog"></i> Settings</a>
15
+ </li>
16
+ </ul>
17
+ </nav>
18
+ <div class="sidebar-footer">
19
+ <p>v0.2.0 | <i class="fas fa-brain"></i></p>
20
+ </div>
21
+ </aside>
@@ -0,0 +1,73 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Research Details - Deep Research System{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="page active" id="research-details">
7
+ <div class="page-header">
8
+ <div class="results-header">
9
+ <h1>Research Details</h1>
10
+ <div class="results-actions">
11
+ <button class="btn btn-outline" id="back-to-history-from-details"><i class="fas fa-arrow-left"></i> Back to History</button>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ <div class="card">
16
+ <div class="card-content">
17
+ <div class="research-metadata">
18
+ <div class="metadata-item">
19
+ <span class="metadata-label">Query:</span>
20
+ <span id="detail-query" class="metadata-value"></span>
21
+ </div>
22
+ <div class="metadata-item">
23
+ <span class="metadata-label">Status:</span>
24
+ <span id="detail-status" class="metadata-value"></span>
25
+ </div>
26
+ <div class="metadata-item">
27
+ <span class="metadata-label">Mode:</span>
28
+ <span id="detail-mode" class="metadata-value"></span>
29
+ </div>
30
+ <div class="metadata-item">
31
+ <span class="metadata-label">Progress:</span>
32
+ <div class="detail-progress-container">
33
+ <div class="detail-progress-bar">
34
+ <div class="detail-progress-fill" id="detail-progress-fill"></div>
35
+ </div>
36
+ <span id="detail-progress-percentage">0%</span>
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <div class="research-log-container">
42
+ <h3>Research Progress Log</h3>
43
+ <div class="research-log" id="research-log">
44
+ <!-- Will be populated dynamically -->
45
+ <div class="loading-spinner centered">
46
+ <div class="spinner"></div>
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="detail-actions" id="detail-actions">
52
+ <!-- Conditionally shown based on research status -->
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ {% endblock %}
58
+
59
+ {% block templates %}
60
+ <template id="log-entry-template">
61
+ <div class="log-entry">
62
+ <div class="log-entry-time"></div>
63
+ <div class="log-entry-content">
64
+ <div class="log-entry-message"></div>
65
+ <div class="log-entry-progress"></div>
66
+ </div>
67
+ </div>
68
+ </template>
69
+ {% endblock %}
70
+
71
+ {% block page_scripts %}
72
+ <script src="{{ url_for('research.serve_static', path='js/components/details.js') }}"></script>
73
+ {% endblock %}
@@ -0,0 +1,51 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% set active_page = 'history' %}
4
+
5
+ {% block title %}Research History - Deep Research System{% endblock %}
6
+
7
+ {% block styles %}
8
+ {{ super() }}
9
+ <link rel="stylesheet" href="{{ url_for('research.serve_static', path='css/components/history.css') }}">
10
+ {% endblock %}
11
+
12
+ {% block content %}
13
+ <div class="page active" id="history">
14
+ <div class="page-header">
15
+ <h1>Research History</h1>
16
+ </div>
17
+ <div class="card">
18
+ <div class="card-content">
19
+ <div class="search-controls" style="margin-bottom: 1rem;">
20
+ <input type="text" id="history-search" placeholder="Search history..." class="search-input">
21
+ <button id="clear-history-btn" class="btn btn-danger" style="display: none;">
22
+ <i class="fas fa-trash-alt"></i> Clear All
23
+ </button>
24
+ </div>
25
+ <div class="history-list" id="history-items">
26
+ <!-- Will be populated dynamically -->
27
+ <div class="loading-spinner centered">
28
+ <div class="spinner"></div>
29
+ </div>
30
+ </div>
31
+ <div id="history-empty-message" class="empty-state" style="display: none;">
32
+ <i class="fas fa-history empty-icon"></i>
33
+ <p>No research history found.</p>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ {% endblock %}
39
+
40
+ {% block templates %}
41
+ <!-- Template is no longer needed since we build items dynamically in JavaScript -->
42
+ {% endblock %}
43
+
44
+ {% block page_scripts %}
45
+ <!-- Load utilities first -->
46
+ <script src="{{ url_for('research.serve_static', path='js/services/ui.js') }}"></script>
47
+ <script src="{{ url_for('research.serve_static', path='js/services/formatting.js') }}"></script>
48
+ <script src="{{ url_for('research.serve_static', path='js/services/api.js') }}"></script>
49
+ <!-- Then load the component -->
50
+ <script src="{{ url_for('research.serve_static', path='js/components/history.js') }}"></script>
51
+ {% endblock %}
@@ -0,0 +1,57 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Research in Progress - Deep Research System{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="page active" id="research-progress">
7
+ <div class="page-header">
8
+ <h1>Research in Progress</h1>
9
+ </div>
10
+ <div class="card">
11
+ <div class="card-content">
12
+ <div class="progress-info">
13
+ <div class="current-query-container">
14
+ <div class="current-query-label">Current Query:</div>
15
+ <div id="current-query" class="current-query"></div>
16
+ </div>
17
+ <div class="progress-container">
18
+ <div class="progress-bar">
19
+ <div id="progress-bar" class="progress-fill"></div>
20
+ </div>
21
+ <div id="progress-percentage" class="progress-percentage">0%</div>
22
+ </div>
23
+ <div class="status-container">
24
+ <div class="status-label">Status:</div>
25
+ <div id="status-text" class="status-indicator">Initializing</div>
26
+ </div>
27
+ <div class="task-container">
28
+ <div class="task-label">Current Task:</div>
29
+ <div id="current-task" class="task-text">Starting research...</div>
30
+ </div>
31
+ <div class="progress-actions">
32
+ <button id="cancel-research-btn" class="btn btn-outline terminate-btn">
33
+ <i class="fas fa-stop-circle"></i> Cancel Research
34
+ </button>
35
+ <a id="view-results-btn" class="btn btn-primary" style="display: none;">
36
+ <i class="fas fa-eye"></i> View Results
37
+ </a>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ {% include "components/log_panel.html" %}
44
+ </div>
45
+ {% endblock %}
46
+
47
+ {% block page_scripts %}
48
+ <!-- Load required services -->
49
+ <script src="{{ url_for('research.serve_static', path='js/services/audio.js') }}"></script>
50
+ <script src="{{ url_for('research.serve_static', path='js/services/ui.js') }}"></script>
51
+ <script src="{{ url_for('research.serve_static', path='js/services/formatting.js') }}"></script>
52
+ <script src="{{ url_for('research.serve_static', path='js/services/api.js') }}"></script>
53
+ <script src="{{ url_for('research.serve_static', path='js/services/socket.js') }}"></script>
54
+
55
+ <!-- Then load the component -->
56
+ <script src="{{ url_for('research.serve_static', path='js/components/progress.js') }}"></script>
57
+ {% endblock %}