scitex 2.14.0__py3-none-any.whl → 2.15.1__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.
- scitex/__init__.py +47 -0
- scitex/_env_loader.py +156 -0
- scitex/_mcp_resources/__init__.py +37 -0
- scitex/_mcp_resources/_cheatsheet.py +135 -0
- scitex/_mcp_resources/_figrecipe.py +138 -0
- scitex/_mcp_resources/_formats.py +102 -0
- scitex/_mcp_resources/_modules.py +337 -0
- scitex/_mcp_resources/_session.py +149 -0
- scitex/_mcp_tools/__init__.py +4 -0
- scitex/_mcp_tools/audio.py +66 -0
- scitex/_mcp_tools/diagram.py +11 -95
- scitex/_mcp_tools/introspect.py +191 -0
- scitex/_mcp_tools/plt.py +260 -305
- scitex/_mcp_tools/scholar.py +74 -0
- scitex/_mcp_tools/social.py +244 -0
- scitex/_mcp_tools/writer.py +21 -204
- scitex/ai/_gen_ai/_PARAMS.py +10 -7
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
- scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
- scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
- scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
- scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
- scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
- scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
- scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
- scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
- scitex/audio/README.md +40 -36
- scitex/audio/__init__.py +127 -59
- scitex/audio/_branding.py +185 -0
- scitex/audio/_mcp/__init__.py +32 -0
- scitex/audio/_mcp/handlers.py +59 -6
- scitex/audio/_mcp/speak_handlers.py +238 -0
- scitex/audio/_relay.py +225 -0
- scitex/audio/engines/elevenlabs_engine.py +6 -1
- scitex/audio/mcp_server.py +228 -75
- scitex/canvas/README.md +1 -1
- scitex/canvas/editor/_dearpygui/__init__.py +25 -0
- scitex/canvas/editor/_dearpygui/_editor.py +147 -0
- scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
- scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
- scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
- scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
- scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
- scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
- scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
- scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
- scitex/canvas/editor/_dearpygui/_selection.py +295 -0
- scitex/canvas/editor/_dearpygui/_state.py +93 -0
- scitex/canvas/editor/_dearpygui/_utils.py +61 -0
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/cli/__init__.py +38 -43
- scitex/cli/audio.py +76 -27
- scitex/cli/capture.py +13 -20
- scitex/cli/introspect.py +443 -0
- scitex/cli/main.py +198 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/scholar/__init__.py +8 -0
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +314 -0
- scitex/cli/writer.py +117 -0
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +191 -0
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/introspect/__init__.py +75 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +42 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/introspect/_mcp/__init__.py +37 -0
- scitex/introspect/_mcp/handlers.py +208 -0
- scitex/introspect/_members.py +151 -0
- scitex/introspect/_resolve.py +89 -0
- scitex/introspect/_signature.py +131 -0
- scitex/introspect/_source.py +80 -0
- scitex/introspect/_type_hints.py +172 -0
- scitex/io/bundle/README.md +1 -1
- scitex/mcp_server.py +98 -5
- scitex/plt/__init__.py +248 -550
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/plt/gallery/README.md +1 -1
- scitex/plt/utils/_hitmap/__init__.py +82 -0
- scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
- scitex/plt/utils/_hitmap/_color_application.py +346 -0
- scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
- scitex/plt/utils/_hitmap/_constants.py +40 -0
- scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
- scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
- scitex/plt/utils/_hitmap/_query.py +113 -0
- scitex/plt/utils/_hitmap.py +46 -1616
- scitex/plt/utils/_metadata/__init__.py +80 -0
- scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
- scitex/plt/utils/_metadata/_artists/_base.py +195 -0
- scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
- scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
- scitex/plt/utils/_metadata/_artists/_images.py +80 -0
- scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
- scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
- scitex/plt/utils/_metadata/_artists/_text.py +106 -0
- scitex/plt/utils/_metadata/_csv.py +416 -0
- scitex/plt/utils/_metadata/_detect.py +225 -0
- scitex/plt/utils/_metadata/_legend.py +127 -0
- scitex/plt/utils/_metadata/_rounding.py +117 -0
- scitex/plt/utils/_metadata/_verification.py +202 -0
- scitex/schema/README.md +1 -1
- scitex/scholar/__init__.py +8 -0
- scitex/scholar/_mcp/crossref_handlers.py +265 -0
- scitex/scholar/core/Scholar.py +63 -1700
- scitex/scholar/core/_mixins/__init__.py +36 -0
- scitex/scholar/core/_mixins/_enrichers.py +270 -0
- scitex/scholar/core/_mixins/_library_handlers.py +100 -0
- scitex/scholar/core/_mixins/_loaders.py +103 -0
- scitex/scholar/core/_mixins/_pdf_download.py +375 -0
- scitex/scholar/core/_mixins/_pipeline.py +312 -0
- scitex/scholar/core/_mixins/_project_handlers.py +125 -0
- scitex/scholar/core/_mixins/_savers.py +69 -0
- scitex/scholar/core/_mixins/_search.py +103 -0
- scitex/scholar/core/_mixins/_services.py +88 -0
- scitex/scholar/core/_mixins/_url_finding.py +105 -0
- scitex/scholar/crossref_scitex.py +367 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/scholar/examples/00_run_all.sh +120 -0
- scitex/scholar/jobs/_executors.py +27 -3
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
- scitex/scholar/pdf_download/_cli.py +154 -0
- scitex/scholar/pdf_download/strategies/__init__.py +11 -8
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
- scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
- scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
- scitex/scholar/pipelines/_single_steps.py +71 -36
- scitex/scholar/storage/_LibraryManager.py +97 -1695
- scitex/scholar/storage/_mixins/__init__.py +30 -0
- scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
- scitex/scholar/storage/_mixins/_library_operations.py +218 -0
- scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
- scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
- scitex/scholar/storage/_mixins/_resolution.py +376 -0
- scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
- scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
- scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
- scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
- scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
- scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
- scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
- scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
- scitex/security/README.md +3 -3
- scitex/session/README.md +1 -1
- scitex/sh/README.md +1 -1
- scitex/social/__init__.py +153 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/template/README.md +1 -1
- scitex/template/clone_writer_directory.py +5 -5
- scitex/writer/README.md +1 -1
- scitex/writer/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.1.dist-info/METADATA +648 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/RECORD +166 -111
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
- scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
- scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
- scitex/diagram/_compile.py +0 -312
- scitex/diagram/_diagram.py +0 -355
- scitex/diagram/_mcp/__init__.py +0 -4
- scitex/diagram/_mcp/handlers.py +0 -400
- scitex/diagram/_mcp/tool_schemas.py +0 -157
- scitex/diagram/_presets.py +0 -173
- scitex/diagram/_schema.py +0 -182
- scitex/diagram/_split.py +0 -278
- scitex/plt/_mcp/__init__.py +0 -4
- scitex/plt/_mcp/_handlers_annotation.py +0 -102
- scitex/plt/_mcp/_handlers_figure.py +0 -195
- scitex/plt/_mcp/_handlers_plot.py +0 -252
- scitex/plt/_mcp/_handlers_style.py +0 -219
- scitex/plt/_mcp/handlers.py +0 -74
- scitex/plt/_mcp/tool_schemas.py +0 -497
- scitex/plt/mcp_server.py +0 -231
- scitex/scholar/data/.gitkeep +0 -0
- scitex/scholar/data/README.md +0 -44
- scitex/scholar/data/bib_files/bibliography.bib +0 -1952
- scitex/scholar/data/bib_files/neurovista.bib +0 -277
- scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
- scitex/scholar/data/bib_files/openaccess.bib +0 -89
- scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
- scitex/scholar/data/bib_files/pac.bib +0 -698
- scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
- scitex/scholar/data/bib_files/pac_processed.bib +0 -0
- scitex/scholar/data/bib_files/pac_titles.txt +0 -75
- scitex/scholar/data/bib_files/paywalled.bib +0 -98
- scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
- scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
- scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
- scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
- scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_seizure.bib +0 -46
- scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
- scitex/scholar/data/impact_factor.db +0 -0
- scitex/scholar/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex-2.14.0.dist-info/METADATA +0 -1238
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/licenses/LICENSE +0 -0
scitex/writer/_mcp/handlers.py
CHANGED
|
@@ -1,765 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-
|
|
3
|
-
# File: src/scitex/writer/_mcp
|
|
4
|
-
# ----------------------------------------
|
|
2
|
+
# Timestamp: 2026-01-20
|
|
3
|
+
# File: src/scitex/writer/_mcp/handlers.py
|
|
5
4
|
|
|
6
5
|
"""
|
|
7
|
-
MCP Handler
|
|
6
|
+
MCP Handler for SciTeX Writer module.
|
|
8
7
|
|
|
9
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
"
|
|
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":
|
|
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
|