fix: ia streaming usa json.Decoder en vez de Scanner + loggeo + manejo error interno Ollama

This commit is contained in:
Lizandro Guarnizo
2026-07-06 23:40:56 -05:00
parent 9dfa3afab0
commit b6522fa850
+30 -11
View File
@@ -5,6 +5,8 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@@ -22,6 +24,7 @@ type DataIa struct {
type respuestaOllama struct { type respuestaOllama struct {
Response string `json:"response"` Response string `json:"response"`
Done bool `json:"done"` Done bool `json:"done"`
Error string `json:"error"`
} }
func GeneraTextoStream(c *fiber.Ctx) error { func GeneraTextoStream(c *fiber.Ctx) error {
@@ -31,8 +34,10 @@ func GeneraTextoStream(c *fiber.Ctx) error {
} }
data.Stream = true data.Stream = true
hasDBConfig := true
config, err := models.GetAiConfigForService("ia") config, err := models.GetAiConfigForService("ia")
if err != nil { if err != nil {
hasDBConfig = false
config = &models.AiConfig{ config = &models.AiConfig{
BaseURL: "http://72.60.24.97:8080/ollama", BaseURL: "http://72.60.24.97:8080/ollama",
ApiKey: "", ApiKey: "",
@@ -49,6 +54,12 @@ func GeneraTextoStream(c *fiber.Ctx) error {
baseURL := strings.TrimSuffix(strings.TrimRight(config.BaseURL, "/"), "/v1") baseURL := strings.TrimSuffix(strings.TrimRight(config.BaseURL, "/"), "/v1")
endpoint := baseURL + "/api/generate" endpoint := baseURL + "/api/generate"
if !hasDBConfig {
log.Printf("[IA] Usando config default: endpoint=%s model=%s", endpoint, data.Model)
} else {
log.Printf("[IA] Usando config BD: endpoint=%s model=%s", endpoint, data.Model)
}
jsonData, _ := json.Marshal(data) jsonData, _ := json.Marshal(data)
req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(jsonData)) req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(jsonData))
if err != nil { if err != nil {
@@ -62,31 +73,39 @@ func GeneraTextoStream(c *fiber.Ctx) error {
client := &http.Client{Timeout: 120 * time.Second} client := &http.Client{Timeout: 120 * time.Second}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Printf("[IA] Error conectando a Ollama: %v", err)
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()}) return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
resp.Body.Close() resp.Body.Close()
log.Printf("[IA] Ollama status %d: %s", resp.StatusCode, string(bodyBytes))
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{ return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{
"error": fmt.Sprintf("Ollama respondió con status %d", resp.StatusCode), "error": fmt.Sprintf("Ollama respondió con status %d", resp.StatusCode),
"details": string(bodyBytes),
}) })
} }
c.Set("Content-Type", "text/plain; charset=utf-8") c.Set("Content-Type", "text/plain; charset=utf-8")
c.Set("Cache-Control", "no-cache") c.Set("Cache-Control", "no-cache")
c.Set("Connection", "keep-alive") c.Set("X-Accel-Buffering", "no")
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) { c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
defer resp.Body.Close() defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body) dec := json.NewDecoder(resp.Body)
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024) for {
for scanner.Scan() {
line := scanner.Bytes()
if len(line) == 0 {
continue
}
var msg respuestaOllama var msg respuestaOllama
if err := json.Unmarshal(line, &msg); err != nil { if err := dec.Decode(&msg); err != nil {
continue if err != io.EOF {
log.Printf("[IA] Error decodificando: %v", err)
}
break
}
if msg.Error != "" {
log.Printf("[IA] Ollama error: %s", msg.Error)
fmt.Fprintf(w, "[Error: %s]", msg.Error)
w.Flush()
break
} }
if msg.Response != "" { if msg.Response != "" {
fmt.Fprint(w, msg.Response) fmt.Fprint(w, msg.Response)