llama-coder / app.py
Valtry's picture
Create app.py
f1bab26 verified
Raw
History Blame Contribute Delete
5.91 kB
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from transformers import (
AutoTokenizer,
AutoModelForCausalLM,
TextIteratorStreamer
)
import torch
import uvicorn
import threading
import json
# =========================
# APP
# =========================
app = FastAPI()
stop_flags = {}
# =========================
# MODEL
# =========================
MODEL_ID = "Qwen/Qwen2.5-Coder-1.5B-Instruct"
print("🚀 Loading Fast Coder Model...")
device = torch.device(
"cuda" if torch.cuda.is_available() else "cpu"
)
torch.backends.cuda.matmul.allow_tf32 = True
torch.backends.cudnn.allow_tf32 = True
# =========================
# TOKENIZER
# =========================
tokenizer = AutoTokenizer.from_pretrained(
MODEL_ID,
trust_remote_code=True
)
# =========================
# MODEL
# =========================
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
trust_remote_code=True,
torch_dtype=torch.float16 if device.type == "cuda" else torch.float32
)
model = model.to(device)
model.eval()
print(f"✅ Loaded on {device}")
# =========================
# REQUEST
# =========================
class ChatRequest(BaseModel):
message: str
conversation_id: str
temperature: float = 0.1
# =========================
# SYSTEM PROMPT
# =========================
SYSTEM_PROMPT = """
You are a strict expert programming assistant.
CRITICAL RULES:
- Answer ONLY the user's latest request
- NEVER continue conversations
- NEVER generate extra examples unless asked
- NEVER explain unnecessarily
- NEVER repeat code
- NEVER simulate dialogue
- ALWAYS close markdown code blocks properly
- ALWAYS return complete executable code
- Stop immediately after final answer
CODE RULES:
- Use proper markdown
- Use ```language
- Keep formatting clean
- No duplicate code
- No unfinished code
"""
# =========================
# STOP WORDS
# =========================
STOP_WORDS = [
"<|im_end|>",
"<|endoftext|>",
"<|eot_id|>",
"User:",
"Assistant:",
"Human:"
]
# =========================
# CLEAN OUTPUT
# =========================
def clean_output(text):
for w in STOP_WORDS:
if w in text:
text = text.split(w)[0]
return text.strip()
# =========================
# BUILD INPUTS
# =========================
def build_inputs(message):
messages = [
{
"role": "system",
"content": SYSTEM_PROMPT
},
{
"role": "user",
"content": message
}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
return tokenizer(
text,
return_tensors="pt"
).to(device)
# =========================
# STOP ENDPOINT
# =========================
@app.post("/v1/stop")
def stop(data: dict):
stop_flags[data.get("conversation_id")] = True
return {
"status": "stopped"
}
# =========================
# NORMAL CHAT
# =========================
@app.post("/v1/chat")
def chat(req: ChatRequest):
inputs = build_inputs(req.message)
with torch.inference_mode():
output = model.generate(
**inputs,
max_new_tokens=512,
do_sample=False,
temperature=req.temperature,
top_p=1.0,
repetition_penalty=1.08,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id
)
result = tokenizer.decode(
output[0][inputs.input_ids.shape[1]:],
skip_special_tokens=True
)
result = clean_output(result)
return {
"response": result
}
# =========================
# STREAM CHAT
# =========================
@app.post("/v1/chat/stream")
def stream_chat(req: ChatRequest):
inputs = build_inputs(req.message)
streamer = TextIteratorStreamer(
tokenizer,
skip_prompt=True,
skip_special_tokens=True
)
generation_kwargs = dict(
**inputs,
streamer=streamer,
max_new_tokens=512,
do_sample=False,
temperature=req.temperature,
top_p=1.0,
repetition_penalty=1.08,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id
)
thread = threading.Thread(
target=model.generate,
kwargs=generation_kwargs
)
thread.start()
def generate():
full_text = ""
for token in streamer:
if stop_flags.get(req.conversation_id):
stop_flags[req.conversation_id] = False
break
if not token:
continue
stop_hit = False
for sw in STOP_WORDS:
if sw in token:
token = token.split(sw)[0]
stop_hit = True
break
if token:
full_text += token
# stop after completed markdown block
if full_text.count("```") >= 2:
yield f"data: {json.dumps({'choices':[{'delta':{'content': token}}]})}\n\n"
break
yield f"data: {json.dumps({'choices':[{'delta':{'content': token}}]})}\n\n"
if stop_hit:
break
full_text = clean_output(full_text)
yield "event: done\ndata: {}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
# =========================
# HEALTH
# =========================
@app.get("/")
def root():
return {
"status": "Fast Coder Running 🚀"
}
# =========================
# RUN
# =========================
if __name__ == "__main__":
uvicorn.run(
"app:app",
host="0.0.0.0",
port=7860
)