mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 11:09:34 +00:00
feat: integrate Pi backend and Pi Web
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
import type { Options as ReactMarkdownOptions } from "react-markdown";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
|
||||
const markdownSanitizeSchema = {
|
||||
...defaultSchema,
|
||||
attributes: {
|
||||
...defaultSchema.attributes,
|
||||
code: [["className", /^language-./, "math-inline", "math-display"]],
|
||||
},
|
||||
strip: [...(defaultSchema.strip || []), "iframe", "object", "style", "form"],
|
||||
};
|
||||
|
||||
export function normalizeDisplayMath(markdown: string): string {
|
||||
const lineBreak = markdown.includes("\r\n") ? "\r\n" : "\n";
|
||||
const lines = markdown.split(/\r?\n/);
|
||||
const normalized: string[] = [];
|
||||
let fence: { marker: string; size: number } | null = null;
|
||||
let inlineCodeMarkerSize = 0;
|
||||
let rawCodeTag: string | null = null;
|
||||
|
||||
for (let index = 0; index < lines.length; index++) {
|
||||
const line = lines[index];
|
||||
|
||||
if (rawCodeTag) {
|
||||
normalized.push(line);
|
||||
if (new RegExp(`</${rawCodeTag}\\s*>`, "i").test(line)) rawCodeTag = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
||||
if (fenceMatch) {
|
||||
const marker = fenceMatch[1][0];
|
||||
const size = fenceMatch[1].length;
|
||||
if (!fence) fence = { marker, size };
|
||||
else if (marker === fence.marker && size >= fence.size) fence = null;
|
||||
inlineCodeMarkerSize = 0;
|
||||
normalized.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fence) {
|
||||
normalized.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
const rawCodeOpen = line.match(/<(code|pre|script|style)\b/i);
|
||||
if (rawCodeOpen) {
|
||||
const tag = rawCodeOpen[1].toLowerCase();
|
||||
const remainder = line.slice((rawCodeOpen.index ?? 0) + rawCodeOpen[0].length);
|
||||
if (!new RegExp(`</${tag}\\s*>`, "i").test(remainder)) rawCodeTag = tag;
|
||||
inlineCodeMarkerSize = 0;
|
||||
normalized.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/^(?: {4}|\t)/.test(line) || line.trim() === "") {
|
||||
inlineCodeMarkerSize = 0;
|
||||
normalized.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inlineCodeMarkerSize || line.includes("`")) {
|
||||
inlineCodeMarkerSize = updateInlineCodeMarker(line, inlineCodeMarkerSize);
|
||||
normalized.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bracketDisplayOneLine = line.match(/^([ ]{0,3})\\\[[ \t]*(.+?)[ \t]*\\\][ \t]*$/);
|
||||
if (bracketDisplayOneLine) {
|
||||
const math = bracketDisplayOneLine[2].trim();
|
||||
if (math) {
|
||||
normalized.push(`${bracketDisplayOneLine[1]}$$`, math, `${bracketDisplayOneLine[1]}$$`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bracketDisplayStart = line.match(/^([ ]{0,3})\\\[[ \t]*$/);
|
||||
if (bracketDisplayStart) {
|
||||
const closingIndex = findBracketDisplayClose(lines, index + 1);
|
||||
if (closingIndex !== -1) {
|
||||
normalized.push(
|
||||
`${bracketDisplayStart[1]}$$`,
|
||||
...lines.slice(index + 1, closingIndex),
|
||||
`${bracketDisplayStart[1]}$$`,
|
||||
);
|
||||
index = closingIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const displayMathMatch = line.match(/^([ \t]{0,3})\$\$(.+)\$\$[ \t]*$/);
|
||||
if (displayMathMatch) {
|
||||
const math = displayMathMatch[2].trim();
|
||||
if (math) {
|
||||
normalized.push(`${displayMathMatch[1]}$$`, math, `${displayMathMatch[1]}$$`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
normalized.push(normalizeInlineLatexMath(line));
|
||||
}
|
||||
|
||||
return normalized.join(lineBreak);
|
||||
}
|
||||
|
||||
function findBracketDisplayClose(lines: string[], startIndex: number): number {
|
||||
for (let index = startIndex; index < lines.length; index++) {
|
||||
const line = lines[index];
|
||||
if (/^ {0,3}\\\][ \t]*$/.test(line)) return index;
|
||||
|
||||
// Do not pair delimiters across another Markdown block boundary.
|
||||
if (
|
||||
/^ {0,3}(`{3,}|~{3,})/.test(line) ||
|
||||
/^ {0,3}\\\[[ \t]*$/.test(line) ||
|
||||
/<(code|pre|script|style)\b/i.test(line)
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function updateInlineCodeMarker(line: string, initialMarkerSize: number): number {
|
||||
let markerSize = initialMarkerSize;
|
||||
for (let cursor = 0; cursor < line.length;) {
|
||||
if (line[cursor] !== "`") {
|
||||
cursor++;
|
||||
continue;
|
||||
}
|
||||
|
||||
let end = cursor + 1;
|
||||
while (line[end] === "`") end++;
|
||||
const runSize = end - cursor;
|
||||
if (markerSize === 0) markerSize = runSize;
|
||||
else if (runSize === markerSize) markerSize = 0;
|
||||
cursor = end;
|
||||
}
|
||||
return markerSize;
|
||||
}
|
||||
|
||||
function normalizeInlineLatexMath(line: string): string {
|
||||
if (
|
||||
/^\s{0,3}\[[^\]]+\]:/.test(line) ||
|
||||
/]\s*\(/.test(line) ||
|
||||
/<(?:!--|\/?[A-Za-z][^>]*>)/.test(line) ||
|
||||
/\b(?:https?|file|mailto):/i.test(line) ||
|
||||
/\b[A-Za-z]:\\/.test(line)
|
||||
) {
|
||||
return line;
|
||||
}
|
||||
|
||||
return line.replace(
|
||||
/(?<!\\)\\\(([^`\r\n$]+?)(?<!\\)\\\)/g,
|
||||
(match, math: string) => (math.trim() ? `$${math}$` : match),
|
||||
);
|
||||
}
|
||||
|
||||
export const markdownRemarkPlugins: ReactMarkdownOptions["remarkPlugins"] = [remarkGfm, remarkMath];
|
||||
export const markdownPreviewRemarkPlugins: ReactMarkdownOptions["remarkPlugins"] = [remarkGfm, remarkMath];
|
||||
|
||||
export const markdownRehypePlugins: ReactMarkdownOptions["rehypePlugins"] = [
|
||||
rehypeRaw,
|
||||
[rehypeSanitize, markdownSanitizeSchema],
|
||||
[rehypeKatex, { throwOnError: false, strict: false }],
|
||||
];
|
||||
|
||||
export const markdownPreviewRehypePlugins: ReactMarkdownOptions["rehypePlugins"] = [
|
||||
rehypeRaw,
|
||||
[rehypeSanitize, markdownSanitizeSchema],
|
||||
[rehypeKatex, { throwOnError: false, strict: false }],
|
||||
];
|
||||
Reference in New Issue
Block a user