This commit is contained in:
2026-04-13 15:17:59 +07:00
parent 77a0e38fa7
commit 01c5ccbd93
3 changed files with 143 additions and 34 deletions

View File

@@ -1,7 +1,6 @@
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { canUseWritingCheck, recordWritingCheckUsage } from "@/utils/rate-limiter"
import { useAuthStore } from "@/store/auth-store"
import { supabase } from "@/lib/supabase"
import { saveWritingSubmission, countTodayWritingSubmissions } from "@/lib/progress-service"
import type { WritingFeedback } from "@/types"
@@ -9,24 +8,20 @@ const AUTH_DAILY_LIMIT = 10
const GUEST_DAILY_LIMIT = 3
const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL as string
const SUPABASE_ANON_KEY = (
import.meta.env.VITE_SUPABASE_ANON_KEY || import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
) as string
const SUPABASE_ANON_KEY = (import.meta.env.VITE_SUPABASE_ANON_KEY || import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY) as string
// Calls the edge function and streams SSE chunks, invoking onChunk for each text piece.
// Accumulates the full response, then extracts and parses the JSON object.
// Calls the writing-check-dbiz Supabase edge function.
// SSE format emitted by the function: data: {"text":"..."} | data: [DONE]
async function callEdgeFunction(
content: string,
onChunk?: (text: string) => void,
): Promise<WritingFeedback> {
const { data: { session } } = await supabase.auth.getSession()
const res = await fetch(`${SUPABASE_URL}/functions/v1/writing-check-dbiz`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
apikey: SUPABASE_ANON_KEY,
Authorization: `Bearer ${session?.access_token ?? SUPABASE_ANON_KEY}`,
},
body: JSON.stringify({ content }),
})
@@ -54,22 +49,23 @@ async function callEdgeFunction(
const payload = line.slice(6).trim()
if (payload === "[DONE]") continue
let event: { text?: string; error?: string }
let chunk: { text?: string; error?: string }
try {
event = JSON.parse(payload)
chunk = JSON.parse(payload)
} catch {
continue // skip malformed SSE lines
continue
}
if (event.error) throw new Error(event.error)
if (event.text) {
accumulated += event.text
onChunk?.(event.text)
if (chunk.error) throw new Error(chunk.error)
const text = chunk.text ?? ""
if (text) {
accumulated += text
onChunk?.(text)
}
}
}
// Extract the outermost JSON object from the accumulated stream
const start = accumulated.indexOf("{")
const end = accumulated.lastIndexOf("}")
if (start === -1 || end === -1) {
@@ -78,7 +74,6 @@ async function callEdgeFunction(
const raw = JSON.parse(accumulated.slice(start, end + 1))
// Normalize: model sometimes returns array fields as a plain string
const toArray = (v: unknown): string[] => {
if (Array.isArray(v)) return v
if (typeof v === "string" && v.length > 0) return [v]