Files
learnharness/app/api/chats/[id]/markdown/route.ts
T
sorokin.oleg.edu a50ca4b867
CI / Typecheck, tests, lint (push) Canceled after 0s
CI / Standalone (mac-arm64) (push) Canceled after 0s
CI / Standalone (linux-x64) (push) Canceled after 0s
CI / Standalone (windows-x64) (push) Canceled after 0s
feat: add Russian localization and independent STT languages
2026-10-25 17:18:44 +03:00

38 lines
1.7 KiB
TypeScript

/**
* THE SESSION MARKDOWN EXPORT (owner, release polish 2026-10-06): the
* user-facing export the session-markdown engine was built for — the
* same document the extractor reads, minted anchorless (anchors are
* extraction provenance; a learner's export carries no message ids).
*
* GET /api/chats/:id/markdown → the whole session as one markdown file
* (Content-Disposition attachment; filename from the slugified title).
* 404 unknown chat. Both session kinds export — practice sessions ride
* the same engine (problem/conclude results render as tool blocks,
* markers are invisible by the engine's law).
*/
import { sessionMarkdown } from "@/src/core";
import { getChat, applicationLanguage } from "@/src/server";
/** Filename-safe title (own module scope on purpose: tiny + pure). */
function slugify(title: string): string {
const slug = title
.toLowerCase()
.normalize("NFKD")
.replace(/[^\p{L}\p{N}]+/gu, "-")
.replace(/^-+|-+$/g, "");
return slug.length > 0 ? slug : "session";
}
export async function GET(_req: Request, ctx: { params: Promise<{ id: string }> }): Promise<Response> {
const { id } = await ctx.params;
const record = getChat(id);
if (!record) return Response.json({ error: "Unknown chat" }, { status: 404 });
const markdown = sessionMarkdown(record.messages, { title: record.title, anchors: false, language: applicationLanguage(_req.headers.get("accept-language")) });
return new Response(markdown, {
headers: {
"content-type": "text/markdown; charset=utf-8",
"content-disposition": `attachment; filename="${/^[a-z0-9-]+$/.test(slugify(record.title)) ? slugify(record.title) : "session"}.md"; filename*=UTF-8''${encodeURIComponent(slugify(record.title))}.md`,
},
});
}