Skip to content

fix: enable shiki highlighting for t2i templates#7501

Open
camera-2018 wants to merge 1 commit intoAstrBotDevs:masterfrom
camera-2018:fix-t2i-template-add-shiki
Open

fix: enable shiki highlighting for t2i templates#7501
camera-2018 wants to merge 1 commit intoAstrBotDevs:masterfrom
camera-2018:fix-t2i-template-add-shiki

Conversation

@camera-2018
Copy link
Copy Markdown
Contributor

Modifications / 改动点

给t2i模板添加代码高亮

  1. 改动前
    f5ec249b912cc362ce61b8a54d989d8d

2.改动后
image
image

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果


Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Copilot AI review requested due to automatic review settings April 13, 2026 02:54
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Apr 13, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @camera-2018, your pull request is larger than the review limit of 150000 diff characters

@dosubot dosubot bot added the area:webui The bug / feature is about webui(dashboard) of astrbot. label Apr 13, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Shiki-based syntax highlighting support for T2I HTML templates by bundling a browser-ready Shiki runtime and wiring it into the network render flow/templates.

Changes:

  • Introduces a Vite build script to generate an IIFE Shiki runtime bundle for a curated set of languages/themes.
  • Updates T2I templates to inline the Shiki runtime, base64-decode the markdown source, render with marked, and then highlight code blocks + render KaTeX.
  • Updates the network T2I renderer to inject the Shiki runtime and provide text_base64 for templates.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
dashboard/scripts/build-t2i-shiki-runtime.mjs Builds the bundled Shiki runtime used by T2I templates.
dashboard/package.json Adds a script entry to run the Shiki runtime build.
astrbot/core/utils/t2i/template/base.html Uses injected Shiki runtime to highlight rendered markdown code blocks; switches to text_base64.
astrbot/core/utils/t2i/template/astrbot_powershell.html Same as base template, tuned for dark theme and PowerShell styling.
astrbot/core/utils/t2i/network_strategy.py Injects Shiki runtime into template data and provides text_base64 when using the default render path.
Comments suppressed due to low confidence (2)

astrbot/core/utils/t2i/network_strategy.py:98

  • render_custom_template() now always injects shiki_runtime into tmpldata, which substantially increases the payload sent to /generate (the runtime is ~MBs). This can noticeably increase latency and may exceed request-size limits on some deployments/proxies. If possible, consider hosting the runtime once (e.g., served by the render endpoint or a static URL) and referencing it via <script src> in the template, or otherwise enabling endpoint-side caching/deduplication.
        tmpl_data = {"shiki_runtime": get_shiki_runtime()} | tmpl_data
        post_data = {
            "tmpl": tmpl_str,
            "json": return_url,
            "tmpldata": tmpl_data,
            "options": default_options,
        }

astrbot/core/utils/t2i/network_strategy.py:98

  • NetworkRenderStrategy.render() provides text_base64, but render_custom_template() does not. Since the updated built-in templates (base.html, astrbot_powershell.html) now consume text_base64 (and ignore text), callers using HtmlRenderer.render_custom_template() with those templates and only providing text will render blank content. Consider generating text_base64 inside render_custom_template() when text is present and text_base64 is missing to keep the API usable for custom callers.
    async def render_custom_template(
        self,
        tmpl_str: str,
        tmpl_data: dict,
        return_url: bool = True,
        options: dict | None = None,
    ) -> str:
        """使用自定义文转图模板"""
        default_options = {"full_page": True, "type": "jpeg", "quality": 40}
        if options:
            default_options |= options

        tmpl_data = {"shiki_runtime": get_shiki_runtime()} | tmpl_data
        post_data = {
            "tmpl": tmpl_str,
            "json": return_url,
            "tmpldata": tmpl_data,
            "options": default_options,
        }

