scitex 2.14.0__py3-none-any.whl → 2.15.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 (300) hide show
  1. scitex/__init__.py +71 -17
  2. scitex/_env_loader.py +156 -0
  3. scitex/_mcp_resources/__init__.py +37 -0
  4. scitex/_mcp_resources/_cheatsheet.py +135 -0
  5. scitex/_mcp_resources/_figrecipe.py +138 -0
  6. scitex/_mcp_resources/_formats.py +102 -0
  7. scitex/_mcp_resources/_modules.py +337 -0
  8. scitex/_mcp_resources/_session.py +149 -0
  9. scitex/_mcp_tools/__init__.py +4 -0
  10. scitex/_mcp_tools/audio.py +66 -0
  11. scitex/_mcp_tools/diagram.py +11 -95
  12. scitex/_mcp_tools/introspect.py +210 -0
  13. scitex/_mcp_tools/plt.py +260 -305
  14. scitex/_mcp_tools/scholar.py +74 -0
  15. scitex/_mcp_tools/social.py +244 -0
  16. scitex/_mcp_tools/template.py +24 -0
  17. scitex/_mcp_tools/writer.py +21 -204
  18. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  19. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  20. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  21. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  22. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  23. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  24. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  25. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  26. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  27. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  28. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
  29. scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
  30. scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
  31. scitex/audio/README.md +40 -36
  32. scitex/audio/__init__.py +129 -61
  33. scitex/audio/_branding.py +185 -0
  34. scitex/audio/_mcp/__init__.py +32 -0
  35. scitex/audio/_mcp/handlers.py +59 -6
  36. scitex/audio/_mcp/speak_handlers.py +238 -0
  37. scitex/audio/_relay.py +225 -0
  38. scitex/audio/_tts.py +18 -10
  39. scitex/audio/engines/base.py +17 -10
  40. scitex/audio/engines/elevenlabs_engine.py +7 -2
  41. scitex/audio/mcp_server.py +228 -75
  42. scitex/canvas/README.md +1 -1
  43. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  44. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  45. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  46. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  47. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  48. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  49. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  50. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  51. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  52. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  53. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  54. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  55. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  56. scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
  57. scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
  58. scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
  59. scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
  60. scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
  61. scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
  62. scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
  63. scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
  64. scitex/canvas/editor/flask_editor/_core.py +25 -1684
  65. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  66. scitex/cli/__init__.py +38 -43
  67. scitex/cli/audio.py +76 -27
  68. scitex/cli/capture.py +13 -20
  69. scitex/cli/introspect.py +481 -0
  70. scitex/cli/main.py +200 -109
  71. scitex/cli/mcp.py +60 -34
  72. scitex/cli/plt.py +357 -0
  73. scitex/cli/repro.py +15 -8
  74. scitex/cli/resource.py +15 -8
  75. scitex/cli/scholar/__init__.py +23 -8
  76. scitex/cli/scholar/_crossref_scitex.py +296 -0
  77. scitex/cli/scholar/_fetch.py +25 -3
  78. scitex/cli/social.py +314 -0
  79. scitex/cli/stats.py +15 -8
  80. scitex/cli/template.py +129 -12
  81. scitex/cli/tex.py +15 -8
  82. scitex/cli/writer.py +132 -8
  83. scitex/cloud/__init__.py +41 -2
  84. scitex/config/README.md +1 -1
  85. scitex/config/__init__.py +16 -2
  86. scitex/config/_env_registry.py +256 -0
  87. scitex/context/__init__.py +22 -0
  88. scitex/dev/__init__.py +20 -1
  89. scitex/diagram/__init__.py +42 -19
  90. scitex/diagram/mcp_server.py +13 -125
  91. scitex/gen/__init__.py +50 -14
  92. scitex/gen/_list_packages.py +4 -4
  93. scitex/introspect/__init__.py +82 -0
  94. scitex/introspect/_call_graph.py +303 -0
  95. scitex/introspect/_class_hierarchy.py +163 -0
  96. scitex/introspect/_core.py +41 -0
  97. scitex/introspect/_docstring.py +131 -0
  98. scitex/introspect/_examples.py +113 -0
  99. scitex/introspect/_imports.py +271 -0
  100. scitex/{gen/_inspect_module.py → introspect/_list_api.py} +43 -54
  101. scitex/introspect/_mcp/__init__.py +41 -0
  102. scitex/introspect/_mcp/handlers.py +233 -0
  103. scitex/introspect/_members.py +155 -0
  104. scitex/introspect/_resolve.py +89 -0
  105. scitex/introspect/_signature.py +131 -0
  106. scitex/introspect/_source.py +80 -0
  107. scitex/introspect/_type_hints.py +172 -0
  108. scitex/io/_save.py +1 -2
  109. scitex/io/bundle/README.md +1 -1
  110. scitex/logging/_formatters.py +19 -9
  111. scitex/mcp_server.py +98 -5
  112. scitex/os/__init__.py +4 -0
  113. scitex/{gen → os}/_check_host.py +4 -5
  114. scitex/plt/__init__.py +245 -550
  115. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  116. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  117. scitex/plt/gallery/README.md +1 -1
  118. scitex/plt/utils/_hitmap/__init__.py +82 -0
  119. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  120. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  121. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  122. scitex/plt/utils/_hitmap/_constants.py +40 -0
  123. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  124. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  125. scitex/plt/utils/_hitmap/_query.py +113 -0
  126. scitex/plt/utils/_hitmap.py +46 -1616
  127. scitex/plt/utils/_metadata/__init__.py +80 -0
  128. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  129. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  130. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  131. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  132. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  133. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  134. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  135. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  136. scitex/plt/utils/_metadata/_csv.py +416 -0
  137. scitex/plt/utils/_metadata/_detect.py +225 -0
  138. scitex/plt/utils/_metadata/_legend.py +127 -0
  139. scitex/plt/utils/_metadata/_rounding.py +117 -0
  140. scitex/plt/utils/_metadata/_verification.py +202 -0
  141. scitex/schema/README.md +1 -1
  142. scitex/scholar/__init__.py +8 -0
  143. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  144. scitex/scholar/core/Scholar.py +63 -1700
  145. scitex/scholar/core/_mixins/__init__.py +36 -0
  146. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  147. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  148. scitex/scholar/core/_mixins/_loaders.py +103 -0
  149. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  150. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  151. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  152. scitex/scholar/core/_mixins/_savers.py +69 -0
  153. scitex/scholar/core/_mixins/_search.py +103 -0
  154. scitex/scholar/core/_mixins/_services.py +88 -0
  155. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  156. scitex/scholar/crossref_scitex.py +367 -0
  157. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  158. scitex/scholar/examples/00_run_all.sh +120 -0
  159. scitex/scholar/jobs/_executors.py +27 -3
  160. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  161. scitex/scholar/pdf_download/_cli.py +154 -0
  162. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  163. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  164. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  165. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  166. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  167. scitex/scholar/pipelines/_single_steps.py +71 -36
  168. scitex/scholar/storage/_LibraryManager.py +97 -1695
  169. scitex/scholar/storage/_mixins/__init__.py +30 -0
  170. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  171. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  172. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  173. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  174. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  175. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  176. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  177. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  178. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  179. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  180. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  181. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  182. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  183. scitex/security/README.md +3 -3
  184. scitex/session/README.md +1 -1
  185. scitex/session/__init__.py +26 -7
  186. scitex/session/_decorator.py +1 -1
  187. scitex/sh/README.md +1 -1
  188. scitex/sh/__init__.py +7 -4
  189. scitex/social/__init__.py +155 -0
  190. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  191. scitex/stats/_mcp/_handlers/__init__.py +31 -0
  192. scitex/stats/_mcp/_handlers/_corrections.py +113 -0
  193. scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
  194. scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
  195. scitex/stats/_mcp/_handlers/_format.py +94 -0
  196. scitex/stats/_mcp/_handlers/_normality.py +110 -0
  197. scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
  198. scitex/stats/_mcp/_handlers/_power.py +247 -0
  199. scitex/stats/_mcp/_handlers/_recommend.py +102 -0
  200. scitex/stats/_mcp/_handlers/_run_test.py +279 -0
  201. scitex/stats/_mcp/_handlers/_stars.py +48 -0
  202. scitex/stats/_mcp/handlers.py +19 -1171
  203. scitex/stats/auto/_stat_style.py +175 -0
  204. scitex/stats/auto/_style_definitions.py +411 -0
  205. scitex/stats/auto/_styles.py +22 -620
  206. scitex/stats/descriptive/__init__.py +11 -8
  207. scitex/stats/descriptive/_ci.py +39 -0
  208. scitex/stats/power/_power.py +15 -4
  209. scitex/str/__init__.py +2 -1
  210. scitex/str/_title_case.py +63 -0
  211. scitex/template/README.md +1 -1
  212. scitex/template/__init__.py +25 -10
  213. scitex/template/_code_templates.py +147 -0
  214. scitex/template/_mcp/handlers.py +81 -0
  215. scitex/template/_mcp/tool_schemas.py +55 -0
  216. scitex/template/_templates/__init__.py +51 -0
  217. scitex/template/_templates/audio.py +233 -0
  218. scitex/template/_templates/canvas.py +312 -0
  219. scitex/template/_templates/capture.py +268 -0
  220. scitex/template/_templates/config.py +43 -0
  221. scitex/template/_templates/diagram.py +294 -0
  222. scitex/template/_templates/io.py +107 -0
  223. scitex/template/_templates/module.py +53 -0
  224. scitex/template/_templates/plt.py +202 -0
  225. scitex/template/_templates/scholar.py +267 -0
  226. scitex/template/_templates/session.py +130 -0
  227. scitex/template/_templates/session_minimal.py +43 -0
  228. scitex/template/_templates/session_plot.py +67 -0
  229. scitex/template/_templates/session_stats.py +77 -0
  230. scitex/template/_templates/stats.py +323 -0
  231. scitex/template/_templates/writer.py +296 -0
  232. scitex/template/clone_writer_directory.py +5 -5
  233. scitex/ui/_backends/_email.py +10 -2
  234. scitex/ui/_backends/_webhook.py +5 -1
  235. scitex/web/_search_pubmed.py +10 -6
  236. scitex/writer/README.md +1 -1
  237. scitex/writer/_mcp/handlers.py +11 -744
  238. scitex/writer/_mcp/tool_schemas.py +5 -335
  239. scitex-2.15.2.dist-info/METADATA +648 -0
  240. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/RECORD +246 -150
  241. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  242. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  243. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  244. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  245. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  246. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  247. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  248. scitex/diagram/_compile.py +0 -312
  249. scitex/diagram/_diagram.py +0 -355
  250. scitex/diagram/_mcp/__init__.py +0 -4
  251. scitex/diagram/_mcp/handlers.py +0 -400
  252. scitex/diagram/_mcp/tool_schemas.py +0 -157
  253. scitex/diagram/_presets.py +0 -173
  254. scitex/diagram/_schema.py +0 -182
  255. scitex/diagram/_split.py +0 -278
  256. scitex/gen/_ci.py +0 -12
  257. scitex/gen/_title_case.py +0 -89
  258. scitex/plt/_mcp/__init__.py +0 -4
  259. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  260. scitex/plt/_mcp/_handlers_figure.py +0 -195
  261. scitex/plt/_mcp/_handlers_plot.py +0 -252
  262. scitex/plt/_mcp/_handlers_style.py +0 -219
  263. scitex/plt/_mcp/handlers.py +0 -74
  264. scitex/plt/_mcp/tool_schemas.py +0 -497
  265. scitex/plt/mcp_server.py +0 -231
  266. scitex/scholar/data/.gitkeep +0 -0
  267. scitex/scholar/data/README.md +0 -44
  268. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  269. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  270. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  271. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  272. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  273. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  274. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  275. scitex/scholar/data/bib_files/pac.bib +0 -698
  276. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  277. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  278. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  279. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  280. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  281. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  282. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  283. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  284. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  285. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  286. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  287. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  288. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  289. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  290. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  291. scitex/scholar/data/impact_factor.db +0 -0
  292. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  293. scitex/scholar/examples/dev.py +0 -38
  294. scitex-2.14.0.dist-info/METADATA +0 -1238
  295. /scitex/{gen → context}/_detect_environment.py +0 -0
  296. /scitex/{gen → context}/_get_notebook_path.py +0 -0
  297. /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
  298. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/WHEEL +0 -0
  299. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/entry_points.txt +0 -0
  300. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,35 +1,20 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # File: ./src/scitex/vis/editor/flask_editor/templates/__init__.py
