any2human / frontend /src /api.ts
idnameraj's picture
Upload 3150 files
c212805 verified
Raw
History Blame Contribute Delete
4.59 kB
export type Tone = "Neutral" | "Casual" | "Formal" | "Academic";
export type StrengthLabel = "Light" | "Normal" | "Heavy";
export const TONES: Tone[] = ["Neutral", "Casual", "Formal", "Academic"];
export const STRENGTHS: StrengthLabel[] = ["Light", "Normal", "Heavy"];
export const STRENGTH_MAP: Record<StrengthLabel, number> = {
Light: 0,
Normal: 1,
Heavy: 2,
};
export type RewriteMeta = {
input_words: number;
output_words: number;
seconds: number;
lexical_refined: number;
ml_polish_requested: boolean;
tone: string;
strength: number;
};
export type AccountInfo = {
email: string | null;
display_name: string | null;
role: string;
plan: {
id: string;
name: string;
daily_rewrites: number;
max_words_per_request: number;
daily_word_cap: number;
price_inr_monthly: number;
};
usage: {
date: string;
rewrite_count: number;
word_count: number;
remaining_rewrites: number;
remaining_words: number;
};
};
export type RewriteResponse = {
rewrite: string;
meta: RewriteMeta;
account?: AccountInfo | null;
};
export type ApiError = Error & { status?: number; code?: string };
function detailMessage(detail: unknown, fallback: string): string {
if (typeof detail === "string") return detail;
if (Array.isArray(detail)) {
return detail
.map((d) => (typeof d === "object" && d && "msg" in d ? String(d.msg) : String(d)))
.join(" ");
}
return fallback;
}
export async function rewriteText(
payload: {
text: string;
tone: Tone;
strength: number;
preserve_length: boolean;
ml_polish?: boolean;
},
accessToken?: string | null,
): Promise<RewriteResponse> {
const headers: Record<string, string> = { "Content-Type": "application/json" };
if (accessToken) headers.Authorization = `Bearer ${accessToken}`;
const res = await fetch("/v1/rewrite", {
method: "POST",
headers,
body: JSON.stringify(payload),
});
if (!res.ok) {
let detail: unknown = "Rewrite failed.";
try {
const data = await res.json();
detail = data.detail ?? detail;
} catch {
/* ignore */
}
const err = new Error(detailMessage(detail, "Rewrite failed.")) as ApiError;
err.status = res.status;
if (res.status === 401 || res.status === 429 || res.status === 413) {
err.code = "limit";
}
throw err;
}
return res.json();
}
export type GrammarIssue = {
id: string;
start: number;
end: number;
message: string;
suggestion: string | null;
category: string;
};
export type GrammarResponse = {
issues: GrammarIssue[];
input_words: number;
engine: string;
language?: string;
note?: string;
};
export async function checkGrammar(
text: string,
options?: { language?: string; accessToken?: string | null },
): Promise<GrammarResponse> {
const headers: Record<string, string> = { "Content-Type": "application/json" };
const accessToken = options?.accessToken;
if (accessToken) headers.Authorization = `Bearer ${accessToken}`;
let res: Response;
try {
res = await fetch("/v1/grammar", {
method: "POST",
headers,
body: JSON.stringify({
text,
language: options?.language || "en-US",
}),
});
} catch {
const err = new Error(
"Could not reach the grammar API. Is the ZuZu server running?",
) as ApiError;
err.code = "network";
throw err;
}
if (!res.ok) {
let detail: unknown = `Grammar check failed (HTTP ${res.status}).`;
try {
const data = await res.json();
detail = data.detail ?? detail;
} catch {
/* non-JSON body — often means the Space/app build is missing /v1/grammar */
if (res.status === 404) {
detail =
"Grammar API not found (404). Restart/redeploy the app so /v1/grammar is available.";
}
}
const err = new Error(detailMessage(detail, `Grammar check failed (HTTP ${res.status}).`)) as ApiError;
err.status = res.status;
throw err;
}
return res.json();
}
export async function fetchMe(accessToken?: string | null): Promise<{
auth_enabled: boolean;
account: AccountInfo | null;
}> {
const headers: Record<string, string> = {};
if (accessToken) headers.Authorization = `Bearer ${accessToken}`;
const res = await fetch("/v1/me", { headers });
if (!res.ok) {
throw new Error("Could not load account.");
}
return res.json();
}