Davizig10jojo commited on
Commit
08e6d5c
·
verified ·
1 Parent(s): 57b2954

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -119
app.py CHANGED
@@ -2,13 +2,11 @@ import os
2
  import sys
3
  import logging
4
 
5
- # Suprime warnings de asyncio e gradio
6
  logging.getLogger("asyncio").setLevel(logging.CRITICAL)
7
  logging.getLogger("gradio").setLevel(logging.ERROR)
8
 
9
- # ==============================================================================
10
- # 1. CONFIGURAÇÃO DE AMBIENTE CUDA (ZeroGPU)
11
- # ==============================================================================
12
  cuda_paths = [
13
  "/usr/local/cuda/lib64",
14
  "/usr/local/nvidia/lib64",
@@ -16,17 +14,13 @@ cuda_paths = [
16
  os.path.join(sys.prefix, "lib", f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages", "nvidia", "cuda_runtime", "lib"),
17
  os.path.join(sys.prefix, "lib", f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages", "nvidia", "cublas", "lib"),
18
  ]
19
-
20
  existing_ld = os.environ.get("LD_LIBRARY_PATH", "")
21
  new_paths = [p for p in cuda_paths if os.path.exists(p)]
22
  os.environ["LD_LIBRARY_PATH"] = ":".join(new_paths + [existing_ld])
23
-
24
  os.environ["GRADIO_SSR_MODE"] = "False"
25
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
26
 
27
- # ==============================================================================
28
- # 2. IMPORTAÇÕES GLOBAIS
29
- # ==============================================================================
30
  import threading
31
  import uvicorn
32
  import time
@@ -36,7 +30,7 @@ import gc
36
  import gradio as gr
37
  from fastapi import FastAPI, HTTPException
38
  from fastapi.middleware.cors import CORSMiddleware
39
- from fastapi.responses import StreamingResponse, JSONResponse
40
  from pydantic import BaseModel
41
  from typing import List, Optional
42
  from pyngrok import ngrok
@@ -46,55 +40,26 @@ import spaces
46
  NGROK_TOKEN = os.getenv("NGROK_TOKEN")
47
 
48
  MODEL_REGISTRY = {
49
- "qwen2.5-coder-7b": {
50
- "repo_id": "Davizig10jojo/Qwen2.5-Coder-Mix-7B-GGUF",
51
- "filename": "Qwen2.5-Coder-Mix-7B-Q2_K.gguf",
52
- "min_size_mb": 1000
53
- },
54
- "blazernano-0.6b": {
55
- "repo_id": "Davizig10jojo/BlazerNano-0.6b-GGUF",
56
- "filename": "blazernano-0.6b-Q6_K.gguf",
57
- "min_size_mb": 100
58
- },
59
- "blazertiny-1b": {
60
- "repo_id": "Davizig10jojo/BlazerTiny-1b-GGUF",
61
- "filename": "blazertiny-1b-Q6_K.gguf",
62
- "min_size_mb": 200
63
- },
64
- "blazerstandard-4b": {
65
- "repo_id": "Davizig10jojo/BlazerStandard-4B-GGUF",
66
- "filename": "blazerstandard-4b-Q6_K.gguf",
67
- "min_size_mb": 2000
68
- },
69
- "blazerrhino-3b": {
70
- "repo_id": "Davizig10jojo/BlazerRhino-3B-GGUF",
71
- "filename": "BlazerRhino-3B-Instruct.Q4_K_M.gguf",
72
- "min_size_mb": 1000
73
- }
74
  }
75
 
76
  print("📥 Mapeando caminhos dos arquivos locais...")
77
  MODEL_PATHS = {}
78
-
79
  for key, meta in MODEL_REGISTRY.items():
80
  try:
81
  path = hf_hub_download(repo_id=meta["repo_id"], filename=meta["filename"])
82
- size_mb = os.path.getsize(path) / (1024 * 1024)
83
- if size_mb < meta["min_size_mb"]:
84
- raise Exception(f"Arquivo muito pequeno ({size_mb:.2f}MB).")
85
  MODEL_PATHS[key] = path
86
- print(f"📦 Arquivo pronto: {key} ({size_mb:.2f} MB)")
87
  except Exception as e:
88
  print(f"⚠️ Erro ao baixar {key}: {e}")
89
 
90
  api_app = FastAPI(title="Blazer GPU Engine")
91
- api_app.add_middleware(
92
- CORSMiddleware,
93
- allow_origins=["*"],
94
- allow_credentials=True,
95
- allow_methods=["*"],
96
- allow_headers=["*"],
97
- )
98
 
99
  class ChatMessage(BaseModel):
100
  role: str
@@ -108,28 +73,15 @@ class ChatCompletionRequest(BaseModel):
108
  stream: Optional[bool] = True
109
 
110
  @spaces.GPU(duration=1)
111
- def check_hf():
112
- return True
113
-
114
- # Healthcheck para manter o Ngrok vivo
115
- @api_app.get("/health")
116
- def healthcheck():
117
- return {"status": "ok"}
118
 
119
- # ==============================================================================
120
- # 3. FUNÇÃO DE STREAMING OTIMIZADA PARA QWEN/BLAZER
121
- # ==============================================================================
122
- @spaces.GPU(duration=120) # Aumentado para 120s para evitar timeout em códigos longos
123
  def stream_generator(model_id: str, prompt_formatado: str, max_tokens: int, temperature: float):
124
- # LAZY LOADING: Importa apenas quando a GPU já está alocada
125
  from llama_cpp import Llama
126
 
127
  if model_id not in MODEL_PATHS:
128
- fallback_model = "blazertiny-1b"
129
- if fallback_model in MODEL_PATHS:
130
- model_id = fallback_model
131
- else:
132
- raise ValueError("Nenhum modelo disponível.")
133
 
134
  print(f"💻 Executando inferência via GPU (ZeroGPU) para: {model_id}")
135
 
@@ -139,13 +91,12 @@ def stream_generator(model_id: str, prompt_formatado: str, max_tokens: int, temp
139
  model_path=MODEL_PATHS[model_id],
140
  n_ctx=1024,
141
  n_threads=2,
142
- n_gpu_layers=-1, # Todas as camadas na GPU
143
  verbose=False,
144
- use_mmap=True, # Otimização de memória
145
- use_mlock=False
146
  )
147
 
148
- # Paradas específicas para Qwen/CoT
149
  stop_sequences = ["<|im_end|>", "</think>", "User:", "Assistant:"]
150
 
151
  response_stream = llm(
@@ -162,98 +113,66 @@ def stream_generator(model_id: str, prompt_formatado: str, max_tokens: int, temp
162
  chunk_id = f"chatcmpl-{int(time.time())}"
163
  for chunk in response_stream:
164
  token = chunk["choices"][0]["text"]
165
- if token:
166
- # Filtra tokens de pensamento
167
- if "</think>" in token or "<think>" in token:
168
- continue
169
-
170
  data = {
171
- "id": chunk_id,
172
- "object": "chat.completion.chunk",
173
- "created": int(time.time()),
174
- "model": model_id,
175
- "choices": [{
176
- "index": 0,
177
- "delta": {"content": token},
178
- "finish_reason": None
179
- }]
180
  }
181
  yield f"data: {json.dumps(data)}\n"
182
 
183
- fim = {
184
- "id": chunk_id,
185
- "object": "chat.completion.chunk",
186
- "created": int(time.time()),
187
- "model": model_id,
188
- "choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}]
189
- }
190
- yield f"data: {json.dumps(fim)}\n"
191
  yield "data: [DONE]\n"
192
 
193
  except Exception as e:
194
- print(f"🔴 Erro Crítico no Worker: {e}")
195
- print(traceback.format_exc())
196
  raise RuntimeError(str(e))
197
  finally:
198
- if llm:
199
- del llm
200
  gc.collect()
201
- # Força liberação de memória CUDA
202
- import torch
203
- if torch.cuda.is_available():
204
- torch.cuda.empty_cache()
 
205
 
206
  @api_app.post("/v1/chat/completions")
207
  async def chat_completions(request: ChatCompletionRequest):
208
  try:
209
- # Template Qwen Oficial
210
- system_prompt = "You are Blazer, a helpful coding assistant. Answer directly and concisely. Do not show your thinking process."
211
-
212
  prompt_formatado = f"<|im_start|>system\n{system_prompt}<|im_end|>\n"
213
 
214
  for msg in request.messages:
215
  role = msg.role.lower() if msg.role else "user"
216
- content = msg.content.strip()
217
- prompt_formatado += f"<|im_start|>{role}\n{content}<|im_end|>\n"
218
 
219
  prompt_formatado += "<|im_start|>assistant\n"
220
 
221
  return StreamingResponse(
222
- stream_generator(
223
- model_id=request.model,
224
- prompt_formatado=prompt_formatado,
225
- max_tokens=request.max_tokens,
226
- temperature=request.temperature
227
- ),
228
  media_type="text/event-stream"
229
  )
230
  except Exception as e:
231
- print(f"🔴 ERRO NA API: {e}")
232
  raise HTTPException(status_code=500, detail=str(e))
233
 
234
  @api_app.get("/v1/models")
235
  async def listar_modelos():
236
- opcoes = [{"id": chave, "object": "model", "created": 1677652288, "owned_by": "user"} for chave in MODEL_PATHS.keys()]
237
- return {"object": "list", "data": opcoes}
238
 
239
  def run_fastapi():
240
  uvicorn.run(api_app, host="127.0.0.1", port=8000, log_level="warning")
241
 
242
  def iniciar_ngrok():
243
- if not NGROK_TOKEN:
244
- print("⚠️ NGROK_TOKEN ausente.")
245
- return
246
  time.sleep(15)
247
  ngrok.set_auth_token(NGROK_TOKEN)
248
  for tentativa in range(5):
249
  try:
250
- ngrok.kill()
251
- time.sleep(3)
252
  public_url = ngrok.connect(8000, proto="http", bind_tls=True)
253
  print(f"\n🔗 URL POCKETPAL: {public_url.public_url}\n")
254
  return
255
  except Exception as e:
256
- print(f"⚠️ Falha Ngrok {tentativa + 1}: {e}")
257
  time.sleep(10)
258
 
259
  with gr.Blocks() as demo:
@@ -262,7 +181,6 @@ with gr.Blocks() as demo:
262
  if __name__ == "__main__":
263
  try: check_hf()
264
  except: pass
265
-
266
  threading.Thread(target=run_fastapi, daemon=True).start()
267
  threading.Thread(target=iniciar_ngrok, daemon=True).start()
268
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
2
  import sys
3
  import logging
4
 
5
+ # 1. SUPRESSÃO DE RUÍDO NOS LOGS
6
  logging.getLogger("asyncio").setLevel(logging.CRITICAL)
7
  logging.getLogger("gradio").setLevel(logging.ERROR)
8
 
9
+ # 2. CONFIGURAÇÃO CUDA ZERO-GPU
 
 
10
  cuda_paths = [
11
  "/usr/local/cuda/lib64",
12
  "/usr/local/nvidia/lib64",
 
14
  os.path.join(sys.prefix, "lib", f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages", "nvidia", "cuda_runtime", "lib"),
15
  os.path.join(sys.prefix, "lib", f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages", "nvidia", "cublas", "lib"),
16
  ]
 
17
  existing_ld = os.environ.get("LD_LIBRARY_PATH", "")
18
  new_paths = [p for p in cuda_paths if os.path.exists(p)]
19
  os.environ["LD_LIBRARY_PATH"] = ":".join(new_paths + [existing_ld])
 
20
  os.environ["GRADIO_SSR_MODE"] = "False"
21
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
22
 
23
+ # 3. IMPORTAÇÕES
 
 
24
  import threading
25
  import uvicorn
26
  import time
 
30
  import gradio as gr
31
  from fastapi import FastAPI, HTTPException
32
  from fastapi.middleware.cors import CORSMiddleware
33
+ from fastapi.responses import StreamingResponse
34
  from pydantic import BaseModel
35
  from typing import List, Optional
36
  from pyngrok import ngrok
 
40
  NGROK_TOKEN = os.getenv("NGROK_TOKEN")
41
 
42
  MODEL_REGISTRY = {
43
+ "qwen2.5-coder-7b": {"repo_id": "Davizig10jojo/Qwen2.5-Coder-Mix-7B-GGUF", "filename": "Qwen2.5-Coder-Mix-7B-Q2_K.gguf", "min_size_mb": 1000},
44
+ "blazernano-0.6b": {"repo_id": "Davizig10jojo/BlazerNano-0.6b-GGUF", "filename": "blazernano-0.6b-Q6_K.gguf", "min_size_mb": 100},
45
+ "blazertiny-1b": {"repo_id": "Davizig10jojo/BlazerTiny-1b-GGUF", "filename": "blazertiny-1b-Q6_K.gguf", "min_size_mb": 200},
46
+ "blazerstandard-4b": {"repo_id": "Davizig10jojo/BlazerStandard-4B-GGUF", "filename": "blazerstandard-4b-Q6_K.gguf", "min_size_mb": 2000},
47
+ "blazerrhino-3b": {"repo_id": "Davizig10jojo/BlazerRhino-3B-GGUF", "filename": "BlazerRhino-3B-Instruct.Q4_K_M.gguf", "min_size_mb": 1000}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  print("📥 Mapeando caminhos dos arquivos locais...")
51
  MODEL_PATHS = {}
 
52
  for key, meta in MODEL_REGISTRY.items():
53
  try:
54
  path = hf_hub_download(repo_id=meta["repo_id"], filename=meta["filename"])
55
+ if os.path.getsize(path) / (1024 * 1024) < meta["min_size_mb"]: raise Exception("Arquivo corrompido")
 
 
56
  MODEL_PATHS[key] = path
57
+ print(f"📦 Arquivo pronto: {key}")
58
  except Exception as e:
59
  print(f"⚠️ Erro ao baixar {key}: {e}")
60
 
61
  api_app = FastAPI(title="Blazer GPU Engine")
62
+ api_app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
 
 
 
 
 
 
63
 
64
  class ChatMessage(BaseModel):
65
  role: str
 
73
  stream: Optional[bool] = True
74
 
75
  @spaces.GPU(duration=1)
76
+ def check_hf(): return True
 
 
 
 
 
 
77
 
78
+ # 4. STREAMING COM TIMEOUT ESTENDIDO E LIMPEZA DE VRAM
79
+ @spaces.GPU(duration=120)
 
 
80
  def stream_generator(model_id: str, prompt_formatado: str, max_tokens: int, temperature: float):
 
81
  from llama_cpp import Llama
82
 
83
  if model_id not in MODEL_PATHS:
84
+ model_id = "blazertiny-1b"
 
 
 
 
85
 
86
  print(f"💻 Executando inferência via GPU (ZeroGPU) para: {model_id}")
87
 
 
91
  model_path=MODEL_PATHS[model_id],
92
  n_ctx=1024,
93
  n_threads=2,
94
+ n_gpu_layers=-1,
95
  verbose=False,
96
+ use_mmap=True
 
97
  )
98
 
99
+ # Template Qwen Oficial + Stop Sequences para evitar vazamento de pensamento
100
  stop_sequences = ["<|im_end|>", "</think>", "User:", "Assistant:"]
101
 
102
  response_stream = llm(
 
113
  chunk_id = f"chatcmpl-{int(time.time())}"
114
  for chunk in response_stream:
115
  token = chunk["choices"][0]["text"]
116
+ if token and "</think>" not in token:
 
 
 
 
117
  data = {
118
+ "id": chunk_id, "object": "chat.completion.chunk", "created": int(time.time()),
119
+ "model": model_id, "choices": [{"index": 0, "delta": {"content": token}, "finish_reason": None}]
 
 
 
 
 
 
 
120
  }
121
  yield f"data: {json.dumps(data)}\n"
122
 
123
+ yield f"data: {json.dumps({'id': chunk_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': model_id, 'choices': [{'index': 0, 'delta': {}, 'finish_reason': 'stop'}]})}\n"
 
 
 
 
 
 
 
124
  yield "data: [DONE]\n"
125
 
126
  except Exception as e:
127
+ print(f"🔴 Erro Crítico: {e}")
 
128
  raise RuntimeError(str(e))
129
  finally:
130
+ if llm: del llm
 
131
  gc.collect()
132
+ # Limpeza extra de VRAM
133
+ try:
134
+ import torch
135
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
136
+ except: pass
137
 
138
  @api_app.post("/v1/chat/completions")
139
  async def chat_completions(request: ChatCompletionRequest):
140
  try:
141
+ # System Prompt direto para evitar recusas ou alucinações
142
+ system_prompt = "You are Blazer, a helpful assistant. Answer directly and concisely."
 
143
  prompt_formatado = f"<|im_start|>system\n{system_prompt}<|im_end|>\n"
144
 
145
  for msg in request.messages:
146
  role = msg.role.lower() if msg.role else "user"
147
+ prompt_formatado += f"<|im_start|>{role}\n{msg.content.strip()}<|im_end|>\n"
 
148
 
149
  prompt_formatado += "<|im_start|>assistant\n"
150
 
151
  return StreamingResponse(
152
+ stream_generator(model_id=request.model, prompt_formatado=prompt_formatado, max_tokens=request.max_tokens, temperature=request.temperature),
 
 
 
 
 
153
  media_type="text/event-stream"
154
  )
155
  except Exception as e:
 
156
  raise HTTPException(status_code=500, detail=str(e))
157
 
158
  @api_app.get("/v1/models")
159
  async def listar_modelos():
160
+ return {"object": "list", "data": [{"id": k, "object": "model", "created": 1677652288, "owned_by": "user"} for k in MODEL_PATHS.keys()]}
 
161
 
162
  def run_fastapi():
163
  uvicorn.run(api_app, host="127.0.0.1", port=8000, log_level="warning")
164
 
165
  def iniciar_ngrok():
166
+ if not NGROK_TOKEN: return
 
 
167
  time.sleep(15)
168
  ngrok.set_auth_token(NGROK_TOKEN)
169
  for tentativa in range(5):
170
  try:
171
+ ngrok.kill(); time.sleep(3)
 
172
  public_url = ngrok.connect(8000, proto="http", bind_tls=True)
173
  print(f"\n🔗 URL POCKETPAL: {public_url.public_url}\n")
174
  return
175
  except Exception as e:
 
176
  time.sleep(10)
177
 
178
  with gr.Blocks() as demo:
 
181
  if __name__ == "__main__":
182
  try: check_hf()
183
  except: pass
 
184
  threading.Thread(target=run_fastapi, daemon=True).start()
185
  threading.Thread(target=iniciar_ngrok, daemon=True).start()
186
  demo.launch(server_name="0.0.0.0", server_port=7860)