4
3
  """Template components for Flask editor.
5
4
 
6
- Supports two modes:
7
- - Static files mode (default): Uses external CSS/JS files from static/
8
- - Inline mode (fallback): Embeds CSS/JS directly in HTML
5
+ Uses external CSS/JS files from static/ directory.
9
6
  """
10
7
 
11
8
  from ._html import HTML_BODY
12
9
 
13
- # Configuration flag - set to False to use inline mode for debugging
14
- USE_STATIC_FILES = True
15
10
 
16
-
17
- def build_html_template(use_static: bool = None) -> str:
18
- """Build the complete HTML template from components.
19
-
20
- Args:
21
- use_static: Override static file usage. If None, uses USE_STATIC_FILES.
11
+ def build_html_template() -> str:
12
+ """Build the complete HTML template.
22
13
 
23
14
  Returns:
24
15
  Complete HTML template string.
25
16
  """
26
- if use_static is None:
27
- use_static = USE_STATIC_FILES
28
-
29
- if use_static:
30
- return _build_static_template()
31
- else:
32
- return _build_inline_template()
17
+ return _build_static_template()
33
18
 
34
19
 
35
20
  def _build_static_template() -> str:
@@ -37,42 +22,44 @@ def _build_static_template() -> str:
37
22
  # Get list of JS files in correct load order
38
23
  js_files = [
39
24
  # Dev tools (load first to capture console logs)
40
- 'js/dev/element-inspector.js',
25
+ "js/dev/element-inspector.js",
41
26
  # Core modules first (dependencies)
42
- 'js/core/state.js',
43
- 'js/core/utils.js',
44
- 'js/core/api.js',
27
+ "js/core/state.js",
28
+ "js/core/utils.js",
29
+ "js/core/api.js",
45
30
  # Editor modules
46
- 'js/editor/bbox.js',
47
- 'js/editor/overlay.js',
48
- 'js/editor/preview.js',
49
- 'js/editor/element-drag.js',
31
+ "js/editor/bbox.js",
32
+ "js/editor/overlay.js",
33
+ "js/editor/preview.js",
34
+ "js/editor/element-drag.js",
50
35
  # Canvas modules
51
- 'js/canvas/selection.js',
52
- 'js/canvas/resize.js',
53
- 'js/canvas/dragging.js',
54
- 'js/canvas/canvas.js',
36
+ "js/canvas/selection.js",
37
+ "js/canvas/resize.js",
38
+ "js/canvas/dragging.js",
39
+ "js/canvas/canvas.js",
55
40
  # Alignment modules
56
- 'js/alignment/basic.js',
57
- 'js/alignment/axis.js',
58
- 'js/alignment/distribute.js',
41
+ "js/alignment/basic.js",
42
+ "js/alignment/axis.js",
43
+ "js/alignment/distribute.js",
59
44
  # UI modules
60
- 'js/ui/theme.js',
61
- 'js/ui/help.js',
62
- 'js/ui/download.js',
63
- 'js/ui/controls.js',
45
+ "js/ui/theme.js",
46
+ "js/ui/help.js",
47
+ "js/ui/download.js",
48
+ "js/ui/controls.js",
64
49
  # Shortcuts
65
- 'js/shortcuts/context-menu.js',
66
- 'js/shortcuts/keyboard.js',
50
+ "js/shortcuts/context-menu.js",
51
+ "js/shortcuts/keyboard.js",
67
52
  # Main entry (last)
68
- 'js/main.js',
53
+ "js/main.js",
69
54
  ]
70
55
 
71
56
  # Generate script tags
72
- script_tags = '\n '.join([
73
- f'<script src="{{{{ url_for(\'static\', filename=\'{f}\') }}}}"></script>'
74
- for f in js_files
75
- ])
57
+ script_tags = "\n ".join(
58
+ [
59
+ f"<script src=\"{{{{ url_for('static', filename='{f}') }}}}\"></script>"
60
+ for f in js_files
61
+ ]
62
+ )
76
63
 
77
64
  return f"""<!DOCTYPE html>
