acsaco commited on
Commit
5c2d8fb
路
verified 路
1 Parent(s): ec47e4c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -56
app.py CHANGED
@@ -1,61 +1,100 @@
1
  import os
2
- import subprocess
3
  import time
4
- import requests
5
  import gradio as gr
6
- from fastapi import FastAPI, Request
7
- from fastapi.responses import StreamingResponse
 
 
 
8
  # Configuraci贸n del modelo
9
- MODEL_ID = os.getenv("MODEL_ID", "Qwen/Qwen3.8-27B")
10
- VLLM_PORT = 8001
11
- print(f"Iniciando vLLM en segundo plano con el modelo: {MODEL_ID}...")
12
- # 1. Ejecutar el servidor de vLLM en segundo plano en el puerto 8001
13
- vllm_cmd = [
14
- "python3", "-m", "vllm.entrypoints.openai.api_server",
15
- "--model", MODEL_ID,
16
- "--port", str(VLLM_PORT),
17
- "--host", "127.0.0.1",
18
- "--trust-remote-code",
19
- "--max-model-len", "8192",
20
- "--gpu-memory-utilization", "0.95"
21
- ]
22
- # Si el modelo est谩 cuantizado (ej. AWQ), puedes a帽adir la opci贸n:
23
- # vllm_cmd.extend(["--quantization", "awq"])
24
- process = subprocess.Popen(vllm_cmd)
25
- # 2. Inicializar la app FastAPI
26
- app = FastAPI(title="Qwen OpenAI API Proxy")
27
- # Redirigir todas las peticiones a /v1 directamente hacia vLLM
28
- @app.api_route("/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
29
- async def proxy_v1(request: Request, path: str):
30
- url = f"http://127.0.0.1:{VLLM_PORT}/v1/{path}"
31
- body = await request.body()
32
- headers = {k: v for k, v in request.headers.items() if k.lower() != "host"}
33
- # Manejar respuestas en streaming para OpenCode
34
- resp = requests.request(
35
- method=request.method,
36
- url=url,
37
- headers=headers,
38
- data=body,
39
- stream=True
40
- )
41
- return StreamingResponse(
42
- resp.iter_content(chunk_size=1024),
43
- status_code=resp.status_code,
44
- headers=dict(resp.headers)
45
- )
46
- # 3. Interfaz visual con Gradio
47
- with gr.Blocks(title="Qwen OpenCode API Endpoint") as demo:
48
- gr.Markdown("# 馃殌 Servidor Qwen Activo")
49
- gr.Markdown(f"**Modelo cargado:** `{MODEL_ID}`")
50
- gr.Markdown("""
51
- ### 馃摗 Configuraci贸n para OpenCode
52
- Copia la siguiente **Base URL** en la configuraci贸n de OpenCode:
53
- """)
54
- gr.Code("https://https://huggingface.co/spaces/acsaco.hf.space/v1", language="bash")
55
- gr.Markdown("""
56
- * **API Key:** `dummy` (si el Space es p煤blico) o tu `HF_TOKEN` (si el Spac
57
- * **Model Name:** El mismo ID cargado en el servidor (`Qwen/Qwen3.8-27B
58
- """)
59
-
60
- # Montar Gradio en el path ra铆z de FastAPI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  app = gr.mount_gradio_app(app, demo, path="/")
 
1
  import os
2
+ import json
3
  import time
4
+ from typing import List, Optional
5
  import gradio as gr
6
+ from fastapi import FastAPI, Request, HTTPException
7
+ from fastapi.responses import StreamingResponse, JSONResponse
8
+ from pydantic import BaseModel
9
+ from huggingface_hub import InferenceClient
10
+
11
  # Configuraci贸n del modelo
12
+ MODEL_ID = "Qwen/Qwen3.8-27B" # Cambiar al modelo deseado
13
+ HF_TOKEN = os.getenv("HF_TOKEN")
14
+
15
+ client = InferenceClient(model=MODEL_ID, token=HF_TOKEN)
16
+ app = FastAPI(title="OpenAI Compatible HF Space API")
17
+
18
+ # --- Esquemas Pydantic para OpenAI API ---
19
+ class ChatMessage(BaseModel):
20
+ role: str
21
+ content: str
22
+
23
+ class ChatCompletionRequest(BaseModel):
24
+ model: Optional[str] = MODEL_ID
25
+ messages: List[ChatMessage]
26
+ temperature: Optional[float] = 0.7
27
+ max_tokens: Optional[int] = 2048
28
+ stream: Optional[bool] = False
29
+
30
+ # --- Endpoints OpenAI ---
31
+ @app.get("/v1/models")
32
+ async def list_models():
33
+ return {
34
+ "object": "list",
35
+ "data": [{"id": MODEL_ID, "object": "model", "owned_by": "huggingface"}]
36
+ }
37
+
38
+ @app.post("/v1/chat/completions")
39
+ async def chat_completions(req: ChatCompletionRequest):
40
+ formatted_messages = [{"role": m.role, "content": m.content} for m in req.messages]
41
+
42
+ if req.stream:
43
+ async def stream_generator():
44
+ stream = client.chat_completion(
45
+ messages=formatted_messages,
46
+ temperature=req.temperature,
47
+ max_tokens=req.max_tokens,
48
+ stream=True
49
+ )
50
+ for chunk in stream:
51
+ delta = chunk.choices[0].delta.content or ""
52
+ payload = {
53
+ "id": f"chatcmpl-{int(time.time())}",
54
+ "object": "chat.completion.chunk",
55
+ "created": int(time.time()),
56
+ "model": MODEL_ID,
57
+ "choices": [{"index": 0, "delta": {"content": delta}, "finish_reason": None}]
58
+ }
59
+ yield f"data: {json.dumps(payload)}\n\n"
60
+ yield "data: [DONE]\n\n"
61
+
62
+ return StreamingResponse(stream_generator(), media_type="text/event-stream")
63
+ else:
64
+ response = client.chat_completion(
65
+ messages=formatted_messages,
66
+ temperature=req.temperature,
67
+ max_tokens=req.max_tokens,
68
+ stream=False
69
+ )
70
+ return {
71
+ "id": f"chatcmpl-{int(time.time())}",
72
+ "object": "chat.completion",
73
+ "created": int(time.time()),
74
+ "model": MODEL_ID,
75
+ "choices": [{
76
+ "index": 0,
77
+ "message": {"role": "assistant", "content": response.choices[0].message.content},
78
+ "finish_reason": "stop"
79
+ }]
80
+ }
81
+
82
+ # --- Interfaz Web Gradio ---
83
+ def gradio_chat(message, history):
84
+ messages = []
85
+ for user_msg, bot_msg in history:
86
+ messages.append({"role": "user", "content": user_msg})
87
+ messages.append({"role": "assistant", "content": bot_msg})
88
+ messages.append({"role": "user", "content": message})
89
+
90
+ response = ""
91
+ for chunk in client.chat_completion(messages=messages, stream=True, max_tokens=2048):
92
+ response += chunk.choices[0].delta.content or ""
93
+ yield response
94
+
95
+ with gr.Blocks(title="AI Chat & API Hub") as demo:
96
+ gr.Markdown(f"# 馃 Interfaz de Chat & API\n**Modelo Activo:** `{MODEL_ID}`\n\nCon茅ctate desde Cursor/OpenCode usando:\n`https:huggingface.co/spaces/acsaco.hf.space/v1`")
97
+ gr.ChatInterface(fn=gradio_chat)
98
+
99
+ # Montar Gradio dentro de FastAPI
100
  app = gr.mount_gradio_app(app, demo, path="/")