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.
Files changed (218) hide show
  1. scitex/__init__.py +47 -0
  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 +191 -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/writer.py +21 -204
  17. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  18. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  19. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  20. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  21. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  22. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  23. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  24. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  25. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  26. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  27. scitex/audio/README.md +40 -36
  28. scitex/audio/__init__.py +127 -59
  29. scitex/audio/_branding.py +185 -0
  30. scitex/audio/_mcp/__init__.py +32 -0
  31. scitex/audio/_mcp/handlers.py +59 -6
  32. scitex/audio/_mcp/speak_handlers.py +238 -0
  33. scitex/audio/_relay.py +225 -0
  34. scitex/audio/engines/elevenlabs_engine.py +6 -1
  35. scitex/audio/mcp_server.py +228 -75
  36. scitex/canvas/README.md +1 -1
  37. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  38. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  39. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  40. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  41. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  42. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  43. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  44. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  45. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  46. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  47. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  48. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  49. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  50. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  51. scitex/cli/__init__.py +38 -43
  52. scitex/cli/audio.py +76 -27
  53. scitex/cli/capture.py +13 -20
  54. scitex/cli/introspect.py +443 -0
  55. scitex/cli/main.py +198 -109
  56. scitex/cli/mcp.py +60 -34
  57. scitex/cli/scholar/__init__.py +8 -0
  58. scitex/cli/scholar/_crossref_scitex.py +296 -0
  59. scitex/cli/scholar/_fetch.py +25 -3
  60. scitex/cli/social.py +314 -0
  61. scitex/cli/writer.py +117 -0
  62. scitex/config/README.md +1 -1
  63. scitex/config/__init__.py +16 -2
  64. scitex/config/_env_registry.py +191 -0
  65. scitex/diagram/__init__.py +42 -19
  66. scitex/diagram/mcp_server.py +13 -125
  67. scitex/introspect/__init__.py +75 -0
  68. scitex/introspect/_call_graph.py +303 -0
  69. scitex/introspect/_class_hierarchy.py +163 -0
  70. scitex/introspect/_core.py +42 -0
  71. scitex/introspect/_docstring.py +131 -0
  72. scitex/introspect/_examples.py +113 -0
  73. scitex/introspect/_imports.py +271 -0
  74. scitex/introspect/_mcp/__init__.py +37 -0
  75. scitex/introspect/_mcp/handlers.py +208 -0
  76. scitex/introspect/_members.py +151 -0
  77. scitex/introspect/_resolve.py +89 -0
  78. scitex/introspect/_signature.py +131 -0
  79. scitex/introspect/_source.py +80 -0
  80. scitex/introspect/_type_hints.py +172 -0
  81. scitex/io/bundle/README.md +1 -1
  82. scitex/mcp_server.py +98 -5
  83. scitex/plt/__init__.py +248 -550
  84. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  85. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  86. scitex/plt/gallery/README.md +1 -1
  87. scitex/plt/utils/_hitmap/__init__.py +82 -0
  88. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  89. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  90. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  91. scitex/plt/utils/_hitmap/_constants.py +40 -0
  92. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  93. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  94. scitex/plt/utils/_hitmap/_query.py +113 -0
  95. scitex/plt/utils/_hitmap.py +46 -1616
  96. scitex/plt/utils/_metadata/__init__.py +80 -0
  97. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  98. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  99. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  100. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  101. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  102. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  103. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  104. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  105. scitex/plt/utils/_metadata/_csv.py +416 -0
  106. scitex/plt/utils/_metadata/_detect.py +225 -0
  107. scitex/plt/utils/_metadata/_legend.py +127 -0
  108. scitex/plt/utils/_metadata/_rounding.py +117 -0
  109. scitex/plt/utils/_metadata/_verification.py +202 -0
  110. scitex/schema/README.md +1 -1
  111. scitex/scholar/__init__.py +8 -0
  112. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  113. scitex/scholar/core/Scholar.py +63 -1700
  114. scitex/scholar/core/_mixins/__init__.py +36 -0
  115. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  116. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  117. scitex/scholar/core/_mixins/_loaders.py +103 -0
  118. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  119. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  120. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  121. scitex/scholar/core/_mixins/_savers.py +69 -0
  122. scitex/scholar/core/_mixins/_search.py +103 -0
  123. scitex/scholar/core/_mixins/_services.py +88 -0
  124. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  125. scitex/scholar/crossref_scitex.py +367 -0
  126. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  127. scitex/scholar/examples/00_run_all.sh +120 -0
  128. scitex/scholar/jobs/_executors.py +27 -3
  129. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  130. scitex/scholar/pdf_download/_cli.py +154 -0
  131. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  132. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  133. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  134. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  135. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  136. scitex/scholar/pipelines/_single_steps.py +71 -36
  137. scitex/scholar/storage/_LibraryManager.py +97 -1695
  138. scitex/scholar/storage/_mixins/__init__.py +30 -0
  139. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  140. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  141. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  142. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  143. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  144. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  145. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  146. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  147. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  148. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  149. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  150. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  151. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  152. scitex/security/README.md +3 -3
  153. scitex/session/README.md +1 -1
  154. scitex/sh/README.md +1 -1
  155. scitex/social/__init__.py +153 -0
  156. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  157. scitex/template/README.md +1 -1
  158. scitex/template/clone_writer_directory.py +5 -5
  159. scitex/writer/README.md +1 -1
  160. scitex/writer/_mcp/handlers.py +11 -744
  161. scitex/writer/_mcp/tool_schemas.py +5 -335
  162. scitex-2.15.1.dist-info/METADATA +648 -0
  163. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/RECORD +166 -111
  164. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  165. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  166. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  167. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  168. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  169. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  170. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  171. scitex/diagram/_compile.py +0 -312
  172. scitex/diagram/_diagram.py +0 -355
  173. scitex/diagram/_mcp/__init__.py +0 -4
  174. scitex/diagram/_mcp/handlers.py +0 -400
  175. scitex/diagram/_mcp/tool_schemas.py +0 -157
  176. scitex/diagram/_presets.py +0 -173
  177. scitex/diagram/_schema.py +0 -182
  178. scitex/diagram/_split.py +0 -278
  179. scitex/plt/_mcp/__init__.py +0 -4
  180. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  181. scitex/plt/_mcp/_handlers_figure.py +0 -195
  182. scitex/plt/_mcp/_handlers_plot.py +0 -252
  183. scitex/plt/_mcp/_handlers_style.py +0 -219
  184. scitex/plt/_mcp/handlers.py +0 -74
  185. scitex/plt/_mcp/tool_schemas.py +0 -497
  186. scitex/plt/mcp_server.py +0 -231
  187. scitex/scholar/data/.gitkeep +0 -0
  188. scitex/scholar/data/README.md +0 -44
  189. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  190. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  191. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  192. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  193. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  194. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  195. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  196. scitex/scholar/data/bib_files/pac.bib +0 -698
  197. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  198. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  199. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  200. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  201. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  202. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  203. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  204. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  205. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  206. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  207. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  208. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  209. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  210. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  211. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  212. scitex/scholar/data/impact_factor.db +0 -0
  213. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  214. scitex/scholar/examples/dev.py +0 -38
  215. scitex-2.14.0.dist-info/METADATA +0 -1238
  216. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/WHEEL +0 -0
  217. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/entry_points.txt +0 -0
  218. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/licenses/LICENSE +0 -0
