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,765 +1,32 @@
1
1
  #!/usr/bin/env python3
2
- # Timestamp: 2026-01-09
3
- # File: src/scitex/writer/_mcp.handlers.py
4
- # ----------------------------------------
2
+ # Timestamp: 2026-01-20
3
+ # File: src/scitex/writer/_mcp/handlers.py
5
4
 
6
5
  """
7
- MCP Handler implementations for SciTeX Writer module.
6
+ MCP Handler for SciTeX Writer module.
8
7
 
9
- Provides async handlers for LaTeX manuscript operations:
10
- - clone_project_handler: Create new writer project
11
- - compile_manuscript_handler: Compile manuscript PDF
12
- - compile_supplementary_handler: Compile supplementary PDF
13
- - compile_revision_handler: Compile revision PDF
14
- - get_project_info_handler: Get project information
15
- - get_pdf_handler: Get compiled PDF path
16
- - list_document_types_handler: List document types
8
+ Delegates to scitex-writer package for usage instructions.
17
9
  """
18
10
 
19
11
  from __future__ import annotations
20
12
 
21
- import asyncio
22
- from pathlib import Path
23
- from typing import List, Optional, Union
24
13
 
25
-
26
- async def clone_project_handler(
27
- project_dir: str,
28
- git_strategy: str = "child",
29
- branch: Optional[str] = None,
30
- tag: Optional[str] = None,
31
- ) -> dict:
32
- """
33
- Create a new writer project from template.
34
-
35
- Parameters
36
- ----------
37
- project_dir : str
38
- Path to create project directory
39
- git_strategy : str, optional
40
- Git initialization strategy (child, parent, origin, none)
41
- branch : str, optional
42
- Specific branch to clone
43
- tag : str, optional
44
- Specific tag to clone
45
-
46
- Returns
47
- -------
48
- dict
49
- Success status and project path
50
- """
51
- try:
52
- from scitex.writer._clone_writer_project import clone_writer_project
53
-
54
- # Handle git_strategy='none'
55
- git_strat = None if git_strategy == "none" else git_strategy
56
-
57
- # Run clone in executor (blocking operation)
58
- loop = asyncio.get_event_loop()
59
- success = await loop.run_in_executor(
60
- None,
61
- lambda: clone_writer_project(
62
- project_dir=project_dir,
63
- git_strategy=git_strat,
64
- branch=branch,
65
- tag=tag,
66
- ),
67
- )
68
-
69
- if success:
70
- resolved_path = Path(project_dir)
71
- if not resolved_path.is_absolute():
72
- resolved_path = Path.cwd() / resolved_path
73
-
74
- return {
75
- "success": True,
76
- "project_path": str(resolved_path),
77
- "git_strategy": git_strategy,
78
- "structure": {
79
- "00_shared": "Shared resources (figures, bibliography)",
80
- "01_manuscript": "Main manuscript",
81
- "02_supplementary": "Supplementary materials",
82
- "03_revision": "Revision documents",
83
- "scripts": "Compilation scripts",
84
- },
85
- "message": f"Successfully created writer project at {resolved_path}",
86
- }
87
- else:
88
- return {
89
- "success": False,
90
- "error": "Failed to clone writer project",
91
- "project_dir": project_dir,
92
- }
93
-
94
- except Exception as e:
95
- return {
96
- "success": False,
97
- "error": str(e),
98
- }
99
-
100
-
101
- async def compile_manuscript_handler(
102
- project_dir: str,
103
- timeout: int = 300,
104
- no_figs: bool = False,
105
- ppt2tif: bool = False,
106
- crop_tif: bool = False,
107
- quiet: bool = False,
108
- verbose: bool = False,
109
- force: bool = False,
110
- ) -> dict:
111
- """
112
- Compile manuscript to PDF.
113
-
114
- Parameters
115
- ----------
116
- project_dir : str
117
- Path to writer project directory
118
- timeout : int, optional
119
- Maximum compilation time in seconds
120
- no_figs : bool, optional
121
- Exclude figures for quick compilation
122
- ppt2tif : bool, optional
123
- Convert PowerPoint files to TIF format (WSL only)
124
- crop_tif : bool, optional
125
- Crop TIF images to remove whitespace
126
- quiet : bool, optional
127
- Suppress detailed LaTeX logs
128
- verbose : bool, optional
129
- Show verbose LaTeX output
130
- force : bool, optional
131
- Force recompilation, ignore cache
132
-
133
- Returns
134
- -------
135
- dict
136
- Success status, PDF path, and compilation details
137
- """
138
- try:
139
- from scitex.writer._compile import compile_manuscript
140
-
141
- project_path = Path(project_dir)
142
- if not project_path.is_absolute():
143
- project_path = Path.cwd() / project_path
144
-
145
- # Run compilation in executor
146
- loop = asyncio.get_event_loop()
147
-
148
- def do_compile():
149
- return compile_manuscript(
150
- project_path,
151
- timeout=timeout,
152
- no_figs=no_figs,
153
- ppt2tif=ppt2tif,
154
- crop_tif=crop_tif,
155
- quiet=quiet,
156
- verbose=verbose,
157
- force=force,
158
- )
159
-
160
- result = await loop.run_in_executor(None, do_compile)
161
-
162
- if result.success:
163
- return {
164
- "success": True,
165
- "output_pdf": str(result.output_pdf) if result.output_pdf else None,
166
- "exit_code": result.exit_code,
167
- "warnings": result.warnings[:10] if result.warnings else [],
168
- "message": "Manuscript compiled successfully",
169
- }
170
- else:
171
- return {
172
- "success": False,
173
- "exit_code": result.exit_code,
174
- "errors": result.errors[:10] if result.errors else [],
175
- "warnings": result.warnings[:10] if result.warnings else [],
176
- "error": f"Compilation failed with exit code {result.exit_code}",
177
- }
178
-
179
- except Exception as e:
180
- return {
181
- "success": False,
182
- "error": str(e),
183
- }
184
-
185
-
186
- async def compile_supplementary_handler(
187
- project_dir: str,
188
- timeout: int = 300,
189
- no_figs: bool = False,
190
- ppt2tif: bool = False,
191
- crop_tif: bool = False,
192
- quiet: bool = False,
193
- ) -> dict:
194
- """
195
- Compile supplementary materials to PDF.
196
-
197
- Parameters
198
- ----------
199
- project_dir : str
200
- Path to writer project directory
201
- timeout : int, optional
202
- Maximum compilation time in seconds
203
- no_figs : bool, optional
204
- Exclude figures for quick compilation
205
- ppt2tif : bool, optional
206
- Convert PowerPoint files to TIF format (WSL only)
207
- crop_tif : bool, optional
208
- Crop TIF images to remove whitespace
209
- quiet : bool, optional
210
- Suppress detailed LaTeX logs
211
-
212
- Returns
213
- -------
214
- dict
215
- Success status, PDF path, and compilation details
216
- """
217
- try:
218
- from scitex.writer._compile import compile_supplementary
219
-
220
- project_path = Path(project_dir)
221
- if not project_path.is_absolute():
222
- project_path = Path.cwd() / project_path
223
-
224
- loop = asyncio.get_event_loop()
225
-
226
- def do_compile():
227
- return compile_supplementary(
228
- project_path,
229
- timeout=timeout,
230
- no_figs=no_figs,
231
- ppt2tif=ppt2tif,
232
- crop_tif=crop_tif,
233
- quiet=quiet,
234
- )
235
-
236
- result = await loop.run_in_executor(None, do_compile)
237
-
238
- if result.success:
239
- return {
240
- "success": True,
241
- "output_pdf": str(result.output_pdf) if result.output_pdf else None,
242
- "exit_code": result.exit_code,
243
- "warnings": result.warnings[:10] if result.warnings else [],
244
- "message": "Supplementary materials compiled successfully",
245
- }
246
- else:
247
- return {
248
- "success": False,
249
- "exit_code": result.exit_code,
250
- "errors": result.errors[:10] if result.errors else [],
251
- "warnings": result.warnings[:10] if result.warnings else [],
252
- "error": f"Compilation failed with exit code {result.exit_code}",
253
- }
254
-
255
- except Exception as e:
256
- return {
257
- "success": False,
258
- "error": str(e),
259
- }
260
-
261
-
262
- async def compile_revision_handler(
263
- project_dir: str,
264
- track_changes: bool = False,
265
- timeout: int = 300,
266
- ) -> dict:
267
- """
268
- Compile revision document to PDF.
269
-
270
- Parameters
271
- ----------
272
- project_dir : str
273
- Path to writer project directory
274
- track_changes : bool, optional
275
- Enable change tracking in output
276
- timeout : int, optional
277
- Maximum compilation time in seconds
278
-
279
- Returns
280
- -------
281
- dict
282
- Success status, PDF path, and compilation details
283
- """
284
- try:
285
- from scitex.writer._compile import compile_revision
286
-
287
- project_path = Path(project_dir)
288
- if not project_path.is_absolute():
289
- project_path = Path.cwd() / project_path
290
-
291
- loop = asyncio.get_event_loop()
292
-
293
- def do_compile():
294
- return compile_revision(
295
- project_path,
296
- track_changes=track_changes,
297
- timeout=timeout,
298
- )
299
-
300
- result = await loop.run_in_executor(None, do_compile)
301
-
302
- if result.success:
303
- return {
304
- "success": True,
305
- "output_pdf": str(result.output_pdf) if result.output_pdf else None,
306
- "exit_code": result.exit_code,
307
- "track_changes": track_changes,
308
- "warnings": result.warnings[:10] if result.warnings else [],
309
- "message": "Revision compiled successfully",
310
- }
311
- else:
312
- return {
313
- "success": False,
314
- "exit_code": result.exit_code,
315
- "errors": result.errors[:10] if result.errors else [],
316
- "warnings": result.warnings[:10] if result.warnings else [],
317
- "error": f"Compilation failed with exit code {result.exit_code}",
318
- }
319
-
320
- except Exception as e:
321
- return {
322
- "success": False,
323
- "error": str(e),
324
- }
325
-
326
-
327
- async def get_project_info_handler(project_dir: str) -> dict:
328
- """
329
- Get writer project information.
330
-
331
- Parameters
332
- ----------
333
- project_dir : str
334
- Path to writer project directory
335
-
336
- Returns
337
- -------
338
- dict
339
- Project structure and status information
340
- """
341
- try:
342
- from scitex.writer import Writer
343
-
344
- project_path = Path(project_dir)
345
- if not project_path.is_absolute():
346
- project_path = Path.cwd() / project_path
347
-
348
- loop = asyncio.get_event_loop()
349
-
350
- def get_info():
351
- writer = Writer(project_path)
352
-
353
- # Check for compiled PDFs
354
- pdfs = {}
355
- for doc_type in ["manuscript", "supplementary", "revision"]:
356
- pdf = writer.get_pdf(doc_type)
357
- pdfs[doc_type] = str(pdf) if pdf else None
358
-
359
- return {
360
- "project_name": writer.project_name,
361
- "project_dir": str(writer.project_dir.absolute()),
362
- "git_root": str(writer.git_root) if writer.git_root else None,
363
- "documents": {
364
- "shared": str(writer.shared.root),
365
- "manuscript": str(writer.manuscript.root),
366
- "supplementary": str(writer.supplementary.root),
367
- "revision": str(writer.revision.root),
368
- "scripts": str(writer.scripts.root),
369
- },
370
- "compiled_pdfs": pdfs,
371
- }
372
-
373
- info = await loop.run_in_executor(None, get_info)
374
-
375
- return {
376
- "success": True,
377
- **info,
378
- }
379
-
380
- except Exception as e:
381
- return {
382
- "success": False,
383
- "error": str(e),
384
- }
385
-
386
-
387
- async def get_pdf_handler(
388
- project_dir: str,
389
- doc_type: str = "manuscript",
390
- ) -> dict:
391
- """
392
- Get path to compiled PDF.
393
-
394
- Parameters
395
- ----------
396
- project_dir : str
397
- Path to writer project directory
398
- doc_type : str, optional
399
- Document type (manuscript, supplementary, revision)
400
-
401
- Returns
402
- -------
403
- dict
404
- PDF path if exists
405
- """
406
- try:
407
- from scitex.writer import Writer
408
-
409
- project_path = Path(project_dir)
410
- if not project_path.is_absolute():
411
- project_path = Path.cwd() / project_path
412
-
413
- loop = asyncio.get_event_loop()
414
-
415
- def get_pdf():
416
- writer = Writer(project_path)
417
- return writer.get_pdf(doc_type)
418
-
419
- pdf = await loop.run_in_executor(None, get_pdf)
420
-
421
- if pdf:
422
- return {
423
- "success": True,
424
- "exists": True,
425
- "doc_type": doc_type,
426
- "pdf_path": str(pdf),
427
- }
428
- else:
429
- return {
430
- "success": True,
431
- "exists": False,
432
- "doc_type": doc_type,
433
- "pdf_path": None,
434
- "message": f"No compiled PDF found for {doc_type}",
435
- }
436
-
437
- except Exception as e:
438
- return {
439
- "success": False,
440
- "error": str(e),
441
- }
442
-
443
-
444
- async def list_document_types_handler() -> dict:
445
- """
446
- List available document types in a writer project.
447
-
448
- Returns
449
- -------
450
- dict
451
- List of document types with descriptions
452
- """
453
- return {
454
- "success": True,
455
- "document_types": [
456
- {
457
- "id": "manuscript",
458
- "name": "Manuscript",
459
- "description": "Main manuscript document",
460
- "directory": "01_manuscript",
461
- "compile_command": "compile_manuscript",
462
- },
463
- {
464
- "id": "supplementary",
465
- "name": "Supplementary Materials",
466
- "description": "Supplementary information, figures, and tables",
467
- "directory": "02_supplementary",
468
- "compile_command": "compile_supplementary",
469
- },
470
- {
471
- "id": "revision",
472
- "name": "Revision",
473
- "description": "Revision document with optional change tracking",
474
- "directory": "03_revision",
475
- "compile_command": "compile_revision",
476
- "supports_track_changes": True,
477
- },
478
- ],
479
- "shared_directory": {
480
- "id": "shared",
481
- "name": "Shared Resources",
482
- "description": "Figures, bibliography, and shared assets",
483
- "directory": "00_shared",
484
- },
485
- }
486
-
487
-
488
- async def csv2latex_handler(
489
- csv_path: str,
490
- output_path: Optional[str] = None,
491
- caption: Optional[str] = None,
492
- label: Optional[str] = None,
493
- longtable: bool = False,
494
- ) -> dict:
495
- """
496
- Convert CSV file to LaTeX table.
497
-
498
- Parameters
499
- ----------
500
- csv_path : str
501
- Path to CSV file
502
- output_path : str, optional
503
- Output path for LaTeX file
504
- caption : str, optional
505
- Table caption
506
- label : str, optional
507
- Table label for referencing
508
- longtable : bool, optional
509
- Use longtable for multi-page tables
510
-
511
- Returns
512
- -------
513
- dict
514
- LaTeX content and output path
515
- """
516
- try:
517
- from scitex.writer.utils import csv2latex
518
-
519
- loop = asyncio.get_event_loop()
520
- latex_content = await loop.run_in_executor(
521
- None,
522
- lambda: csv2latex(
523
- csv_path=csv_path,
524
- output_path=output_path,
525
- caption=caption,
526
- label=label,
527
- longtable=longtable,
528
- ),
529
- )
530
-
531
- return {
532
- "success": True,
533
- "latex_content": latex_content,
534
- "output_path": output_path,
535
- "message": f"Converted {csv_path} to LaTeX table",
536
- }
537
-
538
- except Exception as e:
539
- return {
540
- "success": False,
541
- "error": str(e),
542
- }
543
-
544
-
545
- async def latex2csv_handler(
546
- latex_path: str,
547
- output_path: Optional[str] = None,
548
- table_index: int = 0,
549
- ) -> dict:
550
- """
551
- Convert LaTeX table to CSV.
552
-
553
- Parameters
554
- ----------
555
- latex_path : str
556
- Path to LaTeX file containing table
557
- output_path : str, optional
558
- Output path for CSV file
559
- table_index : int, optional
560
- Index of table to extract
561
-
562
- Returns
563
- -------
564
- dict
565
- CSV content preview and output path
566
- """
567
- try:
568
- from scitex.writer.utils import latex2csv
569
-
570
- loop = asyncio.get_event_loop()
571
- df = await loop.run_in_executor(
572
- None,
573
- lambda: latex2csv(
574
- latex_path=latex_path,
575
- output_path=output_path,
576
- table_index=table_index,
577
- ),
578
- )
579
-
580
- return {
581
- "success": True,
582
- "rows": len(df),
583
- "columns": list(df.columns),
584
- "preview": df.head(5).to_dict(),
585
- "output_path": output_path,
586
- "message": f"Converted LaTeX table to CSV ({len(df)} rows)",
587
- }
588
-
589
- except Exception as e:
590
- return {
591
- "success": False,
592
- "error": str(e),
593
- }
594
-
595
-
596
- async def pdf_to_images_handler(
597
- pdf_path: str,
598
- output_dir: Optional[str] = None,
599
- pages: Optional[Union[int, List[int]]] = None,
600
- dpi: int = 150,
601
- format: str = "png",
602
- ) -> dict:
603
- """
604
- Render PDF pages as images.
605
-
606
- Parameters
607
- ----------
608
- pdf_path : str
609
- Path to PDF file
610
- output_dir : str, optional
611
- Output directory for images
612
- pages : int or list of int, optional
613
- Page(s) to render (0-indexed). If None, renders all.
614
- dpi : int, optional
615
- Resolution in DPI
616
- format : str, optional
617
- Output format (png, jpg)
618
-
619
- Returns
620
- -------
621
- dict
622
- List of rendered images with paths
623
- """
624
- try:
625
- from scitex.writer.utils import pdf_to_images
626
-
627
- loop = asyncio.get_event_loop()
628
- images = await loop.run_in_executor(
629
- None,
630
- lambda: pdf_to_images(
631
- pdf_path=pdf_path,
632
- output_dir=output_dir,
633
- pages=pages,
634
- dpi=dpi,
635
- format=format,
636
- ),
637
- )
638
-
639
- return {
640
- "success": True,
641
- "images": images,
642
- "count": len(images),
643
- "message": f"Rendered {len(images)} page(s) from {pdf_path}",
644
- }
645
-
646
- except Exception as e:
647
- return {
648
- "success": False,
649
- "error": str(e),
650
- }
651
-
652
-
653
- async def list_figures_handler(
654
- project_dir: str,
655
- extensions: Optional[list] = None,
656
- ) -> dict:
657
- """
658
- List figures in writer project.
659
-
660
- Parameters
661
- ----------
662
- project_dir : str
663
- Path to writer project directory
664
- extensions : list, optional
665
- File extensions to include
666
-
667
- Returns
668
- -------
669
- dict
670
- List of figure info
671
- """
14
+ async def writer_usage_handler() -> dict:
15
+ """Get usage guide for SciTeX Writer."""
672
16
  try:
673
- from scitex.writer.utils import list_figures
674
-
675
- loop = asyncio.get_event_loop()
676
- figures = await loop.run_in_executor(
677
- None,
678
- lambda: list_figures(
679
- project_dir=project_dir,
680
- extensions=extensions,
681
- ),
682
- )
17
+ from scitex_writer._server import INSTRUCTIONS
683
18
 
684
19
  return {
685
20
  "success": True,
686
- "figures": figures,
687
- "count": len(figures),
688
- "message": f"Found {len(figures)} figures in {project_dir}",
689
- }
690
-
691
- except Exception as e:
692
- return {
693
- "success": False,
694
- "error": str(e),
21
+ "instructions": INSTRUCTIONS,
695
22
  }
696
-
697
-
698
- async def convert_figure_handler(
699
- input_path: str,
700
- output_path: str,
701
- dpi: int = 300,
702
- quality: int = 95,
703
- ) -> dict:
704
- """
705
- Convert figure between formats.
706
-
707
- Parameters
708
- ----------
709
- input_path : str
710
- Input figure path
711
- output_path : str
712
- Output figure path
713
- dpi : int, optional
714
- Resolution for PDF rasterization
715
- quality : int, optional
716
- JPEG quality (1-100)
717
-
718
- Returns
719
- -------
720
- dict
721
- Conversion result with paths
722
- """
723
- try:
724
- from scitex.writer.utils import convert_figure
725
-
726
- loop = asyncio.get_event_loop()
727
- result = await loop.run_in_executor(
728
- None,
729
- lambda: convert_figure(
730
- input_path=input_path,
731
- output_path=output_path,
732
- dpi=dpi,
733
- quality=quality,
734
- ),
735
- )
736
-
737
- return {
738
- "success": True,
739
- **result,
740
- "message": f"Converted {input_path} to {output_path}",
741
- }
742
-
743
- except Exception as e:
23
+ except ImportError:
744
24
  return {
745
25
  "success": False,
746
- "error": str(e),
26
+ "error": "scitex-writer is required. Install with: pip install scitex-writer",
747
27
  }
748
28
 
749
29
 
750
- __all__ = [
751
- "clone_project_handler",
752
- "compile_manuscript_handler",
753
- "compile_supplementary_handler",
754
- "compile_revision_handler",
755
- "get_project_info_handler",
756
- "get_pdf_handler",
757
- "list_document_types_handler",
758
- "csv2latex_handler",
759
- "latex2csv_handler",
760
- "pdf_to_images_handler",
761
- "list_figures_handler",
762
- "convert_figure_handler",
763
- ]
30
+ __all__ = ["writer_usage_handler"]
764
31
 
765
32
  # EOF