78
65
  <html lang="en" data-theme="dark">
@@ -95,29 +82,4 @@ def _build_static_template() -> str:
95
82
  """
96
83
 
97
84
 
98
- def _build_inline_template() -> str:
99
- """Build template with inline CSS/JS (fallback mode)."""
100
- from ._styles import CSS_STYLES
101
- from ._scripts import JS_SCRIPTS
102
-
103
- return f"""<!DOCTYPE html>
104
- <html lang="en" data-theme="dark">
105
- <head>
106
- <meta charset="UTF-8">
107
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
- <title>SciTeX Figure Editor - {{{{ filename }}}}</title>
109
- <style>
110
- {CSS_STYLES}
111
- </style>
112
- </head>
113
- <body>
114
- {HTML_BODY}
115
- <script>
116
- {JS_SCRIPTS}
117
- </script>
118
- </body>
119
- </html>
120
- """
121
-
122
-
123
85
  # EOF
scitex/cli/__init__.py CHANGED
@@ -16,49 +16,44 @@ import click
16
16
  from .main import cli
17
17
 
18
18
 
19
- def add_help_recursive(group: click.Group, parent_name: str = "scitex") -> None:
20
- """Add help-recursive command to a click group.
19
+ def print_help_recursive(ctx, group: click.Group) -> None:
20
+ """Print help for a group and all its subcommands.
21
21
 
22
22
  Args:
23
- group: The click group to add the command to
24
- parent_name: The parent command name for display (e.g., "scitex writer")
23
+ ctx: The click context
24
+ group: The click group to print help for
25
25
  """
