gemma4 / app.py
suli12138's picture
Upload 3 files
9e7a01c verified
Raw
History Blame Contribute Delete
2.28 kB
import spaces
import torch
from fastapi import HTTPException
from gradio import Server
from loguru import logger
from pydantic import BaseModel
from typing import List, Optional
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL_NAME = "TrevorJS/gemma-4-E4B-it-uncensored"
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = None
class ChatMessage(BaseModel):
role: str
content: str
class ChatCompletionRequest(BaseModel):
model: str
messages: List[ChatMessage]
temperature: Optional[float] = 0.7
max_tokens: Optional[int] = 512
@spaces.GPU
def run_inference(prompt: str, max_tokens: int = 512, temperature: float = 0.7) -> str:
global model
if model is None:
logger.info(f"Loading model {MODEL_NAME}...")
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME, device_map="auto", torch_dtype=torch.bfloat16
)
logger.info("Model loaded")
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_tokens,
temperature=temperature,
do_sample=temperature > 0
)
generated = outputs[0][inputs.input_ids.shape[-1]:]
return tokenizer.decode(generated, skip_special_tokens=True)
app = Server()
@app.get("/")
def root():
return {"message": "Gemma 4 E4B Uncensored API is running"}
@app.post("/v1/chat/completions")
async def chat_completions(request: ChatCompletionRequest):
try:
messages = [{"role": m.role, "content": m.content} for m in request.messages]
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
response = run_inference(prompt, request.max_tokens, request.temperature)
return {
"id": "chatcmpl-zerogpu",
"object": "chat.completion",
"model": request.model,
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": response},
"finish_reason": "stop"
}]
}
except Exception as e:
logger.error(f"Error: {e}")
raise HTTPException(status_code=500, detail=str(e))
app.launch()