@@ -369,5 +369,79 @@ def register_scholar_tools(mcp) -> None:
369
369
  result = await get_job_result_handler(job_id=job_id)
370
370
  return _json(result)
371
371
 
372
+ # =========================================================================
373
+ # CrossRef Tools (via crossref-local delegation - 167M+ papers)
374
+ # =========================================================================
375
+
376
+ @mcp.tool()
377
+ async def scholar_crossref_search(
378
+ query: str,
379
+ limit: int = 20,
380
+ offset: int = 0,
381
+ year_min: Optional[int] = None,
382
+ year_max: Optional[int] = None,
383
+ enrich: bool = False,
384
+ ) -> str:
385
+ """[scholar] Search CrossRef database (167M+ papers) via crossref-local. Fast full-text search with optional citation enrichment."""
386
+ from scitex.scholar._mcp.crossref_handlers import crossref_search_handler
387
+
388
+ result = await crossref_search_handler(
389
+ query=query,
390
+ limit=limit,
391
+ offset=offset,
392
+ year_min=year_min,
393
+ year_max=year_max,
394
+ enrich=enrich,
395
+ )
396
+ return _json(result)
397
+
398
+ @mcp.tool()
399
+ async def scholar_crossref_get(
400
+ doi: str,
401
+ include_citations: bool = False,
402
+ include_references: bool = False,
403
+ ) -> str:
404
+ """[scholar] Get paper metadata by DOI from CrossRef database."""
405
+ from scitex.scholar._mcp.crossref_handlers import crossref_get_handler
406
+
407
+ result = await crossref_get_handler(
408
+ doi=doi,
409
+ include_citations=include_citations,
410
+ include_references=include_references,
411
+ )
412
+ return _json(result)
413
+
414
+ @mcp.tool()
415
+ async def scholar_crossref_count(query: str) -> str:
416
+ """[scholar] Count papers matching a query in CrossRef database."""
417
+ from scitex.scholar._mcp.crossref_handlers import crossref_count_handler
418
+
419
+ result = await crossref_count_handler(query=query)
420
+ return _json(result)
421
+
422
+ @mcp.tool()
423
+ async def scholar_crossref_citations(
424
+ doi: str,
425
+ direction: str = "citing",
426
+ limit: int = 100,
427
+ ) -> str:
428
+ """[scholar] Get citation relationships (citing/cited papers) for a DOI."""
429
+ from scitex.scholar._mcp.crossref_handlers import crossref_citations_handler
430
+
431
+ result = await crossref_citations_handler(
432
+ doi=doi,
433
+ direction=direction,
434
+ limit=limit,
435
+ )
436
+ return _json(result)
437
+
438
+ @mcp.tool()
439
+ async def scholar_crossref_info() -> str:
440
+ """[scholar] Get CrossRef database configuration and status info."""
441
+ from scitex.scholar._mcp.crossref_handlers import crossref_info_handler
442
+
443
+ result = await crossref_info_handler()
444
+ return _json(result)
445
+
372
446
 