Comment on lines +24 to +39
const languageSpecs = [
["bash", "bash"],
["css", "css"],
["html", "html"],
["javascript", "javascript"],
["json", "json"],
["jsx", "jsx"],
["markdown", "markdown"],
["powershell", "powershell"],
["python", "python"],
["sql", "sql"],
["tsx", "tsx"],
["typescript", "typescript"],
["xml", "xml"],
["yaml", "yaml"],
];
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeLanguage() can return "text" for empty/unknown languages, but "text" is not included in languageSpecs / supportedLanguages. If the Shiki core runtime doesn't have a built-in "text" grammar, codeToHtml() will throw both in the try path and in the catch fallback, breaking rendering for unlabeled code fences (common). Add the "text" language to the bundled languageSpecs (and thus supportedLanguages), similar to how the dashboard runtime initializes Shiki with langs: ["text"] (see dashboard/src/utils/shiki.js).

Copilot uses AI. Check for mistakes.
runtime_path = (
Path(__file__).resolve().parent / "template" / "shiki_runtime.iife.js"
)
runtime = runtime_path.read_text(encoding="utf-8")
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_shiki_runtime() reads shiki_runtime.iife.js unconditionally; if that file is missing/corrupted in a given installation/package, all network T2I renders will fail before even contacting endpoints. Consider catching OSError/FileNotFoundError, logging a warning, and returning an empty string (or a small stub that disables highlighting) so rendering can still proceed without code highlighting.

Suggested change
runtime = runtime_path.read_text(encoding="utf-8")
try:
runtime = runtime_path.read_text(encoding="utf-8")
except OSError as e:
logger.warning(
f"Failed to load Shiki runtime from {runtime_path}: {e}. "
"Continuing without code highlighting runtime.",
)
return ""

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Shiki-based syntax highlighting for the text-to-image (T2I) rendering strategy. Key changes include a new build script for the Shiki runtime, backend updates to serve this runtime and base64-encoded content, and a refactor of the HTML templates to utilize the new highlighting system. Review feedback suggests adding error handling for missing runtime files and optimizing the template data by removing redundant fields and unnecessary escaping logic.

Comment on lines +23 to +28
def get_shiki_runtime() -> str:
runtime_path = (
Path(__file__).resolve().parent / "template" / "shiki_runtime.iife.js"
)
runtime = runtime_path.read_text(encoding="utf-8")
return runtime.replace("</script", "<\\/script")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The get_shiki_runtime function will raise a FileNotFoundError if the shiki_runtime.iife.js file is missing (e.g., if the build script wasn't run or the file wasn't included in the distribution). Since this file is a build artifact from the dashboard directory, it's safer to handle the missing file gracefully and log a clear error message.

@lru_cache(maxsize=1)
def get_shiki_runtime() -> str:
    runtime_path = (
        Path(__file__).resolve().parent / "template" / "shiki_runtime.iife.js"
    )
    if not runtime_path.exists():
        logger.error(f"Shiki runtime not found at {runtime_path}. Please run the build script in the dashboard directory.")
        return ""
    runtime = runtime_path.read_text(encoding="utf-8")
    return runtime.replace("</script", "<\\/script")

Comment on lines +145 to +149
text_base64 = base64.b64encode(text.encode("utf-8")).decode("ascii")
text = text.replace("`", "\\`")
return await self.render_custom_template(
tmpl_str,
{"text": text, "version": f"v{VERSION}"},
{"text": text, "text_base64": text_base64, "version": f"v{VERSION}"},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The text variable is being passed to the template alongside text_base64. However, the updated HTML templates (base.html and astrbot_powershell.html) now use text_base64 for rendering and no longer reference {{ text }}. Passing both redundant data increases the payload size unnecessarily. Additionally, the backtick escaping on line 146 is no longer needed when using base64 encoding.

        text_base64 = base64.b64encode(text.encode("utf-8")).decode("ascii")
        return await self.render_custom_template(
            tmpl_str,
            {"text_base64": text_base64, "version": f"v{VERSION}"},
            return_url,
        )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants