Spaces:
Running on Zero
Running on Zero
File size: 5,908 Bytes
52ae9f5 4f4f61b 52ae9f5 33174d8 4f4f61b 7d94962 ab5e1e8 4f4f61b ab5e1e8 52ae9f5 ab5e1e8 2a5cfe7 ab5e1e8 52ae9f5 2a5cfe7 7d94962 ab5e1e8 2a5cfe7 7d94962 3dc5acc 5c2d8fb 2a5cfe7 4f4f61b 52ae9f5 4f4f61b 523047d 4f4f61b 52ae9f5 2a5cfe7 4f4f61b 52ae9f5 4f4f61b 52ae9f5 ab5e1e8 52ae9f5 ab5e1e8 4f4f61b 52ae9f5 c49b78d 3b32544 ab5e1e8 4f4f61b 2a5cfe7 4f4f61b 2a5cfe7 4f4f61b 523047d 4f4f61b 523047d 4f4f61b 523047d 4f4f61b 523047d 4f4f61b c49b78d 2a5cfe7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | import os
import time
import json
import uuid
import torch
import spaces
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from typing import List, Optional, Dict
from transformers import AutoTokenizer, TextIteratorStreamer
from awq import AutoAWQForCausalLM
from threading import Thread
import gradio as gr
MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct-AWQ"
# Cargar Tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
# Cargar Modelo AWQ
model = AutoAWQForCausalLM.from_quantized(
MODEL_ID,
fuse_layers=False,
trust_remote_code=True,
safetensors=True
)
# Esquemas para la API OpenAI
class ChatMessage(BaseModel):
role: str
content: str
class ChatCompletionRequest(BaseModel):
model: Optional[str] = MODEL_ID
messages: List[ChatMessage]
temperature: Optional[float] = 0.2
top_p: Optional[float] = 0.9
max_tokens: Optional[int] = 2048
stream: Optional[bool] = False
# Generaci贸n en GPU con ZeroGPU
@spaces.GPU(duration=120)
def generate_stream_tokens(messages_dict: List[Dict[str, str]], temperature: float, top_p: float, max_tokens: int):
text = tokenizer.apply_chat_template(
messages_dict,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
streamer = TextIteratorStreamer(
tokenizer,
timeout=60.0,
skip_prompt=True,
skip_special_tokens=True
)
generate_kwargs = dict(
model_inputs,
streamer=streamer,
max_new_tokens=max_tokens,
do_sample=temperature > 0.0,
temperature=max(temperature, 1e-2) if temperature > 0.0 else None,
top_p=top_p if temperature > 0.0 else None,
repetition_penalty=1.05
)
thread = Thread(target=model.generate, kwargs=generate_kwargs)
thread.start()
for new_token in streamer:
yield new_token
# Funciones de soporte para Gradio UI
def gradio_generate(message, history, system_prompt, temperature, top_p, max_tokens):
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
for user_msg, bot_msg in history:
messages.append({"role": "user", "content": user_msg})
if bot_msg:
messages.append({"role": "assistant", "content": bot_msg})
messages.append({"role": "user", "content": message})
partial_text = ""
for token in generate_stream_tokens(messages, temperature, top_p, int(max_tokens)):
partial_text += token
yield partial_text
# Definici贸n de la interfaz Gradio
with gr.Blocks(title="Qwen2.5-Coder-32B API & UI") as demo:
gr.Markdown("# 馃殌 Qwen2.5-Coder-32B-Instruct (AWQ en ZeroGPU)")
gr.Markdown("Compatible con OpenAI: `/v1/chat/completions` | Modelo: `Qwen/Qwen2.5-Coder-32B-Instruct-AWQ`")
gr.ChatInterface(
fn=gradio_generate,
additional_inputs=[
gr.Textbox("Eres un asistente de programaci贸n experto.", label="System Prompt"),
gr.Slider(0.0, 1.0, 0.2, step=0.05, label="Temperature"),
gr.Slider(0.1, 1.0, 0.9, step=0.05, label="Top-P"),
gr.Slider(256, 4096, 2048, step=256, label="Max New Tokens")
]
)
# Definici贸n de FastAPI y vinculaci贸n de endpoints a la app subyacente de Gradio
fastapi_app = demo.app
@fastapi_app.get("/v1/models")
async def list_models():
return {
"object": "list",
"data": [
{
"id": MODEL_ID,
"object": "model",
"created": int(time.time()),
"owned_by": "huggingface"
}
]
}
@fastapi_app.post("/v1/chat/completions")
async def chat_completions(req: ChatCompletionRequest):
req_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
created_time = int(time.time())
messages_dict = [{"role": m.role, "content": m.content} for m in req.messages]
if req.stream:
async def event_generator():
for token in generate_stream_tokens(
messages_dict,
temperature=req.temperature or 0.2,
top_p=req.top_p or 0.9,
max_tokens=req.max_tokens or 2048
):
chunk = {
"id": req_id,
"object": "chat.completion.chunk",
"created": created_time,
"model": req.model,
"choices": [{"index": 0, "delta": {"content": token}, "finish_reason": None}]
}
yield f"data: {json.dumps(chunk)}\n\n"
final_chunk = {
"id": req_id,
"object": "chat.completion.chunk",
"created": created_time,
"model": req.model,
"choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}]
}
yield f"data: {json.dumps(final_chunk)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")
full_content = ""
for token in generate_stream_tokens(
messages_dict,
temperature=req.temperature or 0.2,
top_p=req.top_p or 0.9,
max_tokens=req.max_tokens or 2048
):
full_content += token
return {
"id": req_id,
"object": "chat.completion",
"created": created_time,
"model": req.model,
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": full_content},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": -1, "completion_tokens": -1, "total_tokens": -1}
}
if __name__ == "__main__":
demo.queue().launch(server_name="0.0.0.0", server_port=7860) |