373
447
  # EOF
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-01-22
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/_mcp_tools/social.py
4
+
5
+ """Social media module tools for FastMCP unified server.
6
+
7
+ All MCP tools delegate to socialia CLI for reproducibility.
8
+ Each tool returns the CLI command used, enabling human reproduction.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import subprocess
15
+ import sys
16
+ from typing import Optional
17
+
18
+ # Import platform strategies from socialia for MCP tool descriptions
19
+ try:
20
+ from scitex.social import PLATFORM_STRATEGIES
21
+ except ImportError:
22
+ try:
23
+ from socialia import PLATFORM_STRATEGIES
24
+ except ImportError:
25
+ PLATFORM_STRATEGIES = """
26
+ ## Platform Strategies (install socialia for full guide)
27
+ - twitter: 280 chars, hook first, 1-2 hashtags at end
28
+ - linkedin: 3000 chars, first 2 lines critical, 3-5 hashtags at end
29
+ - reddit: title is key, no hashtags, value first
30
+ - youtube: keyword-rich title <60 chars, 3-5 hashtags in description
31
+ """
32
+
33
+
34
+ def _json(data: dict) -> str:
35
+ return json.dumps(data, indent=2, default=str)
36
+
37
+
38
+ def _run_socialia_cli(*args: str) -> dict:
39
+ """Run socialia CLI and return structured result."""
40
+ cmd = [sys.executable, "-m", "socialia", "--json", *args]
41
+ cli_command = f"socialia {' '.join(args)}"
42
+
43
+ try:
44
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
45
+
46
+ if result.returncode == 0:
47
+ try:
48
+ data = json.loads(result.stdout)
49
+ data["cli_command"] = cli_command
50
+ return data
51
+ except json.JSONDecodeError:
52
+ return {
53
+ "success": True,
54
+ "output": result.stdout,
55
+ "cli_command": cli_command,
56
+ }
57
+ else:
58
+ return {
59
+ "success": False,
60
+ "error": result.stderr or result.stdout,
61
+ "cli_command": cli_command,
62
+ }
63
+ except subprocess.TimeoutExpired:
64
+ return {
65
+ "success": False,
66
+ "error": "Command timed out",
67
+ "cli_command": cli_command,
68
+ }
69
+ except Exception as e:
70
+ return {
71
+ "success": False,
72
+ "error": str(e),
73
+ "cli_command": cli_command,
74
+ }
75
+
76
+
77
+ def register_social_tools(mcp) -> None:
78
+ """Register social media tools with FastMCP server."""
79
+
80
+ @mcp.tool()
81
+ async def social_post(
82
+ platform: str,
83
+ text: str,
84
+ reply_to: Optional[str] = None,
85
+ quote: Optional[str] = None,
86
+ subreddit: Optional[str] = None,
87
+ title: Optional[str] = None,
88
+ dry_run: bool = False,
89
+ ) -> str:
90
+ """[social] Post content to a social media platform (twitter, linkedin, reddit, youtube).
91
+
92
+ PLATFORM STRATEGIES:
93
+ - twitter: 280 chars. Hook first. 1+ emoji. GitHub URL. 3-5 hashtags at END for SEO
94
+ - linkedin: 3000 chars. First 2 lines critical. Short paragraphs. Include project links. 3-5 hashtags at END
95
+ - reddit: Title is key. NO hashtags. Value first, self-promo last. Link in body
96
+ - youtube: Keyword-rich title <60 chars. Links in description. 3-5 hashtags in description
97
+
98
+ BAD: "SciTeX v2.15.0 released! New feature. #Python #AI"
99
+ GOOD: "Your AI agent can now speak to you remotely.
100
+
101
+ Audio relay bridges the gap.
102
+
103
+ github.com/user/repo
104
+
105
+ #AIAgents #Python"
106
+ """
107
+ args = ["post", platform, text]
108
+
109
+ if reply_to:
110
+ args.extend(["--reply-to", reply_to])
111
+ if quote:
112
+ args.extend(["--quote", quote])
113
+ if subreddit and platform == "reddit":
114
+ args.extend(["--subreddit", subreddit])
115
+ if title:
116
+ args.extend(["--title", title])
117
+ if dry_run:
118
+ args.append("--dry-run")
119
+
120
+ result = _run_socialia_cli(*args)
121
+ return _json(result)
122
+
123
+ @mcp.tool()
124
+ async def social_delete(
125
+ platform: str,
126
+ post_id: str,
127
+ ) -> str:
128
+ """[social] Delete a post from a platform (twitter, linkedin, reddit)."""
129
+ result = _run_socialia_cli("delete", platform, post_id)
130
+ return _json(result)
131
+
132
+ @mcp.tool()
133
+ async def social_status() -> str:
134
+ """[social] Check social media configuration and authentication status."""
135
+ result = _run_socialia_cli("status")
136
+ return _json(result)
137
+
138
+ @mcp.tool()
139
+ async def social_analytics(
140
+ platform: str,
141
+ days: int = 7,
142
+ ) -> str:
143
+ """[social] Get analytics for a platform (twitter, youtube, ga)."""
144
+ result = _run_socialia_cli("analytics", platform, "--days", str(days))
145
+ return _json(result)
146
+
147
+ @mcp.tool()
148
+ async def social_thread(
149
+ platform: str,
150
+ posts: list[str],
151
+ delay: int = 2,
152
+ dry_run: bool = False,
153
+ ) -> str:
154
+ """[social] Post a thread of connected posts. Posts are list of strings."""
155
+ import tempfile
156
+ from pathlib import Path
157
+
158
+ # Write posts to temp file (socialia expects file input)
159
+ thread_content = "\n---\n".join(posts)
160
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
161
+ f.write(thread_content)
162
+ temp_path = f.name
163
+
164
+ try:
165
+ args = ["thread", platform, "--file", temp_path, "--delay", str(delay)]
166
+ if dry_run:
167
+ args.append("--dry-run")
168
+ result = _run_socialia_cli(*args)
169
+ result["thread_posts"] = posts
170
+ return _json(result)
171
+ finally:
172
+ Path(temp_path).unlink(missing_ok=True)
173
+
174
+ @mcp.tool()
175
+ async def social_check_availability() -> str:
176
+ """[social] Check if socialia is installed and list available platforms."""
177
+ try:
178
+ from scitex.social import (
179
+ SOCIALIA_AVAILABLE,
180
+ __socialia_version__,
181
+ )
182
+
183
+ if SOCIALIA_AVAILABLE:
184
+ return _json(
185
+ {
186
+ "available": True,
187
+ "version": __socialia_version__,
188
+ "platforms": ["twitter", "linkedin", "reddit", "youtube"],
189
+ "analytics": ["twitter", "youtube", "ga"],
190
+ }
191
+ )
192
+ else:
193
+ return _json(
194
+ {
195
+ "available": False,
196
+ "error": "socialia not installed",
197
+ "install_command": "pip install socialia",
198
+ }
199
+ )
200
+ except Exception as e:
201
+ return _json(
202
+ {
203
+ "available": False,
204
+ "error": str(e),
205
+ }
206
+ )
207
+
208
+ @mcp.tool()
209
+ async def social_check(
210
+ platform: Optional[str] = None,
211
+ ) -> str:
212
+ """[social] Check platform connection status (v0.1.4+)."""
213
+ args = ["check"]
214
+ if platform:
215
+ args.append(platform)
216
+ result = _run_socialia_cli(*args)
217
+ return _json(result)
218
+
219
+ @mcp.tool()
220
+ async def social_feed(
221
+ platform: Optional[str] = None,
222
+ limit: int = 10,
223
+ mentions: bool = False,
224
+ ) -> str:
225
+ """[social] Get recent posts from platform feeds (v0.1.4+)."""
226
+ args = ["feed"]
227
+ if platform:
228
+ args.append(platform)
229
+ args.extend(["--limit", str(limit)])
230
+ if mentions:
231
+ args.append("--mentions")
232
+ result = _run_socialia_cli(*args)
233
+ return _json(result)
234
+
235
+ @mcp.tool()
236
+ async def social_me(
237
+ platform: str,
238
+ ) -> str:
239
+ """[social] Get user profile information (v0.1.4+)."""
240
+ result = _run_socialia_cli("me", platform)
241
+ return _json(result)
242
+
243
+
244
+ # EOF
@@ -1,220 +1,37 @@
1
1
  #!/usr/bin/env python3
2
- # Timestamp: 2026-01-15
2
+ # Timestamp: 2026-01-20
3
3
  # File: /home/ywatanabe/proj/scitex-code/src/scitex/_mcp_tools/writer.py
4
- """Writer module tools for FastMCP unified server."""
5
-
6
- from __future__ import annotations
7
-
8
- import json
9
- from typing import List, Optional, Union
4
+ """Writer module tools - delegates to scitex-writer package.
10
5
 
6
+ Provides usage instructions for shell-based compilation workflow.
7
+ """
11
8
 
12
- def _json(data: dict) -> str:
13
- return json.dumps(data, indent=2, default=str)
9
+ from __future__ import annotations
14
10
 
15
11
 
16
12
  def register_writer_tools(mcp) -> None:
17
- """Register writer tools with FastMCP server."""
18
-
19
- @mcp.tool()
20
- async def writer_clone_project(
21
- project_dir: str,
22
- git_strategy: str = "child",
23
- branch: Optional[str] = None,
24
- tag: Optional[str] = None,
25
- ) -> str:
26
- """[writer] Create a new LaTeX manuscript project from template."""
27
- from scitex.writer._mcp.handlers import clone_project_handler
28
-
29
- result = await clone_project_handler(
30
- project_dir=project_dir,
31
- git_strategy=git_strategy,
32
- branch=branch,
33
- tag=tag,
34
- )
35
- return _json(result)
36
-
37
- @mcp.tool()
38
- async def writer_compile_manuscript(
39
- project_dir: str,
40
- timeout: int = 300,
41
- no_figs: bool = False,
42
- ppt2tif: bool = False,
43
- crop_tif: bool = False,
44
- quiet: bool = False,
45
- verbose: bool = False,
46
- force: bool = False,
47
- ) -> str:
48
- """[writer] Compile manuscript LaTeX document to PDF."""
49
- from scitex.writer._mcp.handlers import compile_manuscript_handler
50
-
51
- result = await compile_manuscript_handler(
52
- project_dir=project_dir,
53
- timeout=timeout,
54
- no_figs=no_figs,
55
- ppt2tif=ppt2tif,
56
- crop_tif=crop_tif,
57
- quiet=quiet,
58
- verbose=verbose,
59
- force=force,
60
- )
61
- return _json(result)
62
-
63
- @mcp.tool()
64
- async def writer_compile_supplementary(
65
- project_dir: str,
66
- timeout: int = 300,
67
- no_figs: bool = False,
68
- ppt2tif: bool = False,
69
- crop_tif: bool = False,
70
- quiet: bool = False,
71
- ) -> str:
72
- """[writer] Compile supplementary materials LaTeX document to PDF."""
73
- from scitex.writer._mcp.handlers import compile_supplementary_handler
74
-
75
- result = await compile_supplementary_handler(
76
- project_dir=project_dir,
77
- timeout=timeout,
78
- no_figs=no_figs,
79
- ppt2tif=ppt2tif,
80
- crop_tif=crop_tif,
81
- quiet=quiet,
82
- )
83
- return _json(result)
84
-
85
- @mcp.tool()
86
- async def writer_compile_revision(
87
- project_dir: str,
88
- track_changes: bool = False,
89
- timeout: int = 300,
90
- ) -> str:
91
- """[writer] Compile revision document to PDF with optional change tracking."""
92
- from scitex.writer._mcp.handlers import compile_revision_handler
93
-
94
- result = await compile_revision_handler(
95
- project_dir=project_dir,
96
- track_changes=track_changes,
97
- timeout=timeout,
98
- )
99
- return _json(result)
100
-
101
- @mcp.tool()
102
- async def writer_get_project_info(project_dir: str) -> str:
103
- """[writer] Get writer project structure and status information."""
104
- from scitex.writer._mcp.handlers import get_project_info_handler
13
+ """Register writer tools by delegating to scitex-writer package."""
14
+ try:
15
+ from scitex_writer._server import INSTRUCTIONS
105
16
 
106
- result = await get_project_info_handler(project_dir=project_dir)
107
- return _json(result)
17
+ _SCITEX_WRITER_AVAILABLE = True
18
+ except ImportError:
19
+ _SCITEX_WRITER_AVAILABLE = False
20
+ INSTRUCTIONS = None
108
21
 
109
- @mcp.tool()
110
- async def writer_get_pdf(
111
- project_dir: str,
112
- doc_type: str = "manuscript",
113
- ) -> str:
114
- """[writer] Get path to compiled PDF for a document type."""
115
- from scitex.writer._mcp.handlers import get_pdf_handler
22
+ if not _SCITEX_WRITER_AVAILABLE:
116
23
 
117
- result = await get_pdf_handler(
118
- project_dir=project_dir,
119
- doc_type=doc_type,
120
- )
121
- return _json(result)
24
+ @mcp.tool()
25
+ def writer_usage() -> str:
26
+ """[writer] Get usage guide for SciTeX Writer (not installed)."""
27
+ return "scitex-writer is required. Install with: pip install scitex-writer"
122
28
 
123
- @mcp.tool()
124
- async def writer_list_document_types() -> str:
125
- """[writer] List available document types in a writer project."""
126
- from scitex.writer._mcp.handlers import list_document_types_handler
127
-
128
- result = await list_document_types_handler()
129
- return _json(result)
29
+ return
130
30
 
131
31
  @mcp.tool()
132
- async def writer_csv_to_latex(
133
- csv_path: str,
134
- output_path: Optional[str] = None,
135
- caption: Optional[str] = None,
136
- label: Optional[str] = None,
137
- longtable: bool = False,
138
- ) -> str:
139
- """[writer] Convert CSV file to LaTeX table format."""
140
- from scitex.writer._mcp.handlers import csv2latex_handler
141
-
142
- result = await csv2latex_handler(
143
- csv_path=csv_path,
144
- output_path=output_path,
145
- caption=caption,
146
- label=label,
147
- longtable=longtable,
148
- )
149
- return _json(result)
150
-
151
- @mcp.tool()
152
- async def writer_latex_to_csv(
153
- latex_path: str,
154
- output_path: Optional[str] = None,
155
- table_index: int = 0,
156
- ) -> str:
157
- """[writer] Convert LaTeX table to CSV format."""
158
- from scitex.writer._mcp.handlers import latex2csv_handler
159
-
160
- result = await latex2csv_handler(
161
- latex_path=latex_path,
162
- output_path=output_path,
163
- table_index=table_index,
164
- )
165
- return _json(result)
166
-
167
- @mcp.tool()
168
- async def writer_pdf_to_images(
169
- pdf_path: str,
170
- output_dir: Optional[str] = None,
171
- pages: Optional[Union[int, List[int]]] = None,
172
- dpi: int = 150,
173
- format: str = "png",
174
- ) -> str:
175
- """[writer] Render PDF pages as images."""
176
- from scitex.writer._mcp.handlers import pdf_to_images_handler
177
-
178
- result = await pdf_to_images_handler(
179
- pdf_path=pdf_path,
180
- output_dir=output_dir,
181
- pages=pages,
182
- dpi=dpi,
183
- format=format,
184
- )
185
- return _json(result)
186
-
187
- @mcp.tool()
188
- async def writer_list_figures(
189
- project_dir: str,
190
- extensions: Optional[List[str]] = None,
191
- ) -> str:
192
- """[writer] List all figures in a writer project directory."""
193
- from scitex.writer._mcp.handlers import list_figures_handler
194
-
195
- result = await list_figures_handler(
196
- project_dir=project_dir,
197
- extensions=extensions,
198
- )
199
- return _json(result)
200
-
201
- @mcp.tool()
202
- async def writer_convert_figure(
203
- input_path: str,
204
- output_path: str,
205
- dpi: int = 300,
206
- quality: int = 95,
207
- ) -> str:
208
- """[writer] Convert figure between formats (e.g., PDF to PNG, PNG to JPG)."""
209
- from scitex.writer._mcp.handlers import convert_figure_handler
210
-
211
- result = await convert_figure_handler(
212
- input_path=input_path,
213
- output_path=output_path,
214
- dpi=dpi,
215
- quality=quality,
216
- )
217
- return _json(result)
32
+ def writer_usage() -> str:
33
+ """[writer] Get usage guide for SciTeX Writer LaTeX manuscript compilation system."""
34
+ return INSTRUCTIONS
218
35
 
219
36
 
220
37
  # EOF
@@ -1,14 +1,10 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- # Timestamp: "2025-09-30 06:38:18 (ywatanabe)"
4
- # File: /home/ywatanabe/proj/scitex_repo/src/scitex/ai/_gen_ai/_PARAMS.py
5
- # ----------------------------------------
6
- from __future__ import annotations
7
- import os
3
+ # Timestamp: "2026-01-16 04:02:17 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/ai/_gen_ai/_PARAMS.py
5
+
8
6
 
9
7
  __FILE__ = __file__
10
- __DIR__ = os.path.dirname(__FILE__)
11
- # ----------------------------------------
12
8
 
13
9
  THIS_FILE = "/home/ywatanabe/proj/scitex_repo/src/scitex/ai/_gen_ai/PARAMS.py"
14
10
 
@@ -202,6 +198,13 @@ OPENAI_MODELS = [
202
198
  # https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#pricing
203
199
  # https://docs.anthropic.com/en/docs/about-claude/models#model-comparison-table
204
200
  ANTHROPIC_MODELS = [
201
+ {
202
+ "name": "claude-opus-4-5-20251101",
203
+ "input_cost": 5.00,
204
+ "output_cost": 25.00,
205
+ "api_key_env": "ANTHROPIC_API_KEY",
206
+ "provider": "Anthropic",
207
+ },
205
208
  {
206
209
  "name": "claude-opus-4-1-20250805",
207
210
  "input_cost": 15.00,