Files
mnote/wolai-frontend/convex/_utils/text.ts
T
2026-01-18 05:13:53 +08:00

102 lines
3.0 KiB
TypeScript

function pushText(out: string[], value: unknown) {
const s = typeof value === "string" ? value : null;
if (!s) return;
const trimmed = s.replace(/\s+/g, " ").trim();
if (!trimmed) return;
out.push(trimmed);
}
export function extractTextFromDocumentContent(content: unknown, maxChars = 60000): string {
const out: string[] = [];
const readPropText = (value: unknown) => {
if (!value || typeof value !== "object") return null;
const t = (value as Record<string, unknown>).text;
return typeof t === "string" ? t : null;
};
const walk = (node: unknown) => {
if (out.join("\n").length >= maxChars) return;
if (node == null) return;
if (typeof node === "string") {
pushText(out, node);
return;
}
if (typeof node === "number" || typeof node === "boolean") return;
if (Array.isArray(node)) {
for (const item of node) {
walk(item);
if (out.join("\n").length >= maxChars) return;
}
return;
}
if (typeof node === "object") {
const obj = node as Record<string, unknown>;
// 兼容常见 BlockNote 结构:
// - block.props.text
// - block.content: [{ text: "..." }, ...]
// - block.children: [...]
pushText(out, obj.text);
pushText(out, readPropText(obj.props));
const maybeContent = obj.content;
if (Array.isArray(maybeContent)) {
for (const seg of maybeContent) {
if (typeof seg === "string") pushText(out, seg);
else if (seg && typeof seg === "object") pushText(out, readPropText(seg));
if (out.join("\n").length >= maxChars) return;
}
}
const children = obj.children;
if (Array.isArray(children)) {
for (const c of children) {
walk(c);
if (out.join("\n").length >= maxChars) return;
}
}
// 兜底:遍历其它字段(避免遗漏 title/caption 等)
for (const [k, v] of Object.entries(obj)) {
if (k === "children" || k === "content" || k === "props" || k === "text") continue;
if (typeof v === "string") pushText(out, v);
else if (Array.isArray(v) || (v && typeof v === "object")) walk(v);
if (out.join("\n").length >= maxChars) return;
}
}
};
walk(content);
const joined = out.join("\n").trim();
return joined.length > maxChars ? `${joined.slice(0, maxChars)}…` : joined;
}
type MindmapNode = { data?: { text?: unknown }; children?: unknown[] };
export function extractTextFromMindmapData(data: unknown, maxChars = 60000): string {
const out: string[] = [];
const walk = (node: unknown) => {
if (out.join("\n").length >= maxChars) return;
if (!node || typeof node !== "object") return;
const n = node as MindmapNode;
pushText(out, n.data?.text);
if (Array.isArray(n.children)) {
for (const c of n.children) {
walk(c);
if (out.join("\n").length >= maxChars) return;
}
}
};
walk(data);
const joined = out.join("\n").trim();
return joined.length > maxChars ? `${joined.slice(0, maxChars)}…` : joined;
}