groq-client.ts
structured.ts
transcribe.ts
migration.ts
groq_client.py
.env.local
Chat básico + Streaming para "Dr. Paw"
src/lib/ai/groq-client.ts
// src/lib/ai/groq-client.ts — NutriPaw · Asistente Dr. Paw (Groq) import Groq from "groq-sdk"; const groq = new Groq({ apiKey: process.env.GROQ_API_KEY!, }); // ── Chat básico ──────────────────────────────────────────────────────── export async function drPawChat(prompt: string): Promise<string> { const completion = await groq.chat.completions.create({ model: "llama-3.3-70b-versatile", // ~350 tok/s — mejor relación calidad/velocidad messages: [ { role: "system", content: "Eres Dr. Paw, nutricionista veterinario experto en perros y gatos. " + "Responde de forma concisa, empática y con base científica.", }, { role: "user", content: prompt }, ], temperature: 0.6, max_tokens: 512, }); return completion.choices[0].message.content ?? ""; } // ── Streaming (tiempo real en el dashboard) ──────────────────────────── export async function drPawStream( prompt: string, onChunk: (text: string) => void ): Promise<string> { const stream = await groq.chat.completions.create({ model: "llama-3.3-70b-versatile", messages: [ { role: "system", content: "Eres Dr. Paw, nutricionista veterinario de NutriPaw." }, { role: "user", content: prompt }, ], stream: true, // ← clave: UI percibe respuesta instantánea }); let full = ""; for await (const chunk of stream) { const text = chunk.choices[0]?.delta?.content ?? ""; full += text; onChunk(text); } return full; }
Extracción estructurada de ingredientes (JSON Mode)
src/lib/ai/structured.ts
// src/lib/ai/structured.ts — Análisis de pienso con salida JSON garantizada interface FeedAnalysis { proteina_pct: number; grasa_pct: number; ingredientes_problematicos: string[]; apto_para: string[]; alertas: { nivel: "info" | "warn" | "error"; msg: string }[]; score_nutricional: number; // 0–100 } export async function analyzeIngredients( rawLabel: string, petProfile: { species: "dog" | "cat"; age: number; conditions: string[] } ): Promise<FeedAnalysis> { const completion = await groq.chat.completions.create({ model: "llama-3.1-8b-instant", // 8B es suficiente para extracción; 2× más barato messages: [ { role: "system", content: `Analiza la etiqueta de pienso para ${petProfile.species} ` + `de ${petProfile.age} años. Condiciones: ${petProfile.conditions.join(",")}. ` + "Devuelve SOLO JSON válido con la estructura FeedAnalysis.", }, { role: "user", content: rawLabel }, ], response_format: { type: "json_object" }, // JSON garantizado sin post-procesado temperature: 0, // determinista para extracción }); return JSON.parse(completion.choices[0].message.content!) as FeedAnalysis; }
Migración drop-in desde OpenAI SDK (0 cambios de lógica)
src/lib/ai/migration.ts
// ANTES: OpenAI SDK (código existente NutriPaw) import OpenAI from "openai"; // const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); // DESPUÉS: Groq con OpenAI SDK — MISMO código, solo cambia base_url import OpenAI from "openai"; export const client = new OpenAI({ apiKey: process.env.GROQ_API_KEY, // ← único cambio de env var baseURL: "https://api.groq.com/openai/v1", // ← apunta a Groq }); // Todo el código anterior funciona sin cambios: const res = await client.chat.completions.create({ model: "llama-3.3-70b-versatile", // sustituye gpt-4o-mini messages: [{ role: "user", content: "¿Puede un perro comer uvas?" }], stream: true, });
Selección de Modelo por Caso de Uso — NutriPaw
| Modelo | Velocidad | Contexto | Mejor para | Uso en NutriPaw | Rec. |
|---|---|---|---|---|---|
| llama-3.3-70b-versatile | ~350 tok/s | 128K | Chat, razonamiento, código | Dr. Paw assistant, planes nutricionales | CHAT |
| llama-3.1-8b-instant | ~750 tok/s | 128K | Extracción, clasificación | Análisis de etiquetas de pienso (JSON) | EXTRACT |
| mixtral-8x7b-32768 | ~500 tok/s | 32K | Multilingüe, contenido creativo | Emails en FR/DE/IT para expansión EU | MULTI |
| whisper-large-v3-turbo | ~200× RT | Audio | Transcripción de audio | Voice notes del veterinario → texto | AUDIO |
Comparativa de Latencia P50 — Chat "Dr. Paw" (512 tokens)
OpenAI gpt-4o-mini
3.800ms
Groq llama-3.3-70b
420ms
Groq llama-3.1-8b
180ms