Spaces:
Running
Running
Download frontend/src/lib/api.ts from EvalBot/Audio-EvalBot: direct link, hf CLI and curl.
- Browser
- Download file 10.4 kB
-
https://huggingface.co/spaces/EvalBot/Audio-EvalBot/resolve/main/frontend/src/lib/api.ts
- Command line
-
hf download hf://spaces/EvalBot/Audio-EvalBot/frontend/src/lib/api.ts
-
curl -L -o api.ts https://huggingface.co/spaces/EvalBot/Audio-EvalBot/resolve/main/frontend/src/lib/api.ts
10.4 kB
| import { getAccessToken } from "./auth"; | |
| export class ApiError extends Error { | |
| status: number; | |
| constructor(status: number, message: string) { | |
| super(message); | |
| this.status = status; | |
| } | |
| } | |
| async function request<T>(method: string, path: string, body?: unknown, form?: FormData): Promise<T> { | |
| const token = await getAccessToken(); | |
| const headers: Record<string, string> = {}; | |
| if (token) headers.Authorization = `Bearer ${token}`; | |
| if (body !== undefined && !form) headers["Content-Type"] = "application/json"; | |
| const res = await fetch(`/api${path}`, { | |
| method, | |
| headers, | |
| body: form ?? (body !== undefined ? JSON.stringify(body) : undefined), | |
| }); | |
| if (!res.ok) { | |
| let msg = res.statusText; | |
| try { | |
| const j = await res.json(); | |
| msg = typeof j.detail === "string" ? j.detail : JSON.stringify(j.detail ?? j); | |
| } catch { | |
| /* not JSON */ | |
| } | |
| throw new ApiError(res.status, msg); | |
| } | |
| const type = res.headers.get("content-type") || ""; | |
| return (type.includes("application/json") ? res.json() : res.blob()) as Promise<T>; | |
| } | |
| export const api = { | |
| get: <T>(p: string) => request<T>("GET", p), | |
| post: <T>(p: string, body?: unknown) => request<T>("POST", p, body ?? {}), | |
| put: <T>(p: string, body?: unknown) => request<T>("PUT", p, body ?? {}), | |
| patch: <T>(p: string, body?: unknown) => request<T>("PATCH", p, body ?? {}), | |
| del: <T>(p: string) => request<T>("DELETE", p), | |
| upload: <T>(p: string, form: FormData) => request<T>("POST", p, undefined, form), | |
| blob: (p: string) => request<Blob>("GET", p), | |
| }; | |
| /* ---------- shared types ---------- */ | |
| export type Profile = { | |
| id: string; | |
| email: string | null; | |
| full_name: string | null; | |
| role: "candidate" | "recruiter"; | |
| company_id: string | null; | |
| headline: string | null; | |
| target_track: string | null; | |
| locale: string; | |
| company?: Company | null; | |
| has_cv?: boolean; | |
| }; | |
| export type Company = { id: string; name: string; website?: string | null; about?: string | null; industry?: string | null; size?: string | null; location?: string | null }; | |
| export type Track = { id: string; en: string; ar: string; group: string }; | |
| export type Catalog = { tracks: Track[]; levels: string[]; types: string[] }; | |
| export type PlanQuestion = { text: string; kind?: string; skill?: string; rubric?: string; is_followup?: boolean }; | |
| export type Feedback = { | |
| score: number | null; | |
| relevance?: string | null; | |
| summary?: string; | |
| strengths?: string[]; | |
| improvements?: string[]; | |
| delivery_tip?: string; | |
| improved_answer?: string; | |
| followup_question?: string; | |
| skill?: string; | |
| error?: string; | |
| rubric?: Rubric; | |
| soft_skills?: string[]; | |
| }; | |
| export type Rubric = { clarity: number | null; example_quality: number | null; structure: number | null; outcome: number | null }; | |
| export type EmotionProbs = Record<"neutral" | "happy" | "surprised" | "sad" | "angry" | "fearful" | "disgusted", number>; | |
| export type IntegrityEvent = { type: string; t: number; dur?: number | null; answer?: number }; | |
| export type CameraInfo = { | |
| samples: number; answers: number; face_visible: number | null; eye_contact: number | null; smile: number | null; | |
| head_movement: number | null; emotions: EmotionProbs | null; dominant_emotion: keyof EmotionProbs | null; | |
| timeline: { answer: number; t: number; dominant: keyof EmotionProbs; probs: EmotionProbs }[]; | |
| }; | |
| export type Integrity = { score: number; level: "low" | "medium" | "high"; counts: Record<string, number>; events: IntegrityEvent[]; | |
| notes: string[]; camera: boolean }; | |
| export type CvProfile = { | |
| name: string; headline: string; years_experience: number; skills: string[]; soft_skills: string[]; | |
| experience: { title: string; company: string; period: string; summary: string }[]; | |
| education: { degree: string; institution: string; year: string }[]; | |
| projects: { name: string; summary: string; tech: string[] }[]; certifications: string[]; languages: string[]; | |
| }; | |
| export type SkillMatch = { matched: string[]; missing: string[]; percent: number }; | |
| export type Answer = { | |
| id: string; | |
| idx: number; | |
| question: string; | |
| kind: string | null; | |
| is_followup: boolean; | |
| duration_s: number | null; | |
| transcript: string | null; | |
| voice: Record<string, any> | null; | |
| presence: (Partial<CameraInfo> & { samples?: number; events?: IntegrityEvent[] }) | null; | |
| feedback: Feedback | null; | |
| score: number | null; | |
| has_audio: boolean; | |
| media?: "audio" | "video"; | |
| }; | |
| export type Trait = { trait: string; label: string; score_1_7: number; percentile: number; model_r: number; human_r: number }; | |
| export type Report = { | |
| overall: number | null; | |
| content_score: number | null; | |
| delivery_score: number | null; | |
| duration_s?: number; | |
| voice: Record<string, any>; | |
| camera?: CameraInfo | null; | |
| integrity?: Integrity | null; | |
| rubric?: Rubric; | |
| calibrated: { traits: Trait[]; reference: { interviews: number; raters_per_interview: number } } | null; | |
| summary: { | |
| headline?: string; | |
| executive_summary?: string[]; | |
| strengths?: { competency: string; explanation: string; evidence: string }[]; | |
| weaknesses?: { area: string; feedback: string }[]; | |
| role_fit?: string[]; | |
| recommendations?: { category: string; recommendation: string; how_to: string }[]; | |
| learning_plan?: { topic: string; why: string; how: string }[]; | |
| next_steps?: string[]; | |
| hiring_signal?: "strong_yes" | "yes" | "maybe" | "no"; | |
| soft_skills?: { skill: string; score: number; comment: string }[]; | |
| nonverbal?: string; | |
| }; | |
| }; | |
| export type Session = { | |
| id: string; | |
| user_id: string; | |
| job_id: string | null; | |
| mode: "mock" | "job" | "upload"; | |
| track: string | null; | |
| level: string | null; | |
| interview_type: string | null; | |
| language: "en" | "ar"; | |
| status: "in_progress" | "processing" | "completed" | "failed"; | |
| context: { plan: PlanQuestion[]; role?: string; answer_seconds?: number; job_title?: string }; | |
| overall_score: number | null; | |
| report: Report | null; | |
| error: string | null; | |
| created_at: string; | |
| completed_at: string | null; | |
| answers?: Answer[]; | |
| job?: { title: string; company: string } | null; | |
| candidate?: { full_name: string | null; email: string | null; headline: string | null; cv?: CvProfile | null; skill_match?: SkillMatch | null }; | |
| }; | |
| export type SessionRow = { | |
| id: string; | |
| mode: string; | |
| track: string | null; | |
| level: string | null; | |
| status: Session["status"]; | |
| overall_score: number | null; | |
| created_at: string; | |
| role: string | null; | |
| job_title: string | null; | |
| answered: number; | |
| planned: number; | |
| }; | |
| export type Job = { | |
| id: string; | |
| title: string; | |
| track: string; | |
| level: string; | |
| description: string | null; | |
| questions: PlanQuestion[]; | |
| answer_seconds: number; | |
| status: "draft" | "open" | "closed"; | |
| share_token: string; | |
| created_at: string; | |
| applicants?: number; | |
| completed?: number; | |
| location: string | null; | |
| work_mode: WorkMode; | |
| employment_type: EmploymentType; | |
| salary: string | null; | |
| skills: string[]; | |
| deadline: string | null; | |
| visibility: "public" | "link"; | |
| views?: number; | |
| require_camera: boolean; | |
| record_video: boolean; | |
| }; | |
| export type WorkMode = "onsite" | "remote" | "hybrid"; | |
| export type EmploymentType = "full_time" | "part_time" | "internship" | "contract"; | |
| /** A job as candidates see it (job board and apply page). */ | |
| export type PublicJob = { | |
| id: string; title: string; track: string; level: string; location: string | null; work_mode: WorkMode; | |
| employment_type: EmploymentType; salary: string | null; skills: string[]; deadline: string | null; share_token: string; | |
| created_at: string; answer_seconds: number; question_count: number; company: string; website: string | null; | |
| industry: string | null; company_size: string | null; company_about: string | null; company_location: string | null; | |
| snippet?: string; applicants?: number; description?: string | null; status?: string; accepting?: boolean; | |
| require_camera?: boolean; record_video?: boolean; | |
| }; | |
| export type Application = { | |
| id: string; status: Session["status"]; overall_score: number | null; created_at: string; completed_at: string | null; | |
| title: string; share_token: string; location: string | null; work_mode: WorkMode; employment_type: EmploymentType; | |
| company: string; review_status: "new" | "shortlisted" | "rejected" | "hired"; answered: number; planned: number; | |
| }; | |
| export type TopCandidate = { | |
| id: string; overall_score: number | null; completed_at: string; content_score: string | null; delivery_score: string | null; | |
| hiring_signal: string | null; headline: string | null; full_name: string | null; email: string | null; | |
| candidate_headline: string | null; job_id: string; job_title: string; integrity_level?: Integrity["level"] | null; review_status: CandidateRow["review_status"]; rating: number | null; | |
| }; | |
| export type HiringStats = { | |
| totals: { | |
| jobs: number; open_jobs: number; views: number; applicants: number; people: number; completed: number; in_progress: number; | |
| shortlisted: number; hired: number; rejected: number; to_review: number; flagged: number; avg_score: number | null; median_score: number | null; | |
| best_score: number | null; completion_rate: number | null; avg_minutes: number | null; | |
| }; | |
| funnel: { stage: "views" | "started" | "completed" | "shortlisted" | "hired"; count: number }[]; | |
| timeline: { date: string; applicants: number; completed: number }[]; | |
| distribution: { range: string; count: number }[]; | |
| signals: Record<"strong_yes" | "yes" | "maybe" | "no", number>; | |
| traits: { trait: string; label: string; avg_percentile: number; n: number }[]; | |
| skills: { skill: string; avg: number; n: number }[]; | |
| top: TopCandidate[]; | |
| jobs: { id: string; title: string; status: Job["status"]; views: number; created_at: string; deadline: string | null; accepting: boolean; | |
| applicants: number; completed: number; avg_score: number | null; best_score: number | null; shortlisted: number; hired: number }[]; | |
| }; | |
| export type CandidateRow = { | |
| id: string; | |
| status: Session["status"]; | |
| overall_score: number | null; | |
| created_at: string; | |
| content_score: string | null; | |
| delivery_score: string | null; | |
| hiring_signal: string | null; | |
| headline: string | null; | |
| full_name: string | null; | |
| email: string | null; | |
| review_status: "new" | "shortlisted" | "rejected" | "hired"; | |
| rating: number | null; | |
| notes: string | null; | |
| integrity_score?: number | null; | |
| integrity_level?: Integrity["level"] | null; | |
| cv_match?: number | null; | |
| }; | |