import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; export interface GroqMessage { role: 'system' | 'user' | 'assistant'; content: string; } export interface GroqResponse { id: string; object: string; created: number; model: string; choices: Array<{ index: number; message: { role: string; content: string; }; finish_reason: string; }>; usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number; }; } @Injectable({ providedIn: 'root' }) export class GroqService { private readonly API_URL = 'https://api.groq.com/openai/v1/chat/completions'; private readonly API_KEY = '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'; // Remplacez par votre clé API constructor(private http: HttpClient) {} /** * Envoie un message au chatbot Groq * @param messages Historique complet de la conversation * @param model Modèle à utiliser (par défaut: llama-3.3-70b-versatile) * @returns Observable avec la réponse de Groq */ sendMessage( messages: GroqMessage[], model: string = 'openai/gpt-oss-120b' ): Observable { const headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.API_KEY}` }); const body = { model: model, messages: messages, temperature: 0.7, max_tokens: 2048, top_p: 1, stream: false }; return this.http.post(this.API_URL, body, { headers }); } /** * Envoie un message avec streaming (affichage progressif) * @param messages Historique de la conversation * @param onChunk Callback appelé pour chaque morceau de texte reçu * @param onComplete Callback appelé quand la génération est terminée * @param onError Callback appelé en cas d'erreur */ sendMessageStream( messages: GroqMessage[], onChunk: (text: string) => void, onComplete: () => void, onError: (error: any) => void ): void { const headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.API_KEY}` }); const body = { model: 'openai/gpt-oss-120b', messages: messages, temperature: 0.7, max_tokens: 2048, stream: true }; fetch(this.API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.API_KEY}` }, body: JSON.stringify(body) }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.body; }) .then(body => { const reader = body!.getReader(); const decoder = new TextDecoder(); const processStream = ({ done, value }: ReadableStreamReadResult): Promise => { if (done) { onComplete(); return Promise.resolve(); } const chunk = decoder.decode(value); const lines = chunk.split('\n').filter(line => line.trim() !== ''); for (const line of lines) { if (line.startsWith('data: ')) { const data = line.slice(6); if (data === '[DONE]') { onComplete(); return Promise.resolve(); } try { const parsed = JSON.parse(data); const content = parsed.choices[0]?.delta?.content; if (content) { onChunk(content); } } catch (e) { console.error('Erreur de parsing JSON:', e); } } } return reader.read().then(processStream); }; return reader.read().then(processStream); }) .catch(error => { console.error('Erreur lors de l\'appel à l\'API:', error); onError(error); }); } /** * Vérifie si la clé API est configurée */ isConfigured(): boolean { return true; } }