Spaces:
Sleeping
Sleeping
Tu Nombre
commited on
Commit
·
13c15b7
1
Parent(s):
abd1ef4
Initial commit for Papalia3 Space
Browse files- .DS_Store +0 -0
- Dockerfile +38 -36
- README.md +1 -1
- app.py +15 -49
- requirements.txt +1 -1
- templates/index.html +21 -36
.DS_Store
CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
|
|
Dockerfile
CHANGED
@@ -1,10 +1,9 @@
|
|
|
|
1 |
FROM python:3.9
|
2 |
|
3 |
-
# Install Ollama and required tools
|
4 |
RUN apt-get update && apt-get install -y curl wget netcat-traditional && \
|
5 |
curl -fsSL https://ollama.com/install.sh | sh
|
6 |
|
7 |
-
# Create non-root user
|
8 |
RUN useradd -m -u 1000 user
|
9 |
|
10 |
WORKDIR /app
|
@@ -12,41 +11,45 @@ WORKDIR /app
|
|
12 |
COPY --chown=user ./requirements.txt requirements.txt
|
13 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
14 |
|
15 |
-
# Copy application files including templates
|
16 |
COPY --chown=user . /app
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
50 |
exec uvicorn app:app --host 0.0.0.0 --port 7860 --timeout-keep-alive 120' > /app/start.sh
|
51 |
|
52 |
RUN chmod +x /app/start.sh
|
@@ -54,7 +57,6 @@ RUN chmod +x /app/start.sh
|
|
54 |
USER user
|
55 |
ENV PATH="/home/user/.local/bin:$PATH"
|
56 |
|
57 |
-
# Health check with increased interval
|
58 |
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=3 \
|
59 |
CMD curl -f http://localhost:7860/health || exit 1
|
60 |
|
|
|
1 |
+
# Dockerfile
|
2 |
FROM python:3.9
|
3 |
|
|
|
4 |
RUN apt-get update && apt-get install -y curl wget netcat-traditional && \
|
5 |
curl -fsSL https://ollama.com/install.sh | sh
|
6 |
|
|
|
7 |
RUN useradd -m -u 1000 user
|
8 |
|
9 |
WORKDIR /app
|
|
|
11 |
COPY --chown=user ./requirements.txt requirements.txt
|
12 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
13 |
|
|
|
14 |
COPY --chown=user . /app
|
15 |
|
16 |
+
RUN echo 'FROM llama3
|
17 |
+
|
18 |
+
SYSTEM "Eres un asistente especializado en Desarrollo Humano, basado en la duodécima edición del libro de Papalia. Tu objetivo es proporcionar información precisa y actualizada sobre el desarrollo humano a lo largo del ciclo vital. Base tu conocimiento en la obra de Diane E. Papalia, Ruth Duskin Feldman y Gabriela Martorell. Utiliza siempre evidencia científica y ejemplos del libro para respaldar tus respuestas."
|
19 |
+
|
20 |
+
PARAMETER temperature 0.7
|
21 |
+
PARAMETER top_k 40
|
22 |
+
PARAMETER top_p 0.7
|
23 |
+
PARAMETER repeat_penalty 1.1' > /app/Modelfile
|
24 |
+
|
25 |
+
RUN printf '#!/bin/bash
|
26 |
+
echo "Configurando sistema..."
|
27 |
+
ulimit -v unlimited
|
28 |
+
|
29 |
+
echo "Iniciando servidor Ollama..."
|
30 |
+
ollama serve &
|
31 |
+
|
32 |
+
echo "Esperando a que Ollama esté listo..."
|
33 |
+
for i in {1..120}; do
|
34 |
+
if nc -z localhost 11434; then
|
35 |
+
echo "Ollama está listo"
|
36 |
+
break
|
37 |
+
fi
|
38 |
+
echo "Esperando a Ollama... $i/120s"
|
39 |
+
sleep 1
|
40 |
+
done
|
41 |
+
|
42 |
+
echo "Creando modelo..."
|
43 |
+
cd /app
|
44 |
+
ollama create llama3.2:1b-papalia -f Modelfile
|
45 |
+
|
46 |
+
echo "Verificando modelo..."
|
47 |
+
if ! ollama list | grep -q "llama3.2:1b-papalia"; then
|
48 |
+
echo "Error: El modelo no se pudo crear"
|
49 |
+
exit 1
|
50 |
+
fi
|
51 |
+
|
52 |
+
echo "Iniciando API..."
|
53 |
exec uvicorn app:app --host 0.0.0.0 --port 7860 --timeout-keep-alive 120' > /app/start.sh
|
54 |
|
55 |
RUN chmod +x /app/start.sh
|
|
|
57 |
USER user
|
58 |
ENV PATH="/home/user/.local/bin:$PATH"
|
59 |
|
|
|
60 |
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=3 \
|
61 |
CMD curl -f http://localhost:7860/health || exit 1
|
62 |
|
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: 🏃
|
4 |
colorFrom: red
|
5 |
colorTo: purple
|
|
|
1 |
---
|
2 |
+
title: Papali3
|
3 |
emoji: 🏃
|
4 |
colorFrom: red
|
5 |
colorTo: purple
|
app.py
CHANGED
@@ -1,11 +1,9 @@
|
|
1 |
from fastapi import FastAPI, HTTPException, Request
|
2 |
from fastapi.responses import HTMLResponse, JSONResponse
|
3 |
-
from fastapi.staticfiles import StaticFiles
|
4 |
from fastapi.templating import Jinja2Templates
|
5 |
from fastapi.middleware.cors import CORSMiddleware
|
6 |
from pydantic import BaseModel
|
7 |
import httpx
|
8 |
-
import os
|
9 |
import logging
|
10 |
from typing import Optional, Dict, Any
|
11 |
|
@@ -13,19 +11,12 @@ logging.basicConfig(level=logging.INFO)
|
|
13 |
logger = logging.getLogger(__name__)
|
14 |
|
15 |
app = FastAPI(
|
16 |
-
title="Llama3-Papalia Inference API
|
17 |
-
description="API para interactuar con el modelo
|
18 |
version="1.0.0"
|
19 |
)
|
20 |
|
21 |
-
app.add_middleware(
|
22 |
-
CORSMiddleware,
|
23 |
-
allow_origins=["*"],
|
24 |
-
allow_credentials=True,
|
25 |
-
allow_methods=["*"],
|
26 |
-
allow_headers=["*"],
|
27 |
-
)
|
28 |
-
|
29 |
templates = Jinja2Templates(directory="templates")
|
30 |
|
31 |
class QueryRequest(BaseModel):
|
@@ -45,11 +36,10 @@ async def check_ollama_status() -> Dict[str, Any]:
|
|
45 |
async with httpx.AsyncClient(timeout=5.0) as client:
|
46 |
response = await client.get(OLLAMA_BASE_URL)
|
47 |
if response.status_code != 200:
|
48 |
-
return {"status": "error", "message": "Ollama no responde"
|
49 |
|
50 |
-
# Verificar que el modelo esté disponible
|
51 |
model_response = await client.post(
|
52 |
-
|
53 |
json={
|
54 |
"model": "llama3.2:1b-papalia",
|
55 |
"prompt": "test",
|
@@ -57,38 +47,25 @@ async def check_ollama_status() -> Dict[str, Any]:
|
|
57 |
},
|
58 |
timeout=5.0
|
59 |
)
|
60 |
-
|
61 |
if model_response.status_code != 200:
|
62 |
-
return {"status": "error", "message": "Modelo no disponible"
|
63 |
-
|
64 |
-
return {"status": "ok", "message": "Servicio funcionando correctamente"}
|
65 |
except Exception as e:
|
66 |
return {"status": "error", "message": str(e)}
|
67 |
|
68 |
@app.get("/", response_class=HTMLResponse)
|
69 |
async def read_root(request: Request):
|
70 |
status = await check_ollama_status()
|
71 |
-
return templates.TemplateResponse(
|
72 |
-
"index.html",
|
73 |
-
{
|
74 |
-
"request": request,
|
75 |
-
"title": "Llama3-Papalia Inference",
|
76 |
-
"status": status
|
77 |
-
}
|
78 |
-
)
|
79 |
|
80 |
@app.post("/generate")
|
81 |
async def generate_response(query: QueryRequest):
|
82 |
-
logger.info(f"
|
83 |
-
|
84 |
try:
|
85 |
async with httpx.AsyncClient(timeout=60.0) as client:
|
86 |
status = await check_ollama_status()
|
87 |
if status["status"] != "ok":
|
88 |
-
raise HTTPException(
|
89 |
-
status_code=503,
|
90 |
-
detail=status["message"]
|
91 |
-
)
|
92 |
|
93 |
response = await client.post(
|
94 |
OLLAMA_API_URL,
|
@@ -103,31 +80,20 @@ async def generate_response(query: QueryRequest):
|
|
103 |
)
|
104 |
|
105 |
if response.status_code != 200:
|
106 |
-
raise HTTPException(
|
107 |
-
status_code=response.status_code,
|
108 |
-
detail=f"Error del modelo: {response.text}"
|
109 |
-
)
|
110 |
|
111 |
result = response.json()
|
112 |
logger.info("Respuesta generada exitosamente")
|
113 |
return {"response": result.get("response", ""), "model": "llama3.2:1b-papalia"}
|
114 |
|
115 |
except httpx.TimeoutException:
|
116 |
-
logger.error("Timeout en
|
117 |
-
raise HTTPException(
|
118 |
-
status_code=504,
|
119 |
-
detail="Timeout en la solicitud al modelo"
|
120 |
-
)
|
121 |
except Exception as e:
|
122 |
logger.error(f"Error: {str(e)}")
|
123 |
-
raise HTTPException(
|
124 |
-
status_code=500,
|
125 |
-
detail=str(e)
|
126 |
-
)
|
127 |
|
128 |
@app.get("/health")
|
129 |
async def health_check():
|
130 |
status = await check_ollama_status()
|
131 |
-
if status["status"] == "ok":
|
132 |
-
return {"status": "healthy", "message": status["message"]}
|
133 |
-
return {"status": "unhealthy", "error": status["message"]}
|
|
|
1 |
from fastapi import FastAPI, HTTPException, Request
|
2 |
from fastapi.responses import HTMLResponse, JSONResponse
|
|
|
3 |
from fastapi.templating import Jinja2Templates
|
4 |
from fastapi.middleware.cors import CORSMiddleware
|
5 |
from pydantic import BaseModel
|
6 |
import httpx
|
|
|
7 |
import logging
|
8 |
from typing import Optional, Dict, Any
|
9 |
|
|
|
11 |
logger = logging.getLogger(__name__)
|
12 |
|
13 |
app = FastAPI(
|
14 |
+
title="Llama3.2:1b-Papalia Inference API",
|
15 |
+
description="API para interactuar con el modelo especializado en Desarrollo Humano",
|
16 |
version="1.0.0"
|
17 |
)
|
18 |
|
19 |
+
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
templates = Jinja2Templates(directory="templates")
|
21 |
|
22 |
class QueryRequest(BaseModel):
|
|
|
36 |
async with httpx.AsyncClient(timeout=5.0) as client:
|
37 |
response = await client.get(OLLAMA_BASE_URL)
|
38 |
if response.status_code != 200:
|
39 |
+
return {"status": "error", "message": "Ollama no responde"}
|
40 |
|
|
|
41 |
model_response = await client.post(
|
42 |
+
OLLAMA_API_URL,
|
43 |
json={
|
44 |
"model": "llama3.2:1b-papalia",
|
45 |
"prompt": "test",
|
|
|
47 |
},
|
48 |
timeout=5.0
|
49 |
)
|
|
|
50 |
if model_response.status_code != 200:
|
51 |
+
return {"status": "error", "message": "Modelo no disponible"}
|
52 |
+
return {"status": "ok", "message": "Servicio activo"}
|
|
|
53 |
except Exception as e:
|
54 |
return {"status": "error", "message": str(e)}
|
55 |
|
56 |
@app.get("/", response_class=HTMLResponse)
|
57 |
async def read_root(request: Request):
|
58 |
status = await check_ollama_status()
|
59 |
+
return templates.TemplateResponse("index.html", {"request": request, "title": "Papalia3 Inference", "status": status})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
@app.post("/generate")
|
62 |
async def generate_response(query: QueryRequest):
|
63 |
+
logger.info(f"Solicitud recibida: {query.prompt[:50]}...")
|
|
|
64 |
try:
|
65 |
async with httpx.AsyncClient(timeout=60.0) as client:
|
66 |
status = await check_ollama_status()
|
67 |
if status["status"] != "ok":
|
68 |
+
raise HTTPException(status_code=503, detail=status["message"])
|
|
|
|
|
|
|
69 |
|
70 |
response = await client.post(
|
71 |
OLLAMA_API_URL,
|
|
|
80 |
)
|
81 |
|
82 |
if response.status_code != 200:
|
83 |
+
raise HTTPException(status_code=response.status_code, detail=f"Error del modelo: {response.text}")
|
|
|
|
|
|
|
84 |
|
85 |
result = response.json()
|
86 |
logger.info("Respuesta generada exitosamente")
|
87 |
return {"response": result.get("response", ""), "model": "llama3.2:1b-papalia"}
|
88 |
|
89 |
except httpx.TimeoutException:
|
90 |
+
logger.error("Timeout en solicitud a Ollama")
|
91 |
+
raise HTTPException(status_code=504, detail="Timeout en solicitud al modelo")
|
|
|
|
|
|
|
92 |
except Exception as e:
|
93 |
logger.error(f"Error: {str(e)}")
|
94 |
+
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
|
95 |
|
96 |
@app.get("/health")
|
97 |
async def health_check():
|
98 |
status = await check_ollama_status()
|
99 |
+
return {"status": "healthy", "message": status["message"]} if status["status"] == "ok" else {"status": "unhealthy", "error": status["message"]}
|
|
|
|
requirements.txt
CHANGED
@@ -4,4 +4,4 @@ python-dotenv==1.0.0
|
|
4 |
httpx==0.25.2
|
5 |
pydantic==2.5.2
|
6 |
jinja2==3.1.2
|
7 |
-
python-multipart==0.0.6
|
|
|
4 |
httpx==0.25.2
|
5 |
pydantic==2.5.2
|
6 |
jinja2==3.1.2
|
7 |
+
python-multipart==0.0.6
|
templates/index.html
CHANGED
@@ -1,33 +1,30 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
-
<title>
|
5 |
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
6 |
</head>
|
7 |
-
<body class="bg-gray-100 p-8">
|
8 |
<div class="max-w-4xl mx-auto">
|
9 |
<div class="flex justify-between items-center mb-8">
|
10 |
-
<h1 class="text-3xl font-bold">
|
11 |
<div id="service-status" class="text-sm">Verificando estado...</div>
|
12 |
</div>
|
13 |
|
14 |
-
<div class="bg-white rounded-lg shadow-md p-6">
|
15 |
<div class="mb-4">
|
16 |
-
<label class="block text-gray-700 text-sm font-bold mb-2" for="prompt">
|
17 |
-
Prompt
|
18 |
-
</label>
|
19 |
<textarea
|
20 |
id="prompt"
|
21 |
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
22 |
rows="4"
|
23 |
-
placeholder="Escribe tu pregunta
|
24 |
</div>
|
25 |
|
26 |
<div class="grid grid-cols-2 gap-4 mb-4">
|
27 |
<div>
|
28 |
-
<label class="block text-gray-700 text-sm font-bold mb-2" for="temperature">
|
29 |
-
Temperature
|
30 |
-
</label>
|
31 |
<input
|
32 |
type="number"
|
33 |
id="temperature"
|
@@ -38,9 +35,7 @@
|
|
38 |
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
39 |
</div>
|
40 |
<div>
|
41 |
-
<label class="block text-gray-700 text-sm font-bold mb-2" for="max_tokens">
|
42 |
-
Max Tokens
|
43 |
-
</label>
|
44 |
<input
|
45 |
type="number"
|
46 |
id="max_tokens"
|
@@ -58,19 +53,14 @@
|
|
58 |
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline disabled:opacity-50">
|
59 |
Generar Respuesta
|
60 |
</button>
|
61 |
-
<div id="loading" class="hidden">
|
62 |
Generando...
|
63 |
</div>
|
64 |
</div>
|
65 |
|
66 |
-
<div class="mt-
|
67 |
-
<label class="block text-gray-700 text-sm font-bold mb-2">
|
68 |
-
|
69 |
-
</label>
|
70 |
-
<div
|
71 |
-
id="response"
|
72 |
-
class="mt-2 p-4 bg-gray-100 rounded min-h-[200px] whitespace-pre-wrap">
|
73 |
-
</div>
|
74 |
</div>
|
75 |
</div>
|
76 |
</div>
|
@@ -81,20 +71,21 @@
|
|
81 |
const response = await fetch('/health');
|
82 |
const data = await response.json();
|
83 |
const statusEl = document.getElementById('service-status');
|
|
|
84 |
|
85 |
if (data.status === 'healthy') {
|
86 |
statusEl.textContent = '✅ Servicio activo';
|
87 |
-
statusEl.className = 'text-green-600';
|
88 |
-
|
89 |
} else {
|
90 |
statusEl.textContent = '❌ ' + (data.error || 'Servicio no disponible');
|
91 |
-
statusEl.className = 'text-red-600';
|
92 |
-
|
93 |
}
|
94 |
} catch (error) {
|
95 |
const statusEl = document.getElementById('service-status');
|
96 |
statusEl.textContent = '❌ Error de conexión';
|
97 |
-
statusEl.className = 'text-red-600';
|
98 |
document.getElementById('generate-button').disabled = true;
|
99 |
}
|
100 |
}
|
@@ -119,9 +110,7 @@
|
|
119 |
try {
|
120 |
const response = await fetch('/generate', {
|
121 |
method: 'POST',
|
122 |
-
headers: {
|
123 |
-
'Content-Type': 'application/json',
|
124 |
-
},
|
125 |
body: JSON.stringify({
|
126 |
prompt: promptEl.value,
|
127 |
temperature: parseFloat(temperatureEl.value),
|
@@ -130,10 +119,7 @@
|
|
130 |
});
|
131 |
|
132 |
const data = await response.json();
|
133 |
-
|
134 |
-
if (!response.ok) {
|
135 |
-
throw new Error(data.detail || 'Error en la generación de respuesta');
|
136 |
-
}
|
137 |
|
138 |
responseEl.textContent = data.response || 'No se recibió respuesta del modelo';
|
139 |
responseEl.className = 'mt-2 p-4 bg-gray-100 rounded min-h-[200px] whitespace-pre-wrap';
|
@@ -146,7 +132,6 @@
|
|
146 |
}
|
147 |
}
|
148 |
|
149 |
-
// Verificar estado cada 30 segundos
|
150 |
checkHealth();
|
151 |
setInterval(checkHealth, 30000);
|
152 |
</script>
|
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
+
<title>Papalia3 Inference</title>
|
5 |
<script src="https://cdn.tailwindcss.com"></script>
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
</head>
|
8 |
+
<body class="bg-gray-100 p-4 md:p-8">
|
9 |
<div class="max-w-4xl mx-auto">
|
10 |
<div class="flex justify-between items-center mb-8">
|
11 |
+
<h1 class="text-2xl md:text-3xl font-bold">Papalia3 - Desarrollo Humano</h1>
|
12 |
<div id="service-status" class="text-sm">Verificando estado...</div>
|
13 |
</div>
|
14 |
|
15 |
+
<div class="bg-white rounded-lg shadow-md p-4 md:p-6">
|
16 |
<div class="mb-4">
|
17 |
+
<label class="block text-gray-700 text-sm font-bold mb-2" for="prompt">Prompt</label>
|
|
|
|
|
18 |
<textarea
|
19 |
id="prompt"
|
20 |
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
21 |
rows="4"
|
22 |
+
placeholder="Escribe tu pregunta sobre Desarrollo Humano..."></textarea>
|
23 |
</div>
|
24 |
|
25 |
<div class="grid grid-cols-2 gap-4 mb-4">
|
26 |
<div>
|
27 |
+
<label class="block text-gray-700 text-sm font-bold mb-2" for="temperature">Temperature</label>
|
|
|
|
|
28 |
<input
|
29 |
type="number"
|
30 |
id="temperature"
|
|
|
35 |
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
36 |
</div>
|
37 |
<div>
|
38 |
+
<label class="block text-gray-700 text-sm font-bold mb-2" for="max_tokens">Max Tokens</label>
|
|
|
|
|
39 |
<input
|
40 |
type="number"
|
41 |
id="max_tokens"
|
|
|
53 |
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline disabled:opacity-50">
|
54 |
Generar Respuesta
|
55 |
</button>
|
56 |
+
<div id="loading" class="hidden text-gray-600">
|
57 |
Generando...
|
58 |
</div>
|
59 |
</div>
|
60 |
|
61 |
+
<div class="mt-6">
|
62 |
+
<label class="block text-gray-700 text-sm font-bold mb-2">Respuesta</label>
|
63 |
+
<div id="response" class="mt-2 p-4 bg-gray-100 rounded min-h-[200px] whitespace-pre-wrap"></div>
|
|
|
|
|
|
|
|
|
|
|
64 |
</div>
|
65 |
</div>
|
66 |
</div>
|
|
|
71 |
const response = await fetch('/health');
|
72 |
const data = await response.json();
|
73 |
const statusEl = document.getElementById('service-status');
|
74 |
+
const buttonEl = document.getElementById('generate-button');
|
75 |
|
76 |
if (data.status === 'healthy') {
|
77 |
statusEl.textContent = '✅ Servicio activo';
|
78 |
+
statusEl.className = 'text-sm text-green-600';
|
79 |
+
buttonEl.disabled = false;
|
80 |
} else {
|
81 |
statusEl.textContent = '❌ ' + (data.error || 'Servicio no disponible');
|
82 |
+
statusEl.className = 'text-sm text-red-600';
|
83 |
+
buttonEl.disabled = true;
|
84 |
}
|
85 |
} catch (error) {
|
86 |
const statusEl = document.getElementById('service-status');
|
87 |
statusEl.textContent = '❌ Error de conexión';
|
88 |
+
statusEl.className = 'text-sm text-red-600';
|
89 |
document.getElementById('generate-button').disabled = true;
|
90 |
}
|
91 |
}
|
|
|
110 |
try {
|
111 |
const response = await fetch('/generate', {
|
112 |
method: 'POST',
|
113 |
+
headers: {'Content-Type': 'application/json'},
|
|
|
|
|
114 |
body: JSON.stringify({
|
115 |
prompt: promptEl.value,
|
116 |
temperature: parseFloat(temperatureEl.value),
|
|
|
119 |
});
|
120 |
|
121 |
const data = await response.json();
|
122 |
+
if (!response.ok) throw new Error(data.detail || 'Error en la generación');
|
|
|
|
|
|
|
123 |
|
124 |
responseEl.textContent = data.response || 'No se recibió respuesta del modelo';
|
125 |
responseEl.className = 'mt-2 p-4 bg-gray-100 rounded min-h-[200px] whitespace-pre-wrap';
|
|
|
132 |
}
|
133 |
}
|
134 |
|
|
|
135 |
checkHealth();
|
136 |
setInterval(checkHealth, 30000);
|
137 |
</script>
|