Skip to content

Commit 625eab2

Browse files
authored
feat: enable shiki highlighting for t2i templates and add a template (AstrBotDevs#7501)
* fix: enable shiki highlighting for t2i templates * fix: t2i templates cr * feat: add new t2i template astrbot_vitepress.html
1 parent 207eb34 commit 625eab2

8 files changed

Lines changed: 1223 additions & 180 deletions

File tree

astrbot/core/utils/t2i/network_strategy.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import asyncio
2+
import base64
23
import logging
34
import random
5+
from functools import lru_cache
6+
from pathlib import Path
47

58
import aiohttp
69

@@ -16,6 +19,31 @@
1619
logger = logging.getLogger("astrbot")
1720

1821

22+
@lru_cache(maxsize=1)
23+
def get_shiki_runtime() -> str:
24+
runtime_path = (
25+
Path(__file__).resolve().parent / "template" / "shiki_runtime.iife.js"
26+
)
27+
if not runtime_path.exists():
28+
logger.error(
29+
"T2I Shiki runtime not found at %s. Run `cd dashboard && pnpm run build:t2i-shiki-runtime` to regenerate it. Continuing without code highlighting.",
30+
runtime_path,
31+
)
32+
return ""
33+
34+
try:
35+
runtime = runtime_path.read_text(encoding="utf-8")
36+
except (OSError, UnicodeDecodeError) as err:
37+
logger.warning(
38+
"Failed to load T2I Shiki runtime from %s: %s. Continuing without code highlighting.",
39+
runtime_path,
40+
err,
41+
)
42+
return ""
43+
44+
return runtime.replace("</script", "<\\/script")
45+
46+
1947
class NetworkRenderStrategy(RenderStrategy):
2048
def __init__(self, base_url: str | None = None) -> None:
2149
super().__init__()
@@ -77,6 +105,7 @@ async def render_custom_template(
77105
if options:
78106
default_options |= options
79107

108+
tmpl_data = {"shiki_runtime": get_shiki_runtime()} | tmpl_data
80109
post_data = {
81110
"tmpl": tmpl_str,
82111
"json": return_url,
@@ -129,9 +158,9 @@ async def render(
129158
if not template_name:
130159
template_name = "base"
131160
tmpl_str = await self.get_template(name=template_name)
132-
text = text.replace("`", "\\`")
161+
text_base64 = base64.b64encode(text.encode("utf-8")).decode("ascii")
133162
return await self.render_custom_template(
134163
tmpl_str,
135-
{"text": text, "version": f"v{VERSION}"},
164+
{"text_base64": text_base64, "version": f"v{VERSION}"},
136165
return_url,
137166
)

astrbot/core/utils/t2i/template/astrbot_powershell.html

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@
22
<html>
33
<head>
44
<meta charset="utf-8"/>
5-
<title>Astrbot PowerShell {{ version }} </title>
5+
<title>Astrbot PowerShell {{ version }}</title>
66
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
7-
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11.9.0/lib/common.min.js"></script>
8-
<script>hljs.highlightAll();</script>
9-
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
10-
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"
11-
onload="renderMathInElement(document.getElementById('content'),{delimiters: [{left: '$$', right: '$$', display: true},{left: '$', right: '$', display: false}]});"></script>
127
<style>
138
:root {
149
--bg-color: #010409;
1510
--text-color: #e6edf3;
1611
--title-bar-color: #161b22;
1712
--title-text-color: #e6edf3;
18-
--font-family: 'Consolas', 'Microsoft YaHei Mono', 'Dengxian Mono', 'Courier New', monospace;
13+
--font-family: "Consolas", "Microsoft YaHei Mono", "Dengxian Mono", "Courier New", monospace;
1914
--glow-color: rgba(200, 220, 255, 0.7);
2015
}
2116

@@ -36,7 +31,6 @@
3631
padding: 0;
3732
line-height: 1.6;
3833
font-size: 18px;
39-
/* The CRT glow effect from the image */
4034
text-shadow: 0 0 15px var(--glow-color), 0 0 7px rgba(255, 255, 255, 1);
4135
position: relative;
4236
overflow: hidden;
@@ -63,9 +57,9 @@
6357
color: var(--title-text-color);
6458
font-size: 16px;
6559
border-bottom: 1px solid #30363d;
66-
text-shadow: none; /* No glow for title bar */
60+
text-shadow: none;
6761
}
68-
62+
6963
.header .title {
7064
font-weight: bold;
7165
font-size: 28px;
@@ -78,13 +72,10 @@
7872

7973
main {
8074
padding: 1rem 1.5rem;
75+
position: relative;
76+
z-index: 1;
8177
}
8278

83-
#content {
84-
/* min-width and max-width removed as per request */
85-
}
86-
87-
/* --- Markdown Styles adjusted for terminal look --- */
8879
h1, h2, h3, h4, h5, h6 {
8980
line-height: 1.4;
9081
margin-top: 20px;
@@ -144,7 +135,16 @@
144135
font-size: 100%;
145136
background-color: transparent;
146137
border-radius: 0;
147-
text-shadow: none; /* Disable glow inside code blocks for clarity */
138+
text-shadow: none;
139+
}
140+
141+
pre.shiki {
142+
padding: 1rem;
143+
}
144+
145+
pre.shiki > code,
146+
pre.shiki span {
147+
text-shadow: none;
148148
}
149149

150150
a {
@@ -165,20 +165,54 @@
165165
</style>
166166
</head>
167167
<body>
168-
169168
<div class="header">
170-
<span class="title">> Astrbot PowerShell</span>
169+
<span class="title">&gt; Astrbot PowerShell</span>
171170
<span class="version">{{ version }}</span>
172171
</div>
173172

174173
<main>
175174
<div id="content"></div>
176175
</main>
177176

177+
<script>{{ shiki_runtime | safe }}</script>
178178
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
179+
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
180+
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
179181
<script>
180-
document.getElementById('content').innerHTML = marked.parse(`{{ text | safe }}`);
181-
</script>
182+
(function () {
183+
const contentElement = document.getElementById("content");
184+
const source = decodeBase64Utf8("{{ text_base64 }}");
185+
186+
contentElement.innerHTML = marked.parse(source);
187+
188+
if (window.AstrBotT2IShiki) {
189+
window.AstrBotT2IShiki.highlightAllCodeBlocks(contentElement, "github-dark");
190+
}
191+
192+
if (window.renderMathInElement) {
193+
window.renderMathInElement(contentElement, {
194+
delimiters: [
195+
{ left: "$$", right: "$$", display: true },
196+
{ left: "$", right: "$", display: false }
197+
]
198+
});
199+
}
200+
201+
function decodeBase64Utf8(base64Text) {
202+
const binary = window.atob(base64Text || "");
203+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
204+
205+
if (window.TextDecoder) {
206+
return new TextDecoder().decode(bytes);
207+
}
182208

209+
let fallback = "";
210+
bytes.forEach((byte) => {
211+
fallback += String.fromCharCode(byte);
212+
});
213+
return decodeURIComponent(escape(fallback));
214+
}
215+
})();
216+
</script>
183217
</body>
184-
</html>
218+
</html>

0 commit comments

Comments
 (0)