Server-1730576 / server.py
Simonc-44's picture
Update server.py
1c1af47 verified
Raw
History Blame Contribute Delete
5.36 kB
from fastapi import FastAPI
from fastapi.responses import StreamingResponse, HTMLResponse
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer
import torch
import threading
app = FastAPI()
MODEL_NAME = "unsloth/gemma-3-1b-pt"
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
device_map="cpu",
torch_dtype=torch.float32,
low_cpu_mem_usage=True
)
class Request(BaseModel):
message: str
# =========================
# FRONTEND HTML (TON CODE)
# =========================
@app.get("/", response_class=HTMLResponse)
def home():
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Server Status</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap');
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at top, #0b1020, #030712);
font-family: Inter, sans-serif;
color: white;
overflow: hidden;
}
/* background glow */
.glow {
position: absolute;
width: 700px;
height: 700px;
background: radial-gradient(circle, rgba(99,102,241,0.25), transparent 60%);
filter: blur(70px);
animation: float 6s ease-in-out infinite;
}
@keyframes float {
0%,100% { transform: translateY(0px); }
50% { transform: translateY(-50px); }
}
/* main card */
.card {
position: relative;
text-align: center;
padding: 60px 70px;
border-radius: 28px;
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.08);
backdrop-filter: blur(22px);
box-shadow: 0 30px 100px rgba(0,0,0,0.7);
animation: fadeIn 1.2s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
/* STATUS TEXT */
.status {
display: flex;
align-items: center;
justify-content: center;
gap: 14px;
font-size: 30px;
font-weight: 600;
letter-spacing: 1px;
}
/* ULTRA DOT ANIMATION */
.dot {
width: 14px;
height: 14px;
background: #10b981;
border-radius: 50%;
position: relative;
box-shadow: 0 0 15px rgba(16,185,129,0.9);
animation: flicker 2.2s ease-in-out infinite;
}
.dot::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background: #10b981;
border-radius: 50%;
transform: translate(-50%, -50%);
animation: pulse1 1.8s ease-out infinite;
opacity: 0.6;
}
.dot::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background: #34d399;
border-radius: 50%;
transform: translate(-50%, -50%);
animation: pulse2 2.4s ease-out infinite;
opacity: 0.4;
}
@keyframes flicker {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(0.92); opacity: 0.85; }
}
@keyframes pulse1 {
0% {
transform: translate(-50%, -50%) scale(1);
opacity: 0.7;
}
100% {
transform: translate(-50%, -50%) scale(3.8);
opacity: 0;
}
}
@keyframes pulse2 {
0% {
transform: translate(-50%, -50%) scale(1);
opacity: 0.5;
}
100% {
transform: translate(-50%, -50%) scale(5.5);
opacity: 0;
}
}
.subtitle {
margin-top: 14px;
font-size: 14px;
color: #9ca3af;
letter-spacing: 0.4px;
}
.badge {
margin-top: 22px;
display: inline-block;
padding: 6px 14px;
border-radius: 999px;
font-size: 12px;
background: rgba(99,102,241,0.15);
border: 1px solid rgba(99,102,241,0.35);
color: #a5b4fc;
}
/* particles */
.particle {
position: absolute;
width: 6px;
height: 6px;
background: rgba(255,255,255,0.08);
border-radius: 50%;
animation: move 10s linear infinite;
}
@keyframes move {
from { transform: translateY(0px); opacity: 0; }
50% { opacity: 1; }
to { transform: translateY(-600px); opacity: 0; }
}
</style>
</head>
<body>
<div class="glow"></div>
<div class="particle" style="left:10%; top:80%;"></div>
<div class="particle" style="left:30%; top:90%;"></div>
<div class="particle" style="left:70%; top:85%;"></div>
<div class="particle" style="left:90%; top:95%;"></div>
<div class="card">
<div class="status">
<div class="dot"></div>
Server Running
</div>
</div>
</body>
</html>
"""
# =========================
# CHAT STREAM (FIXÉ)
# =========================
@app.post("/chat-stream")
def chat_stream(req: Request):
# ✅ IMPORTANT : format chat propre
messages = [
{"role": "user", "content": req.message}
]
streamer = TextIteratorStreamer(
tokenizer,
skip_prompt=True,
skip_special_tokens=True
)
def generate():
model.generate(
**inputs,
max_new_tokens=200,
temperature=0.4,
top_p=0.9,
repetition_penalty=1.2,
do_sample=True,
streamer=streamer
)
thread = threading.Thread(target=generate)
thread.start()
def token_stream():
for text in streamer:
yield text
return StreamingResponse(token_stream(), media_type="text/plain")