// Supabase Edge Function: writing-check // Uses GLM API (OpenAI-compatible) to analyze English writing submissions. // Deploy: supabase functions deploy writing-check // Secrets: supabase secrets set GLM_API_KEY= import OpenAI from "npm:openai@^4" const glm = new OpenAI({ apiKey: Deno.env.get("GLM_API_KEY") ?? "", baseURL: "https://open.bigmodel.cn/api/paas/v4/", }) const CORS_HEADERS = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", "Content-Type": "application/json", } // Instructs the model to return a strict JSON structure with Vietnamese feedback. const SYSTEM_PROMPT = `You are an expert English writing teacher specialising in TOEIC and IELTS assessment. Analyse the student's writing and respond ONLY with valid JSON — no markdown, no extra text: { "score": "", "grammar": ["", ...], "vocabulary": ["", ...], "structure": "<2–3 sentence structure assessment in Vietnamese>", "improved_version": "", "summary": "<2–3 sentence overall assessment in Vietnamese>" }` Deno.serve(async (req: Request) => { // Handle CORS pre-flight if (req.method === "OPTIONS") { return new Response("ok", { headers: CORS_HEADERS }) } try { const { content } = await req.json() as { content: string } if (!content || content.trim().length < 10) { return new Response( JSON.stringify({ error: "Bài viết quá ngắn. Vui lòng nhập ít nhất 10 ký tự." }), { status: 400, headers: CORS_HEADERS }, ) } const completion = await glm.chat.completions.create({ // GLM-4-32B-0414-128K: cheapest paid model at $0.1/$0.1 per 1M tokens. // Override via: supabase secrets set GLM_MODEL= model: Deno.env.get("GLM_MODEL") ?? "GLM-4-32B-0414-128K", messages: [ { role: "system", content: SYSTEM_PROMPT }, { role: "user", content: `Analyse this writing:\n\n${content.slice(0, 2000)}` }, ], temperature: 0.3, max_tokens: 1500, }) const raw = completion.choices[0]?.message?.content ?? "{}" // Strip markdown code fences if the model adds them despite instructions const cleaned = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim() const feedback = JSON.parse(cleaned) return new Response(JSON.stringify(feedback), { headers: CORS_HEADERS }) } catch (err) { console.error("writing-check error:", err) return new Response( JSON.stringify({ error: "Đã có lỗi khi chấm bài. Vui lòng thử lại." }), { status: 500, headers: CORS_HEADERS }, ) } })