Sync third-party and MCP marketplace plugins
Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed.
@@ -15,8 +15,8 @@
|
||||
"repo": "https://github.com/Yeachan-Heo/oh-my-codex.git",
|
||||
"ref": "main",
|
||||
"adapter": "codex-plugin",
|
||||
"commit": "e9e3bcc720d964d3673cadb8136394ac103cc091",
|
||||
"syncedAt": "2026-06-25T16:00:00Z"
|
||||
"commit": "d96b698c5f2fabc85c890f7b8fcdc6e02f253ec7",
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "ui-ux-pro-max",
|
||||
@@ -24,8 +24,8 @@
|
||||
"repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
|
||||
"ref": "main",
|
||||
"adapter": "claude-skill",
|
||||
"commit": "9fd25fe07e46ae444edc356e62fe913347ab9e23",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"commit": "65e23199492fa911af32d9078e627ab4de01f4c8",
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "shadcn",
|
||||
@@ -33,8 +33,8 @@
|
||||
"repo": "https://github.com/shadcn-ui/ui.git",
|
||||
"ref": "main",
|
||||
"adapter": "claude-skill",
|
||||
"commit": "c520191cd4c36760ed425b650e139fe6d7e29038",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"commit": "a72491cb9b5f9471392fdc179bbb61739e37ec72",
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "frontend-slides",
|
||||
@@ -69,8 +69,8 @@
|
||||
"repo": "https://github.com/hugohe3/ppt-master.git",
|
||||
"ref": "main",
|
||||
"adapter": "claude-skill",
|
||||
"commit": "47f5051845777839ec29e8d67dd12ae68671854a",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"commit": "13a25616e6354fe5abe16f41da18f532e51ac644",
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "next-skills",
|
||||
@@ -78,8 +78,8 @@
|
||||
"repo": "https://github.com/vercel/next.js.git",
|
||||
"ref": "canary",
|
||||
"adapter": "skill-collection",
|
||||
"commit": "6c22d02ce0c1ba3b8773b314756f388d8f7cbd1a",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"commit": "4b164d765e16de0b277960a27d3938815ac03b97",
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"name": "playwright浏览器自动化操作",
|
||||
"version": "20260605",
|
||||
"keySource": "none",
|
||||
"syncedAt": "2026-06-26T16:01:08Z"
|
||||
"syncedAt": "2026-06-27T16:01:26Z"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "next-skills",
|
||||
"repo": "https://github.com/vercel/next.js.git",
|
||||
"ref": "canary",
|
||||
"commit": "6c22d02ce0c1ba3b8773b314756f388d8f7cbd1a",
|
||||
"commit": "4b164d765e16de0b277960a27d3938815ac03b97",
|
||||
"adapter": "skill-collection",
|
||||
"sourcePath": "skills",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ The two views cross-check each other.
|
||||
|
||||
- Next.js **16.3+** with **Turbopack** — `/_next/mcp` plus the
|
||||
proactive compile check via `get_compilation_issues`.
|
||||
- `agent-browser` **>= 0.31.0** — React introspection, worktree-scoped
|
||||
- `agent-browser` **>= 0.31.1** — React introspection, worktree-scoped
|
||||
`session id`, idempotent `--restore`, and launch flag reconciliation.
|
||||
|
||||
These are hard floors, not soft preferences. If anything is missing,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "oh-my-codex",
|
||||
"version": "0.18.15",
|
||||
"version": "0.18.16",
|
||||
"description": "oh-my-codex 是 Codex CLI 的多 Agent 编排、结构化工作流、插件级 hooks、MCP 和 HUD 扩展插件。",
|
||||
"author": {
|
||||
"name": "Yeachan Heo",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "oh-my-codex",
|
||||
"repo": "https://github.com/Yeachan-Heo/oh-my-codex.git",
|
||||
"ref": "main",
|
||||
"commit": "e9e3bcc720d964d3673cadb8136394ac103cc091",
|
||||
"commit": "d96b698c5f2fabc85c890f7b8fcdc6e02f253ec7",
|
||||
"adapter": "codex-plugin",
|
||||
"sourcePath": "plugins/oh-my-codex",
|
||||
"syncedAt": "2026-06-25T16:00:00Z"
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ PPT Master runs in **any tool with agent capability** — read/write files, exec
|
||||
|
||||
> **Model recommendation**: for the best results, use **Claude Opus** with `gpt-image-2`; **Gemini 3.5 Flash** currently offers great overall value for money — notably fast and well worth a try.
|
||||
|
||||
**🔑 Want to use Claude / GPT / Gemini but don't have access yet?** Project sponsors **[PackyCode](https://www.packyapi.com/register?aff=ppt-master)**, **[APIKEY.FUN](https://apikey.fun/register?aff=PPT-MASTER)** and **[RunAPI](https://runapi.co/register?aff=WMLJ)** can help — all offer pay-as-you-go access to Claude, GPT, Gemini and more, no subscription required. **PackyCode**: 10% off with promo code **`ppt-master`** at top-up. **APIKEY.FUN**: prices as low as **7% of official rates**; register via our link for an exclusive permanent discount of up to 5% on top-ups. **RunAPI**: 150+ models via one API Key at prices as low as **10% of official rates**; register and contact an administrator to claim **¥7 in free credit**.
|
||||
**🔑 Want to use Claude / GPT / Gemini but don't have access yet?** Project sponsors **[PackyCode](https://www.packyapi.com/register?aff=ppt-master)**, **[APIKEY.FUN](https://apikey.fun/register?aff=PPT-MASTER)** and **[RunAPI](https://runapi.co/register?aff=WMLJ)** offer pay-as-you-go access to Claude, GPT, Gemini and more — no subscription required, with exclusive discounts for our users (details at the top of this page).
|
||||
|
||||
**🔀 Juggling several providers?** Once you hold keys from more than one of them, [cc-switch](https://github.com/farion1231/cc-switch) — a cross-platform desktop app — lets you one-click switch API providers for Claude Code, Codex, Gemini CLI and more, no manual config editing.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "ppt-master",
|
||||
"repo": "https://github.com/hugohe3/ppt-master.git",
|
||||
"ref": "main",
|
||||
"commit": "47f5051845777839ec29e8d67dd12ae68671854a",
|
||||
"commit": "13a25616e6354fe5abe16f41da18f532e51ac644",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": "skills/ppt-master",
|
||||
"syncedAt": "2026-06-26T15:59:59Z"
|
||||
"syncedAt": "2026-06-27T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ templates/
|
||||
│ └── pixel_retro/ # Pixel retro / cyberpunk structure (no identity)
|
||||
└── decks/
|
||||
├── 招商银行/ # China Merchants Bank full PPT replica
|
||||
└── 中国电建_常规/ # PowerChina full PPT replica
|
||||
└── 中国电建/ # PowerChina full PPT replica
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -28,6 +28,10 @@ import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
|
||||
@@ -28,6 +28,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from svg_to_pptx.animation_config import ( # noqa: E402
|
||||
build_group_listing,
|
||||
load_animation_config,
|
||||
@@ -35,6 +36,8 @@ from svg_to_pptx.animation_config import ( # noqa: E402
|
||||
write_scaffold,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
|
||||
@@ -16,6 +16,10 @@ import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
from project_utils import (
|
||||
find_all_projects,
|
||||
|
||||
@@ -38,10 +38,13 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from pptx_to_svg.color_resolver import ColorPalette # noqa: E402
|
||||
from pptx_to_svg.emu_units import NS # noqa: E402
|
||||
from pptx_to_svg.ooxml_loader import OoxmlPackage # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def _font_pair(theme_root, font_tag: str) -> dict[str, str]:
|
||||
"""Read one <a:majorFont> / <a:minorFont> into {latin, ea} (skip empties)."""
|
||||
|
||||
@@ -30,6 +30,10 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def _images_by_slide(manifest: list) -> dict[int, list[dict]]:
|
||||
"""Map slide_index -> [image entries on that slide], from ppt_to_md occurrences."""
|
||||
|
||||
@@ -23,6 +23,10 @@ import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def scan_svg_file(svg_path: Path) -> list[dict]:
|
||||
"""Scan a single SVG file for edit annotations."""
|
||||
|
||||
@@ -20,6 +20,10 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Path Configuration
|
||||
|
||||
@@ -50,6 +50,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent.parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from server_common import ( # noqa: E402
|
||||
claim_lock as _claim_lock,
|
||||
find_free_port as _find_free_port,
|
||||
@@ -58,6 +59,8 @@ from server_common import ( # noqa: E402
|
||||
release_lock as _release_lock,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
logger = logging.getLogger('confirm_ui')
|
||||
|
||||
# Per-project lock file. Lives at <project_path>/.confirm_ui.lock and matches
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Console encoding helpers for PPT Master CLI scripts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import sys
|
||||
from typing import TextIO
|
||||
|
||||
|
||||
def _reconfigure_stream(stream: TextIO) -> TextIO:
|
||||
try:
|
||||
stream.reconfigure(encoding="utf-8", errors="replace")
|
||||
return stream
|
||||
except AttributeError:
|
||||
buffer = getattr(stream, "buffer", None)
|
||||
if buffer is None:
|
||||
return stream
|
||||
return io.TextIOWrapper(buffer, encoding="utf-8", errors="replace")
|
||||
except (OSError, ValueError):
|
||||
return stream
|
||||
|
||||
|
||||
def configure_utf8_stdio() -> None:
|
||||
"""Use UTF-8 for CLI stdout/stderr, including Windows non-UTF-8 locales."""
|
||||
sys.stdout = _reconfigure_stream(sys.stdout)
|
||||
sys.stderr = _reconfigure_stream(sys.stderr)
|
||||
@@ -8,6 +8,10 @@ Provides user-friendly error messages and specific fix suggestions.
|
||||
import argparse
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
class ErrorHelper:
|
||||
"""Error message helper."""
|
||||
|
||||
@@ -37,6 +37,10 @@ from pathlib import Path
|
||||
from typing import Optional
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
SVG_NS = "http://www.w3.org/2000/svg"
|
||||
DRAWABLE = {"path", "polygon", "polyline", "rect", "circle", "ellipse", "line"}
|
||||
SEMANTIC_CONTENT = {"text", "tspan", "foreignObject"}
|
||||
|
||||
@@ -39,6 +39,10 @@ import shutil
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
# Import finalize helpers from the internal package.
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from svg_finalize.align_embed_images import (
|
||||
|
||||
@@ -26,12 +26,16 @@ import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
# Import modules from the same directory
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
# Algorithm parameters
|
||||
ALPHA_THRESHOLD = 0.002 # Alpha threshold; values below this are not processed
|
||||
MAX_ALPHA = 0.99 # Maximum alpha value to prevent division by zero
|
||||
|
||||
@@ -14,6 +14,10 @@ from pathlib import Path
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
from project_utils import find_all_projects, get_project_info, CANVAS_FORMATS
|
||||
except ImportError:
|
||||
|
||||
@@ -33,6 +33,10 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
_LIB_ALIASES = {"chunk": "chunk-filled"}
|
||||
_GLOBAL_ICONS_DIR = Path(__file__).resolve().parent.parent / "templates" / "icons"
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -4,6 +4,15 @@ Shared helpers for image generation backends.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -15,6 +15,15 @@ Dependencies:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -22,6 +22,15 @@ Dependencies:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -9,6 +9,15 @@ Configuration keys:
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -53,8 +53,11 @@ import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from config import load_prefixed_env_file, resolve_env_path
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
ENV_PATH = resolve_env_path()
|
||||
IMAGE_ENV_PREFIXES = (
|
||||
"IMAGE_",
|
||||
|
||||
@@ -57,6 +57,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from config import load_prefixed_env_file # noqa: E402
|
||||
from image_backends.backend_common import download_image # noqa: E402
|
||||
from image_sources.provider_common import ( # noqa: E402
|
||||
@@ -68,6 +69,8 @@ from image_sources.provider_common import ( # noqa: E402
|
||||
score_candidate,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Provider registry
|
||||
|
||||
@@ -17,6 +17,15 @@ the corresponding provider_<name>.py module and only imports from here.
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
@@ -25,7 +34,6 @@ if __name__ == "__main__":
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ API docs: https://api.openverse.org/v1/
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -10,6 +10,15 @@ API docs: https://www.pexels.com/api/documentation/
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -10,6 +10,15 @@ API docs: https://pixabay.com/api/docs/
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -13,6 +13,15 @@ API docs: https://www.mediawiki.org/wiki/API:Search
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__doc__)
|
||||
|
||||
@@ -32,12 +32,17 @@ import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
DEFAULT_DPI = 300
|
||||
DEFAULT_TRANSPARENT_TOLERANCE = 12
|
||||
DEFAULT_MANIFEST = "images/formula_manifest.json"
|
||||
|
||||
@@ -30,8 +30,11 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from native_narration_pptx import main # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
@@ -41,6 +41,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from pptx_animations import TRANSITIONS, create_transition_xml # noqa: E402
|
||||
from svg_to_pptx.pptx_builder import ( # noqa: E402
|
||||
_add_default_content_type,
|
||||
@@ -65,6 +66,8 @@ from svg_to_pptx.pptx_notes import ( # noqa: E402
|
||||
markdown_to_plain_text,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
PROJECT_SCHEMA = "native_pptx_enhancement_project.v1"
|
||||
LEGACY_PROJECT_SCHEMAS = {"native_narration_pptx_project.v1"}
|
||||
|
||||
@@ -30,6 +30,7 @@ import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from config import load_prefixed_env_file
|
||||
from tts_backends import (
|
||||
backend_cosyvoice,
|
||||
@@ -39,6 +40,8 @@ from tts_backends import (
|
||||
backend_qwen,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AudioBackend:
|
||||
|
||||
@@ -42,6 +42,10 @@ Usage:
|
||||
import argparse
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Transition effect definitions
|
||||
|
||||
@@ -29,9 +29,12 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from beautify_identity import extract_identity # noqa: E402
|
||||
from template_fill_pptx.analyzer import analyze_pptx # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def _write_json(path: Path, payload: dict[str, Any]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -22,8 +22,11 @@ import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from template_import.manifest import build_manifest
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Build the CLI argument parser for the import entry point."""
|
||||
|
||||
@@ -30,9 +30,12 @@ from pathlib import Path
|
||||
# Allow running this script from anywhere
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from pptx_to_svg import convert_pptx_to_svg
|
||||
from pptx_to_svg.converter import ConvertOptions
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
|
||||
@@ -13,6 +13,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import filecmp
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -21,6 +22,8 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
try:
|
||||
from project_utils import (
|
||||
CANVAS_FORMATS,
|
||||
@@ -65,6 +68,9 @@ IMAGE_ASSET_SUFFIXES = {
|
||||
}
|
||||
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def _curl_cffi_available() -> bool:
|
||||
"""Return whether curl_cffi is importable (enables Python TLS impersonation)."""
|
||||
try:
|
||||
@@ -233,6 +239,9 @@ class ProjectManager:
|
||||
return destination
|
||||
|
||||
def _run_tool(self, args: list[str]) -> None:
|
||||
child_env = os.environ.copy()
|
||||
child_env["PYTHONUTF8"] = "1"
|
||||
child_env["PYTHONIOENCODING"] = "utf-8:replace"
|
||||
try:
|
||||
result = subprocess.run(
|
||||
args,
|
||||
@@ -242,6 +251,7 @@ class ProjectManager:
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
env=child_env,
|
||||
)
|
||||
except FileNotFoundError as exc:
|
||||
raise RuntimeError(f"Missing executable: {args[0]}") from exc
|
||||
|
||||
@@ -12,6 +12,10 @@ from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
# Canvas format definitions (unified source)
|
||||
try:
|
||||
from config import CANVAS_FORMATS
|
||||
|
||||
@@ -39,12 +39,17 @@ import sys
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
try:
|
||||
import yaml # type: ignore
|
||||
except ImportError:
|
||||
yaml = None
|
||||
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
SKILL_DIR = SCRIPT_DIR.parent
|
||||
TEMPLATES_DIR = SKILL_DIR / "templates"
|
||||
|
||||
@@ -18,6 +18,11 @@ import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Union, Any, Optional
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
from PIL import Image, ExifTags
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,14 @@ from pathlib import Path
|
||||
from urllib.parse import unquote, urlparse
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Format registry
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -20,6 +20,14 @@ from datetime import date, datetime, time
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Format registry
|
||||
|
||||
@@ -14,6 +14,14 @@ import sys
|
||||
from pathlib import Path
|
||||
from collections import Counter
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
import fitz # PyMuPDF
|
||||
except ImportError:
|
||||
|
||||
@@ -34,11 +34,19 @@ from io import BytesIO
|
||||
from pathlib import Path
|
||||
from urllib.parse import quote
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
from pptx import Presentation
|
||||
from pptx.enum.action import PP_ACTION
|
||||
from pptx.enum.shapes import MSO_SHAPE_TYPE
|
||||
from pptx.oxml.ns import qn
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
EMU_PER_INCH = 914400
|
||||
OFFICE_VECTOR_EXTENSIONS = {"emf", "wmf"}
|
||||
|
||||
@@ -35,8 +35,17 @@ import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from urllib.parse import urljoin, urlparse
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
import requests
|
||||
from bs4 import BeautifulSoup, NavigableString, Tag
|
||||
|
||||
@@ -59,6 +59,7 @@ _ROOT_SCRIPTS_DIR = _SCRIPTS_DIR.parent
|
||||
if str(_ROOT_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_ROOT_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from server_common import ( # noqa: E402
|
||||
claim_lock as _claim_lock,
|
||||
find_free_port as _find_free_port,
|
||||
@@ -67,6 +68,8 @@ from server_common import ( # noqa: E402
|
||||
release_lock as _release_lock,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
from annotations import ( # noqa: E402
|
||||
assign_temp_ids,
|
||||
is_editable_attr,
|
||||
|
||||
@@ -54,6 +54,14 @@ from typing import TYPE_CHECKING
|
||||
from urllib.parse import unquote
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __package__ in {None, ''}:
|
||||
import types
|
||||
|
||||
|
||||
@@ -24,6 +24,14 @@ from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
from urllib.parse import unquote
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
|
||||
@@ -51,6 +51,14 @@ import argparse
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# Default icon directory
|
||||
DEFAULT_ICONS_DIR = Path(__file__).parent.parent.parent / 'templates' / 'icons'
|
||||
|
||||
@@ -17,6 +17,15 @@ import base64
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def get_mime_type(filename: str, file_bytes: bytes | None = None) -> str:
|
||||
|
||||
@@ -31,6 +31,14 @@ import argparse
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
# Try to import PIL for getting image dimensions
|
||||
try:
|
||||
from PIL import Image
|
||||
|
||||
@@ -2,8 +2,17 @@ import os
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
SVG_NS = "http://www.w3.org/2000/svg"
|
||||
NSMAP = {"svg": SVG_NS}
|
||||
|
||||
@@ -26,6 +26,14 @@ from pathlib import Path
|
||||
from typing import Any, Tuple
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def rect_to_rounded_path(
|
||||
x: float,
|
||||
|
||||
@@ -19,6 +19,10 @@ from typing import List, Dict, Tuple
|
||||
from collections import Counter, defaultdict
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
try:
|
||||
from project_utils import CANVAS_FORMATS
|
||||
from error_helper import ErrorHelper
|
||||
|
||||
@@ -11,7 +11,10 @@ from pathlib import Path
|
||||
# Ensure the scripts directory is on sys.path so the package can be found
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from svg_to_pptx import main
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -9,6 +9,14 @@ import argparse
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __package__ in {None, ''}:
|
||||
import types
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ from pathlib import Path
|
||||
# Ensure the scripts directory is on sys.path so the package can be found.
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from template_fill_pptx import main
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
@@ -8,6 +8,14 @@ import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __package__ in {None, ''}:
|
||||
import types
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ import argparse
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
HEADING_RE = re.compile(r'^(#{1,6})\s*(.+?)\s*$')
|
||||
HR_RE = re.compile(r'^\s*[-*]{3,}\s*$')
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
TOOLS_DIR = Path(__file__).resolve().parent
|
||||
SKILL_DIR = TOOLS_DIR.parent
|
||||
|
||||
@@ -27,6 +27,10 @@ import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
HEX_RE = re.compile(r"^#(?:[0-9A-Fa-f]{3,4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$")
|
||||
FONT_FAMILY_RE = re.compile(r"""(font-family\s*=\s*)(["'])(.*?)\2""")
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ import urllib.request
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
# Histogram threshold: PNG counts as "all background" if a single quantized
|
||||
# color bucket holds >= ALL_BG_THRESHOLD of pixels. Guards against blank
|
||||
|
||||
@@ -6,5 +6,13 @@
|
||||
"google": {
|
||||
"summary": "Google brand identity — multi-product corporate decks, developer events (Google I/O style), education and training in the Google ecosystem",
|
||||
"primary_color": "#4285F4"
|
||||
},
|
||||
"中国电建": {
|
||||
"summary": "POWERCHINA brand identity for engineering project reports, technical proposals, business negotiations, and corporate promotion",
|
||||
"primary_color": "#00418D"
|
||||
},
|
||||
"中汽研": {
|
||||
"summary": "CATARC brand identity for product certification, evaluation reports, automotive technology promotion, and business visits",
|
||||
"primary_color": "#004098"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
brand_id: 中国电建
|
||||
kind: brand
|
||||
summary: POWERCHINA brand identity for engineering project reports, technical proposals, business negotiations, and corporate promotion
|
||||
primary_color: "#00418D"
|
||||
---
|
||||
|
||||
# POWERCHINA (中国电建) Brand Specification
|
||||
|
||||
> Identity-only preset. No SVG page roster; pages are composed freely under these brand constraints.
|
||||
|
||||
## I. Brand Overview
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| Brand Name | POWERCHINA / 中国电建 |
|
||||
| Use Cases | Engineering project reports, technical proposal presentations, business negotiations, corporate promotion, annual summaries |
|
||||
| Tone | Professional, composed, international, state-owned enterprise style |
|
||||
|
||||
## II. Color Scheme
|
||||
|
||||
| Role | HEX | Provenance | Notes |
|
||||
|---|---|---|---|
|
||||
| primary | `#00418D` | approx | POWERCHINA Blue, inherited from the existing POWERCHINA deck templates |
|
||||
| secondary | `#002B5C` | approx | Deep blue for chapter pages, dark headers, and gradient bases |
|
||||
| accent (blue) | `#0066CC` | approx | Bright blue for charts, links, and secondary emphasis |
|
||||
| accent (light) | `#4A90D9` | approx | Sky blue for tertiary highlights and decorative rules |
|
||||
| accent (red) | `#C41E3A` | approx | China red for milestones, key data, and national-strength emphasis |
|
||||
| accent (gold) | `#C9A227` | approx | Honors, achievements, and award moments |
|
||||
| text | `#1A1A1A` | approx | Primary body text on light backgrounds |
|
||||
| muted-text | `#4A5568` | approx | Secondary descriptions and annotations |
|
||||
| bg | `#FFFFFF` | approx | Standard light presentation background |
|
||||
| surface | `#F4F6F8` | approx | Light gray card and module surfaces |
|
||||
|
||||
## III. Typography
|
||||
|
||||
| Role | Family | Weight |
|
||||
|---|---|---|
|
||||
| title | `"Microsoft YaHei", "微软雅黑", "SimHei", Arial, sans-serif` | 700 |
|
||||
| body | `"Microsoft YaHei", "微软雅黑", Arial, sans-serif` | 400 |
|
||||
| data | `Arial, "Microsoft YaHei", sans-serif` | 600-700 |
|
||||
|
||||
Use PowerPoint-safe CJK fonts by default. Keep English technical labels in Arial when they function as engineering annotations or dashboard labels.
|
||||
|
||||
## IV. Logo
|
||||
|
||||
POWERCHINA templates may use the group brand logo or subsidiary logos depending on the presenting entity. Pick one primary logo per deck and avoid mixing several logos on every page.
|
||||
|
||||
| File | Form | Usage |
|
||||
|---|---|---|
|
||||
| `./电建logo.png` | POWERCHINA symbol / primary mark (234x236) | Cover, ending, and compact brand moments where the group identity is required |
|
||||
| `./中国水务logo.png` | China Water logo lockup (1108x190) | Subsidiary-led water-business reports; cover or ending lockup |
|
||||
| `./华东院logo.png` | East China Institute logo lockup (1438x300) | Institute-led technical reports and engineering proposals |
|
||||
| `./水电三局logo.png` | Sinohydro Bureau 3 logo lockup (629x75) | Bureau-led project reports and construction updates |
|
||||
|
||||
- Cover / ending: use the selected primary logo at readable size.
|
||||
- Per-page header: optional; use a compact logo only when it does not crowd the title bar.
|
||||
- Dark backgrounds: prefer white/inverted treatment when available; otherwise place the logo on a white backing plate.
|
||||
- Clearspace: leave at least 0.5x logo height around the mark or lockup.
|
||||
|
||||
## V. Voice & Tone
|
||||
|
||||
- Formality: formal
|
||||
- Person: organization-first, "we / 我们" when speaking as the company
|
||||
- Emoji: avoid
|
||||
- Abbreviations: spell out Chinese organization names on first use; POWERCHINA is acceptable after first mention
|
||||
- Style: emphasize engineering reliability, delivery capability, safety, scale, and public-sector credibility
|
||||
|
||||
## VI. Icon Style
|
||||
|
||||
- Preference: filled or sturdy stroke icons
|
||||
- Recommended libraries: `tabler-filled`, `chunk-filled`, or `tabler-outline` with heavier stroke
|
||||
- Avoid thin decorative icons for engineering / construction content; prefer solid symbols, process arrows, infrastructure metaphors, and chart-friendly pictograms.
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
@@ -0,0 +1,72 @@
|
||||
---
|
||||
brand_id: 中汽研
|
||||
kind: brand
|
||||
summary: CATARC brand identity for product certification, evaluation reports, automotive technology promotion, and business visits
|
||||
primary_color: "#004098"
|
||||
---
|
||||
|
||||
# CATARC (中汽研) Brand Specification
|
||||
|
||||
> Identity-only preset. No SVG page roster; pages are composed freely under these brand constraints.
|
||||
|
||||
## I. Brand Overview
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| Brand Name | CATARC / 中汽研 |
|
||||
| Use Cases | Product certification display, evaluation presentations, automotive technology promotion, business visits, high-end technical reporting |
|
||||
| Tone | Professional, authoritative, trustworthy, technical-consulting style |
|
||||
|
||||
## II. Color Scheme
|
||||
|
||||
| Role | HEX | Provenance | Notes |
|
||||
|---|---|---|---|
|
||||
| primary | `#004098` | approx | CATARC deep blue, inherited from the standard CATARC deck template |
|
||||
| secondary | `#003366` | approx | Dark business blue for covers, chapter pages, and formal section headers |
|
||||
| accent (blue) | `#0050B3` | approx | Bright blue for technology emphasis and gradients |
|
||||
| accent (tech) | `#1890FF` | approx | Modern tech blue for forward-looking automotive topics |
|
||||
| accent (cyan) | `#00E5FF` | approx | High-energy data / future-tech highlights; use sparingly |
|
||||
| accent (red) | `#CC0000` | approx | Certification warnings, failed checks, and key risk emphasis |
|
||||
| text | `#333333` | approx | Primary body text on light backgrounds |
|
||||
| muted-text | `#666666` | approx | Secondary descriptions and notes |
|
||||
| bg | `#FFFFFF` | approx | Standard light presentation background |
|
||||
| surface | `#F5F5F5` | approx | Secondary content blocks and cards |
|
||||
| border | `#E0E0E0` | approx | Dividers, table borders, and technical grids |
|
||||
|
||||
## III. Typography
|
||||
|
||||
| Role | Family | Weight |
|
||||
|---|---|---|
|
||||
| title | `"Microsoft YaHei", "微软雅黑", "SimHei", Arial, Calibri, sans-serif` | 700 |
|
||||
| body | `"Microsoft YaHei", "微软雅黑", Arial, Calibri, sans-serif` | 400 |
|
||||
| data | `Arial, "Microsoft YaHei", sans-serif` | 600-700 |
|
||||
|
||||
Use clear PowerPoint-safe CJK fonts. Keep numbers, certification codes, and technical abbreviations in Arial for legibility.
|
||||
|
||||
## IV. Logo
|
||||
|
||||
CATARC uses separate large and header lockups. Choose the large logo for brand moments and the compact logo for page chrome.
|
||||
|
||||
| File | Form | Usage |
|
||||
|---|---|---|
|
||||
| `./大型 logo.png` | Large CATARC lockup (592x238) | Cover hero, chapter/ending brand moments, and dark page lockups |
|
||||
| `./右上角 logo.png` | Compact header logo (113x50) | Upper-right page header, title bar, and navigation areas |
|
||||
|
||||
- Cover / ending: use `大型 logo.png` where the brand must read strongly.
|
||||
- Content pages: use `右上角 logo.png` only when the layout has enough title-bar space.
|
||||
- Watermarks: large logo may be used as a very faint watermark on content pages.
|
||||
- Clearspace: leave at least 0.5x logo height around the mark or lockup.
|
||||
|
||||
## V. Voice & Tone
|
||||
|
||||
- Formality: formal-neutral
|
||||
- Person: organization-first, "we / 我们" only when speaking as CATARC
|
||||
- Emoji: avoid
|
||||
- Abbreviations: CATARC is acceptable; spell out Chinese entity names on first use
|
||||
- Style: emphasize certification credibility, testing rigor, technical evidence, automotive industry insight, and trusted advisory authority
|
||||
|
||||
## VI. Icon Style
|
||||
|
||||
- Preference: filled or clean stroke icons
|
||||
- Recommended libraries: `tabler-filled`, `chunk-filled`, or `tabler-outline`
|
||||
- Prefer automotive, certification, testing, dashboard, data, process, and compliance metaphors. Avoid playful or consumer-app icon styling.
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
@@ -5,36 +5,18 @@
|
||||
"page_count": 5,
|
||||
"primary_color": "#C00000"
|
||||
},
|
||||
"中国电建_常规": {
|
||||
"中国电建": {
|
||||
"summary": "Engineering project reports, technical proposal presentations, business negotiations, corporate promotion, annual summaries.",
|
||||
"canvas_format": "ppt169",
|
||||
"page_count": 5,
|
||||
"primary_color": "#00418D"
|
||||
},
|
||||
"中国电建_现代": {
|
||||
"summary": "Major engineering reports, international market promotion, technology achievement showcases, high-end business negotiations.",
|
||||
"canvas_format": "ppt169",
|
||||
"page_count": 5,
|
||||
"primary_color": "#00418D"
|
||||
},
|
||||
"中汽研_商务": {
|
||||
"summary": "Product certification display, evaluation presentations, technology promotion, high-end business reporting.",
|
||||
"canvas_format": "ppt169",
|
||||
"page_count": 5,
|
||||
"primary_color": "#003366"
|
||||
},
|
||||
"中汽研_常规": {
|
||||
"中汽研": {
|
||||
"summary": "Product certification display, evaluation presentations, technology promotion, business visits.",
|
||||
"canvas_format": "ppt169",
|
||||
"page_count": 5,
|
||||
"primary_color": "#004098"
|
||||
},
|
||||
"中汽研_现代": {
|
||||
"summary": "Forward-looking technology showcases, strategic releases, high-end business reporting.",
|
||||
"canvas_format": "ppt169",
|
||||
"page_count": 5,
|
||||
"primary_color": "#001529"
|
||||
},
|
||||
"招商银行": {
|
||||
"summary": "交易银行产品介绍、销售收款方案汇报、客户案例拆解、分行培训材料.",
|
||||
"canvas_format": "ppt169",
|
||||
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
@@ -1,5 +1,5 @@
|
||||
---
|
||||
deck_id: 中国电建_常规
|
||||
deck_id: 中国电建
|
||||
kind: deck
|
||||
summary: Engineering project reports, technical proposal presentations, business negotiations, corporate promotion, annual summaries.
|
||||
canvas_format: ppt169
|
||||
@@ -17,7 +17,7 @@ primary_color: "#00418D"
|
||||
|
||||
| Property | Description |
|
||||
| -------------- | ---------------------------------------------------------------- |
|
||||
| **Template Name** | 中国电建_常规 (formerly powerchina) |
|
||||
| **Template Name** | 中国电建 |
|
||||
| **Use Cases** | Engineering project reports, technical proposal presentations, business negotiations, corporate promotion, annual summaries |
|
||||
| **Design Tone** | Professional, composed, international, state-owned enterprise style |
|
||||
| **Theme Mode** | Light theme (white background + POWERCHINA blue accent) |
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
@@ -1,90 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
||||
<!-- 模板: 封面页 - 中国电建现代风 (POWERCHINA Modern) -->
|
||||
|
||||
<defs>
|
||||
<!-- 主背景渐变: 深海蓝 -> 科技蓝 -->
|
||||
<linearGradient id="mainGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#001F45;stop-opacity:1" />
|
||||
<stop offset="50%" style="stop-color:#003270;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00418D;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- 装饰渐变: 亮蓝 -> 透明 -->
|
||||
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#0066CC;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00418D;stop-opacity:0" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- 地球经纬网格 (Global Grid) -->
|
||||
<pattern id="grid" x="0" y="0" width="100" height="50" patternUnits="userSpaceOnUse">
|
||||
<path d="M 100 0 L 0 0 0 50" fill="none" stroke="#FFFFFF" stroke-opacity="0.05" stroke-width="1"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<!-- 背景层 -->
|
||||
<rect width="1280" height="720" fill="url(#mainGrad)"/>
|
||||
<rect width="1280" height="720" fill="url(#grid)"/>
|
||||
|
||||
<!-- 底部基石 (Foundation Block) -->
|
||||
<!-- 象征大坝地基或坚实基础 -->
|
||||
<path d="M0,580 L1280,500 L1280,720 L0,720 Z" fill="#001533" fill-opacity="0.6"/>
|
||||
<rect x="0" y="680" width="1280" height="40" fill="#000F24"/>
|
||||
|
||||
<!-- 装饰线条 (Construction Lines) -->
|
||||
<!-- 对角线切角,体现切割感 -->
|
||||
<path d="M0,0 L400,0 L300,720 L0,720 Z" fill="#FFFFFF" fill-opacity="0.02"/>
|
||||
<line x1="300" y1="0" x2="300" y2="720" stroke="#FFFFFF" stroke-opacity="0.05" stroke-dasharray="10,5"/>
|
||||
|
||||
<!-- 顶部 Logo 区域 (右上角) -->
|
||||
<rect x="1000" y="0" width="280" height="80" fill="#FFFFFF" fill-opacity="0.1"/>
|
||||
<text x="1140" y="50" text-anchor="middle" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="#FFFFFF" letter-spacing="2">
|
||||
POWERCHINA
|
||||
</text>
|
||||
|
||||
<!-- 装饰红条 (点睛) -->
|
||||
<rect x="1000" y="0" width="8" height="80" fill="#C41E3A"/>
|
||||
|
||||
<!-- 主标题区域 (居中偏左) -->
|
||||
<g transform="translate(100, 260)">
|
||||
|
||||
<!-- 巨大装饰年份或序号 -->
|
||||
<text x="-20" y="-60" font-family="Arial, sans-serif" font-size="180" font-weight="bold" fill="#FFFFFF" fill-opacity="0.03">
|
||||
2026
|
||||
</text>
|
||||
|
||||
<!-- 主标题 -->
|
||||
<text x="0" y="0" font-family="Microsoft YaHei, SimHei, sans-serif" font-size="64" font-weight="bold" fill="#FFFFFF" letter-spacing="2">
|
||||
{{TITLE}}
|
||||
</text>
|
||||
|
||||
<!-- 下划线装饰 -->
|
||||
<rect x="0" y="25" width="120" height="8" fill="#0066CC"/>
|
||||
<rect x="120" y="25" width="800" height="2" fill="#FFFFFF" fill-opacity="0.3"/>
|
||||
|
||||
<!-- 副标题 -->
|
||||
<text x="0" y="80" font-family="Microsoft YaHei, Arial, sans-serif" font-size="32" fill="#B0C4DE" font-weight="normal">
|
||||
{{SUBTITLE}}
|
||||
</text>
|
||||
|
||||
<!-- 汇报信息组 -->
|
||||
<g transform="translate(0, 160)">
|
||||
<!-- 左侧竖线 -->
|
||||
<rect x="0" y="0" width="4" height="80" fill="#C41E3A"/>
|
||||
|
||||
<text x="20" y="30" font-family="Microsoft YaHei, sans-serif" font-size="24" fill="#FFFFFF">
|
||||
{{AUTHOR}}
|
||||
</text>
|
||||
<text x="20" y="70" font-family="Microsoft YaHei, sans-serif" font-size="20" fill="#FFFFFF" fill-opacity="0.7">
|
||||
汇报人:{{PRESENTER}} | {{DATE}}
|
||||
</text>
|
||||
</g>
|
||||
|
||||
</g>
|
||||
|
||||
<!-- 底部公司全称 -->
|
||||
<text x="640" y="708" text-anchor="middle" font-family="Microsoft YaHei, sans-serif" font-size="14" fill="#FFFFFF" fill-opacity="0.4" letter-spacing="1">
|
||||
中国电力建设集团有限公司 · POWERCHINA CONSTRUCTION CORPORATION
|
||||
</text>
|
||||
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |