scitex 2.14.0__py3-none-any.whl → 2.15.3__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 +71 -17
- 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 +210 -0
- scitex/_mcp_tools/plt.py +260 -305
- scitex/_mcp_tools/scholar.py +74 -0
- scitex/_mcp_tools/social.py +27 -0
- scitex/_mcp_tools/template.py +24 -0
- scitex/_mcp_tools/writer.py +17 -210
- 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/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
- scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
- scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
- scitex/audio/README.md +40 -36
- scitex/audio/__init__.py +129 -61
- 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/_tts.py +18 -10
- scitex/audio/engines/base.py +17 -10
- scitex/audio/engines/elevenlabs_engine.py +7 -2
- 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/_core/__init__.py +27 -0
- scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
- scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
- scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
- scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
- scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
- scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
- scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
- scitex/canvas/editor/flask_editor/_core.py +25 -1684
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/cli/__init__.py +38 -43
- scitex/cli/audio.py +160 -41
- scitex/cli/capture.py +133 -20
- scitex/cli/introspect.py +488 -0
- scitex/cli/main.py +200 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/plt.py +414 -0
- scitex/cli/repro.py +15 -8
- scitex/cli/resource.py +15 -8
- scitex/cli/scholar/__init__.py +154 -8
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +355 -0
- scitex/cli/stats.py +136 -11
- scitex/cli/template.py +129 -12
- scitex/cli/tex.py +15 -8
- scitex/cli/writer.py +49 -299
- scitex/cloud/__init__.py +41 -2
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +256 -0
- scitex/context/__init__.py +22 -0
- scitex/dev/__init__.py +20 -1
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/gen/__init__.py +50 -14
- scitex/gen/_list_packages.py +4 -4
- scitex/introspect/__init__.py +82 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +41 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/{gen/_inspect_module.py → introspect/_list_api.py} +48 -56
- scitex/introspect/_mcp/__init__.py +41 -0
- scitex/introspect/_mcp/handlers.py +233 -0
- scitex/introspect/_members.py +155 -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/_save.py +1 -2
- scitex/io/bundle/README.md +1 -1
- scitex/logging/_formatters.py +19 -9
- scitex/mcp_server.py +98 -5
- scitex/os/__init__.py +4 -0
- scitex/{gen → os}/_check_host.py +4 -5
- scitex/plt/__init__.py +245 -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/security/README.md +3 -3
- scitex/session/README.md +1 -1
- scitex/session/__init__.py +26 -7
- scitex/session/_decorator.py +1 -1
- scitex/sh/README.md +1 -1
- scitex/sh/__init__.py +7 -4
- scitex/social/__init__.py +155 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/stats/_mcp/_handlers/__init__.py +31 -0
- scitex/stats/_mcp/_handlers/_corrections.py +113 -0
- scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
- scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
- scitex/stats/_mcp/_handlers/_format.py +94 -0
- scitex/stats/_mcp/_handlers/_normality.py +110 -0
- scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
- scitex/stats/_mcp/_handlers/_power.py +247 -0
- scitex/stats/_mcp/_handlers/_recommend.py +102 -0
- scitex/stats/_mcp/_handlers/_run_test.py +279 -0
- scitex/stats/_mcp/_handlers/_stars.py +48 -0
- scitex/stats/_mcp/handlers.py +19 -1171
- scitex/stats/auto/_stat_style.py +175 -0
- scitex/stats/auto/_style_definitions.py +411 -0
- scitex/stats/auto/_styles.py +22 -620
- scitex/stats/descriptive/__init__.py +11 -8
- scitex/stats/descriptive/_ci.py +39 -0
- scitex/stats/power/_power.py +15 -4
- scitex/str/__init__.py +2 -1
- scitex/str/_title_case.py +63 -0
- scitex/template/README.md +1 -1
- scitex/template/__init__.py +25 -10
- scitex/template/_code_templates.py +147 -0
- scitex/template/_mcp/handlers.py +81 -0
- scitex/template/_mcp/tool_schemas.py +55 -0
- scitex/template/_templates/__init__.py +51 -0
- scitex/template/_templates/audio.py +233 -0
- scitex/template/_templates/canvas.py +312 -0
- scitex/template/_templates/capture.py +268 -0
- scitex/template/_templates/config.py +43 -0
- scitex/template/_templates/diagram.py +294 -0
- scitex/template/_templates/io.py +107 -0
- scitex/template/_templates/module.py +53 -0
- scitex/template/_templates/plt.py +202 -0
- scitex/template/_templates/scholar.py +267 -0
- scitex/template/_templates/session.py +130 -0
- scitex/template/_templates/session_minimal.py +43 -0
- scitex/template/_templates/session_plot.py +67 -0
- scitex/template/_templates/session_stats.py +77 -0
- scitex/template/_templates/stats.py +323 -0
- scitex/template/_templates/writer.py +296 -0
- scitex/template/clone_writer_directory.py +5 -5
- scitex/ui/_backends/_email.py +10 -2
- scitex/ui/_backends/_webhook.py +5 -1
- scitex/web/_search_pubmed.py +10 -6
- scitex/writer/README.md +1 -1
- scitex/writer/__init__.py +43 -34
- scitex/writer/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.3.dist-info/METADATA +667 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/RECORD +241 -120
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- 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/gen/_ci.py +0 -12
- scitex/gen/_title_case.py +0 -89
- 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/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex-2.14.0.dist-info/METADATA +0 -1238
- /scitex/{gen → context}/_detect_environment.py +0 -0
- /scitex/{gen → context}/_get_notebook_path.py +0 -0
- /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25
|
+
"js/dev/element-inspector.js",
|
|
41
26
|
# Core modules first (dependencies)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
27
|
+
"js/core/state.js",
|
|
28
|
+
"js/core/utils.js",
|
|
29
|
+
"js/core/api.js",
|
|
45
30
|
# Editor modules
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
"js/alignment/basic.js",
|
|
42
|
+
"js/alignment/axis.js",
|
|
43
|
+
"js/alignment/distribute.js",
|
|
59
44
|
# UI modules
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
"js/ui/theme.js",
|
|
46
|
+
"js/ui/help.js",
|
|
47
|
+
"js/ui/download.js",
|
|
48
|
+
"js/ui/controls.js",
|
|
64
49
|
# Shortcuts
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
"js/shortcuts/context-menu.js",
|
|
51
|
+
"js/shortcuts/keyboard.js",
|
|
67
52
|
# Main entry (last)
|
|
68
|
-
|
|
53
|
+
"js/main.js",
|
|
69
54
|
]
|
|
70
55
|
|
|
71
56
|
# Generate script tags
|
|
72
|
-
script_tags =
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
20
|
-
"""
|
|
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
|
-
|
|
24
|
-
|
|
23
|
+
ctx: The click context
|
|
24
|
+
group: The click group to print help for
|
|
25
25
|
"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
click.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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(
|
|
14
|
-
|
|
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
|
-
|
|
32
|
-
|
|
36
|
+
if help_recursive:
|
|
37
|
+
from . import print_help_recursive
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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()
|
|
@@ -247,7 +240,28 @@ def stop():
|
|
|
247
240
|
sys.exit(1)
|
|
248
241
|
|
|
249
242
|
|
|
250
|
-
@audio.
|
|
243
|
+
@audio.group(invoke_without_command=True)
|
|
244
|
+
@click.pass_context
|
|
245
|
+
def mcp(ctx):
|
|
246
|
+
"""
|
|
247
|
+
MCP (Model Context Protocol) server operations
|
|
248
|
+
|
|
249
|
+
\b
|
|
250
|
+
Commands:
|
|
251
|
+
start - Start the MCP server
|
|
252
|
+
doctor - Check MCP server health
|
|
253
|
+
list-tools - List available MCP tools
|
|
254
|
+
|
|
255
|
+
\b
|
|
256
|
+
Examples:
|
|
257
|
+
scitex audio mcp start
|
|
258
|
+
scitex audio mcp start -t http --port 31293
|
|
259
|
+
"""
|
|
260
|
+
if ctx.invoked_subcommand is None:
|
|
261
|
+
click.echo(ctx.get_help())
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@mcp.command()
|
|
251
265
|
@click.option(
|
|
252
266
|
"-t",
|
|
253
267
|
"--transport",
|
|
@@ -262,13 +276,13 @@ def stop():
|
|
|
262
276
|
)
|
|
263
277
|
@click.option(
|
|
264
278
|
"--port",
|
|
265
|
-
default=
|
|
279
|
+
default=31293,
|
|
266
280
|
type=int,
|
|
267
|
-
help="Port for HTTP/SSE transport (default:
|
|
281
|
+
help="Port for HTTP/SSE transport (default: 31293)",
|
|
268
282
|
)
|
|
269
|
-
def
|
|
283
|
+
def start(transport, host, port):
|
|
270
284
|
"""
|
|
271
|
-
|
|
285
|
+
Start the MCP server for remote audio playback
|
|
272
286
|
|
|
273
287
|
Enables remote agents (via SSH) to play audio on local speakers.
|
|
274
288
|
|
|
@@ -280,22 +294,9 @@ def serve(transport, host, port):
|
|
|
280
294
|
|
|
281
295
|
\b
|
|
282
296
|
Examples:
|
|
283
|
-
|
|
284
|
-
scitex audio
|
|
285
|
-
|
|
286
|
-
# HTTP server for remote agents
|
|
287
|
-
scitex audio serve -t http --port 8084
|
|
288
|
-
|
|
289
|
-
# SSE server
|
|
290
|
-
scitex audio serve -t sse --port 8084
|
|
291
|
-
|
|
292
|
-
\b
|
|
293
|
-
Remote Setup:
|
|
294
|
-
1. Local: scitex audio serve -t http --port 8084
|
|
295
|
-
2. SSH: Add to ~/.ssh/config:
|
|
296
|
-
LocalForward 8084 127.0.0.1:8084
|
|
297
|
-
3. Remote MCP config:
|
|
298
|
-
{"type": "sse", "url": "http://localhost:8084/sse"}
|
|
297
|
+
scitex audio mcp start
|
|
298
|
+
scitex audio mcp start -t http --port 31293
|
|
299
|
+
scitex audio mcp start -t sse --port 31293
|
|
299
300
|
"""
|
|
300
301
|
try:
|
|
301
302
|
from scitex.audio.mcp_server import FASTMCP_AVAILABLE, run_server
|
|
@@ -327,5 +328,123 @@ def serve(transport, host, port):
|
|
|
327
328
|
sys.exit(1)
|
|
328
329
|
|
|
329
330
|
|
|
331
|
+
@mcp.command()
|
|
332
|
+
def doctor():
|
|
333
|
+
"""
|
|
334
|
+
Check MCP server health and dependencies
|
|
335
|
+
|
|
336
|
+
\b
|
|
337
|
+
Example:
|
|
338
|
+
scitex audio mcp doctor
|
|
339
|
+
"""
|
|
340
|
+
click.secho("Audio MCP Server Health Check", fg="cyan", bold=True)
|
|
341
|
+
click.echo()
|
|
342
|
+
|
|
343
|
+
# Check fastmcp
|
|
344
|
+
click.echo("Checking FastMCP... ", nl=False)
|
|
345
|
+
try:
|
|
346
|
+
from scitex.audio.mcp_server import FASTMCP_AVAILABLE
|
|
347
|
+
|
|
348
|
+
if FASTMCP_AVAILABLE:
|
|
349
|
+
click.secho("OK", fg="green")
|
|
350
|
+
else:
|
|
351
|
+
click.secho("NOT INSTALLED", fg="red")
|
|
352
|
+
click.echo(" Install with: pip install fastmcp")
|
|
353
|
+
except ImportError:
|
|
354
|
+
click.secho("FAIL", fg="red")
|
|
355
|
+
|
|
356
|
+
# Check audio backends
|
|
357
|
+
click.echo("Checking audio backends... ", nl=False)
|
|
358
|
+
try:
|
|
359
|
+
from scitex.audio import available_backends
|
|
360
|
+
|
|
361
|
+
backends = available_backends()
|
|
362
|
+
if backends:
|
|
363
|
+
click.secho(f"OK ({', '.join(backends)})", fg="green")
|
|
364
|
+
else:
|
|
365
|
+
click.secho("NONE AVAILABLE", fg="yellow")
|
|
366
|
+
except Exception as e:
|
|
367
|
+
click.secho(f"FAIL ({e})", fg="red")
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@mcp.command("list-tools")
|
|
371
|
+
def list_tools():
|
|
372
|
+
"""
|
|
373
|
+
List available MCP tools
|
|
374
|
+
|
|
375
|
+
\b
|
|
376
|
+
Example:
|
|
377
|
+
scitex audio mcp list-tools
|
|
378
|
+
"""
|
|
379
|
+
click.secho("Audio MCP Tools", fg="cyan", bold=True)
|
|
380
|
+
click.echo()
|
|
381
|
+
tools = [
|
|
382
|
+
("audio_speak", "Convert text to speech and play audio"),
|
|
383
|
+
("audio_generate_audio", "Generate audio file without playing"),
|
|
384
|
+
("audio_list_backends", "List available TTS backends"),
|
|
385
|
+
("audio_list_voices", "List available voices for a backend"),
|
|
386
|
+
("audio_play_audio", "Play an audio file"),
|
|
387
|
+
("audio_check_audio_status", "Check audio system status"),
|
|
388
|
+
]
|
|
389
|
+
for name, desc in tools:
|
|
390
|
+
click.echo(f" {name}: {desc}")
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
@audio.command()
|
|
394
|
+
@click.option(
|
|
395
|
+
"--host",
|
|
396
|
+
default="0.0.0.0",
|
|
397
|
+
help="Host to bind (default: 0.0.0.0)",
|
|
398
|
+
)
|
|
399
|
+
@click.option(
|
|
400
|
+
"--port",
|
|
401
|
+
default=31293,
|
|
402
|
+
type=int,
|
|
403
|
+
help="Port to bind (default: 31293)",
|
|
404
|
+
)
|
|
405
|
+
def relay(host, port):
|
|
406
|
+
"""
|
|
407
|
+
Run simple HTTP relay server for remote audio playback
|
|
408
|
+
|
|
409
|
+
Unlike 'serve' (MCP server), this exposes simple REST endpoints
|
|
410
|
+
that remote agents can POST to for audio playback.
|
|
411
|
+
|
|
412
|
+
\b
|
|
413
|
+
Endpoints:
|
|
414
|
+
POST /speak - Play text-to-speech
|
|
415
|
+
GET /health - Health check
|
|
416
|
+
GET /list_backends - List available backends
|
|
417
|
+
|
|
418
|
+
\b
|
|
419
|
+
Example:
|
|
420
|
+
# On your local machine (where you want audio)
|
|
421
|
+
scitex audio relay --port 31293
|
|
422
|
+
|
|
423
|
+
# On remote server, set env var
|
|
424
|
+
export SCITEX_AUDIO_RELAY_URL=http://YOUR_LOCAL_IP:31293
|
|
425
|
+
|
|
426
|
+
# Or use SSH reverse tunnel
|
|
427
|
+
ssh -R 31293:localhost:31293 remote-server
|
|
428
|
+
"""
|
|
429
|
+
try:
|
|
430
|
+
from scitex.audio.mcp_server import run_relay_server
|
|
431
|
+
|
|
432
|
+
click.secho("Starting audio relay server", fg="cyan")
|
|
433
|
+
click.echo(f" Host: {host}")
|
|
434
|
+
click.echo(f" Port: {port}")
|
|
435
|
+
click.echo()
|
|
436
|
+
click.echo("Endpoints:")
|
|
437
|
+
click.echo(" POST /speak - Play text-to-speech")
|
|
438
|
+
click.echo(" GET /health - Health check")
|
|
439
|
+
click.echo(" GET /list_backends - List backends")
|
|
440
|
+
click.echo()
|
|
441
|
+
|
|
442
|
+
run_relay_server(host=host, port=port)
|
|
443
|
+
|
|
444
|
+
except Exception as e:
|
|
445
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
446
|
+
sys.exit(1)
|
|
447
|
+
|
|
448
|
+
|
|
330
449
|
if __name__ == "__main__":
|
|
331
450
|
audio()
|
scitex/cli/capture.py
CHANGED
|
@@ -10,8 +10,13 @@ import sys
|
|
|
10
10
|
import click
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
@click.group(
|
|
14
|
-
|
|
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
|
-
|
|
41
|
+
if help_recursive:
|
|
42
|
+
from . import print_help_recursive
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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()
|
|
@@ -321,5 +314,125 @@ def window(handle, output, quality):
|
|
|
321
314
|
sys.exit(1)
|
|
322
315
|
|
|
323
316
|
|
|
317
|
+
@capture.group(invoke_without_command=True)
|
|
318
|
+
@click.pass_context
|
|
319
|
+
def mcp(ctx):
|
|
320
|
+
"""
|
|
321
|
+
MCP (Model Context Protocol) server operations
|
|
322
|
+
|
|
323
|
+
\b
|
|
324
|
+
Commands:
|
|
325
|
+
start - Start the MCP server
|
|
326
|
+
doctor - Check MCP server health
|
|
327
|
+
list-tools - List available MCP tools
|
|
328
|
+
|
|
329
|
+
\b
|
|
330
|
+
Examples:
|
|
331
|
+
scitex capture mcp start
|
|
332
|
+
scitex capture mcp list-tools
|
|
333
|
+
"""
|
|
334
|
+
if ctx.invoked_subcommand is None:
|
|
335
|
+
click.echo(ctx.get_help())
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@mcp.command("start")
|
|
339
|
+
@click.option(
|
|
340
|
+
"-t",
|
|
341
|
+
"--transport",
|
|
342
|
+
type=click.Choice(["stdio", "sse", "http"]),
|
|
343
|
+
default="stdio",
|
|
344
|
+
help="Transport protocol (default: stdio)",
|
|
345
|
+
)
|
|
346
|
+
@click.option("--host", default="0.0.0.0", help="Host for HTTP/SSE (default: 0.0.0.0)")
|
|
347
|
+
@click.option(
|
|
348
|
+
"--port", default=8096, type=int, help="Port for HTTP/SSE (default: 8096)"
|
|
349
|
+
)
|
|
350
|
+
def mcp_start(transport, host, port):
|
|
351
|
+
"""
|
|
352
|
+
Start the capture MCP server
|
|
353
|
+
|
|
354
|
+
\b
|
|
355
|
+
Examples:
|
|
356
|
+
scitex capture mcp start
|
|
357
|
+
scitex capture mcp start -t http --port 8096
|
|
358
|
+
"""
|
|
359
|
+
try:
|
|
360
|
+
from scitex.capture.mcp_server import main as run_server
|
|
361
|
+
|
|
362
|
+
if transport != "stdio":
|
|
363
|
+
click.secho(f"Starting capture MCP server ({transport})", fg="cyan")
|
|
364
|
+
click.echo(f" Host: {host}")
|
|
365
|
+
click.echo(f" Port: {port}")
|
|
366
|
+
|
|
367
|
+
run_server()
|
|
368
|
+
|
|
369
|
+
except ImportError as e:
|
|
370
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
371
|
+
click.echo("\nInstall dependencies: pip install fastmcp")
|
|
372
|
+
sys.exit(1)
|
|
373
|
+
except Exception as e:
|
|
374
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
375
|
+
sys.exit(1)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@mcp.command()
|
|
379
|
+
def doctor():
|
|
380
|
+
"""
|
|
381
|
+
Check MCP server health and dependencies
|
|
382
|
+
|
|
383
|
+
\b
|
|
384
|
+
Example:
|
|
385
|
+
scitex capture mcp doctor
|
|
386
|
+
"""
|
|
387
|
+
click.secho("Capture MCP Server Health Check", fg="cyan", bold=True)
|
|
388
|
+
click.echo()
|
|
389
|
+
|
|
390
|
+
click.echo("Checking FastMCP... ", nl=False)
|
|
391
|
+
try:
|
|
392
|
+
import fastmcp # noqa: F401
|
|
393
|
+
|
|
394
|
+
click.secho("OK", fg="green")
|
|
395
|
+
except ImportError:
|
|
396
|
+
click.secho("NOT INSTALLED", fg="red")
|
|
397
|
+
click.echo(" Install with: pip install fastmcp")
|
|
398
|
+
|
|
399
|
+
click.echo("Checking capture module... ", nl=False)
|
|
400
|
+
try:
|
|
401
|
+
from scitex import capture as _ # noqa: F401
|
|
402
|
+
|
|
403
|
+
click.secho("OK", fg="green")
|
|
404
|
+
except ImportError as e:
|
|
405
|
+
click.secho(f"FAIL ({e})", fg="red")
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@mcp.command("list-tools")
|
|
409
|
+
def list_tools():
|
|
410
|
+
"""
|
|
411
|
+
List available MCP tools
|
|
412
|
+
|
|
413
|
+
\b
|
|
414
|
+
Example:
|
|
415
|
+
scitex capture mcp list-tools
|
|
416
|
+
"""
|
|
417
|
+
click.secho("Capture MCP Tools", fg="cyan", bold=True)
|
|
418
|
+
click.echo()
|
|
419
|
+
tools = [
|
|
420
|
+
("capture_capture_screenshot", "Capture screenshot"),
|
|
421
|
+
("capture_capture_window", "Capture specific window"),
|
|
422
|
+
("capture_start_monitoring", "Start continuous capture"),
|
|
423
|
+
("capture_stop_monitoring", "Stop monitoring"),
|
|
424
|
+
("capture_get_monitoring_status", "Get monitoring status"),
|
|
425
|
+
("capture_analyze_screenshot", "Analyze screenshot for errors"),
|
|
426
|
+
("capture_list_recent_screenshots", "List recent screenshots"),
|
|
427
|
+
("capture_clear_cache", "Clear screenshot cache"),
|
|
428
|
+
("capture_create_gif", "Create animated GIF"),
|
|
429
|
+
("capture_list_sessions", "List monitoring sessions"),
|
|
430
|
+
("capture_get_info", "Get monitor/window info"),
|
|
431
|
+
("capture_list_windows", "List visible windows"),
|
|
432
|
+
]
|
|
433
|
+
for name, desc in tools:
|
|
434
|
+
click.echo(f" {name}: {desc}")
|
|
435
|
+
|
|
436
|
+
|
|
324
437
|
if __name__ == "__main__":
|
|
325
438
|
capture()
|