import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; type Grade = 'lowergrade' | 'midgrade' | 'highergrade'; type DbLevel = 'low' | 'mid' | 'high'; function resolveBaseUrl(): string { const isHF = location.hostname.endsWith('hf.space'); if (isHF) return 'https://pykara-py-learn-backend.hf.space/rag'; if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') { return 'http://localhost:5000/rag'; } return '/rag'; } @Injectable({ providedIn: 'root' }) export class ApiService { private baseUrl = resolveBaseUrl(); private getGrade(): Grade { const g = (localStorage.getItem('gradeLevel') || 'highergrade').toLowerCase(); if (g === 'lowergrade' || g === 'midgrade' || g === 'highergrade') return g as Grade; return 'highergrade'; } private toDbLevel(g: Grade): DbLevel { return g === 'lowergrade' ? 'low' : g === 'midgrade' ? 'mid' : 'high'; } private makeHeaders(g: Grade): HttpHeaders { return new HttpHeaders({ 'Content-Type': 'application/json', 'X-User': g, }); } constructor(private http: HttpClient) { } generateOpenQuestions(payload: { qtype: 'OPEN'; n?: number; topic?: string }): Observable { const grade = this.getGrade(); const headers = this.makeHeaders(grade); const body = { qtype: 'OPEN', n: payload.n ?? 5, topic: payload.topic ?? '', model: 'gpt-4o-mini', db_level: this.toDbLevel(grade), }; return this.http.post(`${this.baseUrl}/generate-questions`, body, { headers }); } // Accept either a string (legacy) or an object { question, synthesize_audio, synthesize_video } explainGrammar(payload: string | any): Observable { const grade = this.getGrade(); const headers = this.makeHeaders(grade); // Normalize payload into an object const body = typeof payload === 'string' ? { question: payload } : { ...payload }; // Ensure backend gets db_level and model so it selects the right vectorstore/LLM if (!body.db_level) body.db_level = this.toDbLevel(grade); if (!body.model) body.model = 'gpt-4o-mini'; const url = `${this.baseUrl}/explain-grammar`; return this.http.post(url, body, { headers }); } // ✅ Updated to carry source_ids so follow-ups stay in the same textbook pages suggestFollowups(payload: { last_question: string; last_answer: string; n?: number; source_ids?: string[]; // ← NEW }): Observable { const grade = this.getGrade(); const headers = this.makeHeaders(grade); const body = { last_question: payload.last_question, last_answer: payload.last_answer, n: payload.n ?? 5, model: 'gpt-4o-mini', db_level: this.toDbLevel(grade), source_ids: payload.source_ids ?? [], // ← NEW }; return this.http.post(`${this.baseUrl}/suggest-followups`, body, { headers }); } askQuestion(userInput: string, _sessionId: string | null): Observable { return this.explainGrammar(userInput); } // add method in ApiService synthesizeAudio(text: string, language = 'en', referenceFiles?: string[]) { const payload: any = { text, language }; if (referenceFiles) payload.reference_files = referenceFiles; return this.http.post<{ audio_url: string }>(`${this.baseUrl}/synthesize-audio`, payload); } // New: synthesize video (calls backend D-ID flow) synthesizeVideo(text: string, language = 'en') { const payload: any = { text, language }; return this.http.post<{ video_url: string }>(`${this.baseUrl}/synthesize-video`, payload); } punctuate(text: string): Observable { const headers = { 'Content-Type': 'application/json', 'X-User': localStorage.getItem('username') || '' }; // Use the port your backend runs on (your local runner uses 7000) return this.http.post(`${this.baseUrl}/punctuate`, { text }, { headers }); } }