26
-
27
- @group.command("help-recursive")
28
- @click.pass_context
29
- def help_recursive(ctx):
30
- """Show help for all commands recursively."""
31
- # Create a fake parent context to show correct command path in Usage
32
- fake_parent = click.Context(click.Group(), info_name="scitex")
33
- parent_ctx = click.Context(group, info_name=group.name, parent=fake_parent)
34
-
35
- click.secho(f"━━━ scitex {group.name} ━━━", fg="cyan", bold=True)
36
- click.echo(group.get_help(parent_ctx))
37
-
38
- for name in sorted(group.list_commands(ctx) or []):
39
- cmd = group.get_command(ctx, name)
40
- if cmd is None or name == "help-recursive":
41
- continue
42
- click.echo()
43
- click.secho(f"━━━ scitex {group.name} {name} ━━━", fg="cyan", bold=True)
44
- with click.Context(cmd, info_name=name, parent=parent_ctx) as sub_ctx:
45
- click.echo(cmd.get_help(sub_ctx))
46
- # Handle nested subgroups
47
- if isinstance(cmd, click.Group):
48
- for sub_name in sorted(cmd.list_commands(sub_ctx) or []):
49
- sub_cmd = cmd.get_command(sub_ctx, sub_name)
50
- if sub_cmd is None:
51
- continue
52
- click.echo()
53
- click.secho(
54
- f"━━━ scitex {group.name} {name} {sub_name} ━━━",
55
- fg="cyan",
56
- bold=True,
57
- )
58
- with click.Context(
59
- sub_cmd, info_name=sub_name, parent=sub_ctx
60
- ) as sub_sub_ctx:
61
- click.echo(sub_cmd.get_help(sub_sub_ctx))
62
-
63
-
64
- __all__ = ["cli", "add_help_recursive"]
26
+ # Create a fake parent context to show correct command path in Usage
27
+ fake_parent = click.Context(click.Group(), info_name="scitex")
28
+ parent_ctx = click.Context(group, info_name=group.name, parent=fake_parent)
29
+
30
+ click.secho(f"━━━ scitex {group.name} ━━━", fg="cyan", bold=True)
31
+ click.echo(group.get_help(parent_ctx))
32
+
33
+ for name in sorted(group.list_commands(ctx) or []):
34
+ cmd = group.get_command(ctx, name)
35
+ if cmd is None:
36
+ continue
37
+ click.echo()
38
+ click.secho(f"━━━ scitex {group.name} {name} ━━━", fg="cyan", bold=True)
39
+ with click.Context(cmd, info_name=name, parent=parent_ctx) as sub_ctx:
40
+ click.echo(cmd.get_help(sub_ctx))
41
+ # Handle nested subgroups
42
+ if isinstance(cmd, click.Group):
43
+ for sub_name in sorted(cmd.list_commands(sub_ctx) or []):
44
+ sub_cmd = cmd.get_command(sub_ctx, sub_name)
45
+ if sub_cmd is None:
46
+ continue
47
+ click.echo()
48
+ click.secho(
49
+ f"━━━ scitex {group.name} {name} {sub_name} ━━━",
50
+ fg="cyan",
51
+ bold=True,
52
+ )
53
+ with click.Context(
54
+ sub_cmd, info_name=sub_name, parent=sub_ctx
55
+ ) as sub_sub_ctx:
56
+ click.echo(sub_cmd.get_help(sub_sub_ctx))
57
+
58
+
59
+ __all__ = ["cli", "print_help_recursive"]
scitex/cli/audio.py CHANGED
@@ -10,8 +10,13 @@ import sys
10
10
  import click
11
11
 
12
12
 
13
- @click.group(context_settings={"help_option_names": ["-h", "--help"]})
14
- def audio():
13
+ @click.group(
14
+ context_settings={"help_option_names": ["-h", "--help"]},
15
+ invoke_without_command=True,
16
+ )
17
+ @click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
18
+ @click.pass_context
19
+ def audio(ctx, help_recursive):
15
20
  """
16
21
  Text-to-speech utilities
17
22
 
@@ -28,25 +33,13 @@ def audio():
28
33
  scitex audio backends # List available backends
29
34
  scitex audio check # Check audio status (WSL)
30
35
  """
31
- pass
32
-
36
+ if help_recursive:
37
+ from . import print_help_recursive
33
38
 
34
- @audio.command("help-recursive")
35
- @click.pass_context
36
- def help_recursive(ctx):
37
- """Show help for all commands recursively."""
38
- fake_parent = click.Context(click.Group(), info_name="scitex")
39
- parent_ctx = click.Context(audio, info_name="audio", parent=fake_parent)
40
- click.secho("━━━ scitex audio ━━━", fg="cyan", bold=True)
41
- click.echo(audio.get_help(parent_ctx))
42
- for name in sorted(audio.list_commands(ctx) or []):
43
- cmd = audio.get_command(ctx, name)
44
- if cmd is None or name == "help-recursive":
45
- continue
46
- click.echo()
47
- click.secho(f"━━━ scitex audio {name} ━━━", fg="cyan", bold=True)
48
- with click.Context(cmd, info_name=name, parent=parent_ctx) as sub_ctx:
49
- click.echo(cmd.get_help(sub_ctx))
39
+ print_help_recursive(ctx, audio)
40
+ ctx.exit(0)
41
+ elif ctx.invoked_subcommand is None:
42
+ click.echo(ctx.get_help())
50
43
 
51
44
 
52
45
  @audio.command()
@@ -262,9 +255,9 @@ def stop():
262
255
  )
263
256
  @click.option(
264
257
  "--port",
265
- default=8084,
258
+ default=31293,
266
259
  type=int,
267
- help="Port for HTTP/SSE transport (default: 8084)",
260
+ help="Port for HTTP/SSE transport (default: 31293)",
268
261
  )
269
262
  def serve(transport, host, port):
270
263
  """
@@ -284,18 +277,18 @@ def serve(transport, host, port):
284
277
  scitex audio serve
285
278
 
286
279
  # HTTP server for remote agents
287
- scitex audio serve -t http --port 8084
280
+ scitex audio serve -t http --port 31293
288
281
 
289
282
  # SSE server
290
- scitex audio serve -t sse --port 8084
283
+ scitex audio serve -t sse --port 31293
291
284
 
292
285
  \b
293
286
  Remote Setup:
294
- 1. Local: scitex audio serve -t http --port 8084
287
+ 1. Local: scitex audio serve -t http --port 31293
295
288
  2. SSH: Add to ~/.ssh/config:
296
- LocalForward 8084 127.0.0.1:8084
289
+ LocalForward 31293 127.0.0.1:31293
297
290
  3. Remote MCP config:
298
- {"type": "sse", "url": "http://localhost:8084/sse"}
291
+ {"type": "sse", "url": "http://localhost:31293/sse"}
299
292
  """
300
293
  try:
301
294
  from scitex.audio.mcp_server import FASTMCP_AVAILABLE, run_server
@@ -327,5 +320,61 @@ def serve(transport, host, port):
327
320
  sys.exit(1)
328
321
 
329
322
 
323
+ @audio.command()
324
+ @click.option(
325
+ "--host",
326
+ default="0.0.0.0",
327
+ help="Host to bind (default: 0.0.0.0)",
328
+ )
329
+ @click.option(
330
+ "--port",
331
+ default=31293,
332
+ type=int,
333
+ help="Port to bind (default: 31293)",
334
+ )
335
+ def relay(host, port):
336
+ """
337
+ Run simple HTTP relay server for remote audio playback
338
+
339
+ Unlike 'serve' (MCP server), this exposes simple REST endpoints
340
+ that remote agents can POST to for audio playback.
341
+
342
+ \b
343
+ Endpoints:
344
+ POST /speak - Play text-to-speech
345
+ GET /health - Health check
346
+ GET /list_backends - List available backends
347
+
348
+ \b
349
+ Example:
350
+ # On your local machine (where you want audio)
351
+ scitex audio relay --port 31293
352
+
353
+ # On remote server, set env var
354
+ export SCITEX_AUDIO_RELAY_URL=http://YOUR_LOCAL_IP:31293
355
+
356
+ # Or use SSH reverse tunnel
357
+ ssh -R 31293:localhost:31293 remote-server
358
+ """
359
+ try:
360
+ from scitex.audio.mcp_server import run_relay_server
361
+
362
+ click.secho(f"Starting audio relay server", fg="cyan")
363
+ click.echo(f" Host: {host}")
364
+ click.echo(f" Port: {port}")
365
+ click.echo()
366
+ click.echo("Endpoints:")
367
+ click.echo(" POST /speak - Play text-to-speech")
368
+ click.echo(" GET /health - Health check")
369
+ click.echo(" GET /list_backends - List backends")
370
+ click.echo()
371
+
372
+ run_relay_server(host=host, port=port)
373
+
374
+ except Exception as e:
375
+ click.secho(f"Error: {e}", fg="red", err=True)
376
+ sys.exit(1)
377
+
378
+
330
379
  if __name__ == "__main__":
331
380
  audio()
scitex/cli/capture.py CHANGED
@@ -10,8 +10,13 @@ import sys
10
10
  import click
11
11
 
12
12
 
13
- @click.group(context_settings={"help_option_names": ["-h", "--help"]})
14
- def capture():
13
+ @click.group(
14
+ context_settings={"help_option_names": ["-h", "--help"]},
15
+ invoke_without_command=True,
16
+ )
17
+ @click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
18
+ @click.pass_context
19
+ def capture(ctx, help_recursive):
15
20
  """
16
21
  Screen capture and monitoring utilities
17
22
 
@@ -33,25 +38,13 @@ def capture():
33
38
  scitex capture gif # Create GIF from latest session
34
39
  scitex capture info # List monitors and windows
35
40
  """
36
- pass
41
+ if help_recursive:
42
+ from . import print_help_recursive
37
43
 
38
-
39
- @capture.command("help-recursive")
40
- @click.pass_context
41
- def help_recursive(ctx):
42
- """Show help for all commands recursively."""
43
- fake_parent = click.Context(click.Group(), info_name="scitex")
44
- parent_ctx = click.Context(capture, info_name="capture", parent=fake_parent)
45
- click.secho("━━━ scitex capture ━━━", fg="cyan", bold=True)
46
- click.echo(capture.get_help(parent_ctx))
47
- for name in sorted(capture.list_commands(ctx) or []):
48
- cmd = capture.get_command(ctx, name)
49
- if cmd is None or name == "help-recursive":
50
- continue
51
- click.echo()
52
- click.secho(f"━━━ scitex capture {name} ━━━", fg="cyan", bold=True)
53
- with click.Context(cmd, info_name=name, parent=parent_ctx) as sub_ctx:
54
- click.echo(cmd.get_help(sub_ctx))
44
+ print_help_recursive(ctx, capture)
45
+ ctx.exit(0)
46
+ elif ctx.invoked_subcommand is None:
47
+ click.echo(ctx.get_help())
55
48
 
56
49
 
57
50
  @capture.command()