feat(ai): export assistant analysis result as markdown

This commit is contained in:
Abeautifulsnow authored and GitHub committed 2026-07-31 21:17:57 +08:00
1 parent ce3bb09796
commit f64d363abe
15 files changed
+542 -62

No files matched your search

@@ -0,0 +1,28 @@
import { compactLocalTimestamp, sanitizeExportBaseName } from "./saveTextFile";
export interface BuildAiAnalysisExportInput {
connectionName?: string;
content: string;
analysisLabel: string;
dateLabel: string;
}
export interface BuildAiAnalysisExportOutput {
markdown: string;
defaultFileName: string;
}
export function buildAiAnalysisExport(input: BuildAiAnalysisExportInput): BuildAiAnalysisExportOutput | null {
if (!input.content.trim()) return null;
const rawName = input.connectionName || "";
const sanitizedName = sanitizeExportBaseName(rawName) || "ai";
const displayName = rawName || "AI";
const headerLines = [`# ${displayName} · ${input.analysisLabel}`, `${input.dateLabel}`, ""];
const markdown = headerLines.join("\n") + input.content;
const defaultFileName = `${sanitizedName}_${compactLocalTimestamp()}.md`;
return { markdown, defaultFileName };
}
@@ -0,0 +1,51 @@
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
export async function saveTextFile(content: string, defaultFileName: string, filterName: string, filterExt: string) {
if (isTauriRuntime()) {
const { save } = await import("@tauri-apps/plugin-dialog");
const { writeTextFile } = await import("@tauri-apps/plugin-fs");
const path = await save({
defaultPath: defaultFileName,
filters: [{ name: filterName, extensions: [filterExt] }],
});
if (path) await writeTextFile(path, content);
return;
}
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = defaultFileName;
a.click();
URL.revokeObjectURL(url);
}
export function sanitizeExportBaseName(value: string): string {
return replaceControlCharacters(
value
.trim()
.replace(/\.[sS][qQ][lL]$/, "")
.replace(/[<>:"/\\|?*]/g, "_"),
"_",
)
.replace(/\s+/g, " ")
.replace(/[._\s-]+$/g, "")
.slice(0, 120);
}
function replaceControlCharacters(value: string, replacement: string): string {
return Array.from(value)
.map((char) => (char.charCodeAt(0) < 32 ? replacement : char))
.join("");
}
export function compactLocalTimestamp(date = new Date()): string {
const yy = String(date.getFullYear() % 100).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hour = String(date.getHours()).padStart(2, "0");
const minute = String(date.getMinutes()).padStart(2, "0");
const second = String(date.getSeconds()).padStart(2, "0");
return `${yy}${month}${day}${hour}${minute}${second}`;
}