You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 line
4.1KB

  1. import { Injectable } from '@angular/core';
  2. import { HttpClient, HttpHeaders } from '@angular/common/http';
  3. import { Observable } from 'rxjs';
  4. export interface GroqMessage {
  5. role: 'system' | 'user' | 'assistant';
  6. content: string;
  7. }
  8. export interface GroqResponse {
  9. id: string;
  10. object: string;
  11. created: number;
  12. model: string;
  13. choices: Array<{
  14. index: number;
  15. message: {
  16. role: string;
  17. content: string;
  18. };
  19. finish_reason: string;
  20. }>;
  21. usage: {
  22. prompt_tokens: number;
  23. completion_tokens: number;
  24. total_tokens: number;
  25. };
  26. }
  27. @Injectable({
  28. providedIn: 'root'
  29. })
  30. export class GroqService {
  31. private readonly API_URL = 'https://api.groq.com/openai/v1/chat/completions';
  32. private readonly API_KEY = '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'; // Remplacez par votre clé API
  33. constructor(private http: HttpClient) {}
  34. /**
  35. * Envoie un message au chatbot Groq
  36. * @param messages Historique complet de la conversation
  37. * @param model Modèle à utiliser (par défaut: llama-3.3-70b-versatile)
  38. * @returns Observable avec la réponse de Groq
  39. */
  40. sendMessage(
  41. messages: GroqMessage[],
  42. model: string = 'openai/gpt-oss-120b'
  43. ): Observable<GroqResponse> {
  44. const headers = new HttpHeaders({
  45. 'Content-Type': 'application/json',
  46. 'Authorization': `Bearer ${this.API_KEY}`
  47. });
  48. const body = {
  49. model: model,
  50. messages: messages,
  51. temperature: 0.7,
  52. max_tokens: 2048,
  53. top_p: 1,
  54. stream: false
  55. };
  56. return this.http.post<GroqResponse>(this.API_URL, body, { headers });
  57. }
  58. /**
  59. * Envoie un message avec streaming (affichage progressif)
  60. * @param messages Historique de la conversation
  61. * @param onChunk Callback appelé pour chaque morceau de texte reçu
  62. * @param onComplete Callback appelé quand la génération est terminée
  63. * @param onError Callback appelé en cas d'erreur
  64. */
  65. sendMessageStream(
  66. messages: GroqMessage[],
  67. onChunk: (text: string) => void,
  68. onComplete: () => void,
  69. onError: (error: any) => void
  70. ): void {
  71. const headers = new HttpHeaders({
  72. 'Content-Type': 'application/json',
  73. 'Authorization': `Bearer ${this.API_KEY}`
  74. });
  75. const body = {
  76. model: 'openai/gpt-oss-120b',
  77. messages: messages,
  78. temperature: 0.7,
  79. max_tokens: 2048,
  80. stream: true
  81. };
  82. fetch(this.API_URL, {
  83. method: 'POST',
  84. headers: {
  85. 'Content-Type': 'application/json',
  86. 'Authorization': `Bearer ${this.API_KEY}`
  87. },
  88. body: JSON.stringify(body)
  89. })
  90. .then(response => {
  91. if (!response.ok) {
  92. throw new Error(`HTTP error! status: ${response.status}`);
  93. }
  94. return response.body;
  95. })
  96. .then(body => {
  97. const reader = body!.getReader();
  98. const decoder = new TextDecoder();
  99. const processStream = ({ done, value }: ReadableStreamReadResult<Uint8Array>): Promise<void> => {
  100. if (done) {
  101. onComplete();
  102. return Promise.resolve();
  103. }
  104. const chunk = decoder.decode(value);
  105. const lines = chunk.split('\n').filter(line => line.trim() !== '');
  106. for (const line of lines) {
  107. if (line.startsWith('data: ')) {
  108. const data = line.slice(6);
  109. if (data === '[DONE]') {
  110. onComplete();
  111. return Promise.resolve();
  112. }
  113. try {
  114. const parsed = JSON.parse(data);
  115. const content = parsed.choices[0]?.delta?.content;
  116. if (content) {
  117. onChunk(content);
  118. }
  119. } catch (e) {
  120. console.error('Erreur de parsing JSON:', e);
  121. }
  122. }
  123. }
  124. return reader.read().then(processStream);
  125. };
  126. return reader.read().then(processStream);
  127. })
  128. .catch(error => {
  129. console.error('Erreur lors de l\'appel à l\'API:', error);
  130. onError(error);
  131. });
  132. }
  133. /**
  134. * Vérifie si la clé API est configurée
  135. */
  136. isConfigured(): boolean {
  137. return true;
  138. }
  139. }