smartdigitalsolutions commited on
Commit
09f0413
·
verified ·
1 Parent(s): 57a2fcf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +14 -71
app.py CHANGED
@@ -14,12 +14,12 @@ import spaces
14
  model = None
15
  status_message = "Modello non ancora caricato"
16
  MODEL_PATH = "TheBloke/Mistral-7B-Instruct-v0.2-GGUF"
17
- MODEL_FILE = "mistral-7b-instruct-v0.2.Q4_K_M.gguf" # Versione quantizzata per risparmiare memoria
18
  MODEL_TYPE = "mistral"
19
  MAX_NEW_TOKENS = 2048
20
- MODEL_LOCK = Lock() # Per evitare richieste contemporanee che potrebbero causare OOM
21
 
22
- # Definizioni dei modelli di dati (Pydantic)
23
  class Message(BaseModel):
24
  role: str
25
  content: str
@@ -41,24 +41,16 @@ class CompletionResponse(BaseModel):
41
  choices: List[Dict[str, Any]]
42
  usage: Dict[str, int]
43
 
44
- # Funzioni di utilità
45
  def format_chat_prompt(messages: List[Message]) -> str:
46
- """Formatta i messaggi nel formato atteso da Mistral Instruct."""
47
  conversation = []
48
-
49
  for message in messages:
50
- if message.role == "system":
51
- # Inserisce il messaggio di sistema come istruzione iniziale
52
- conversation.append(f"<s>[INST] {message.content} [/INST]</s>")
53
- elif message.role == "user":
54
  conversation.append(f"<s>[INST] {message.content} [/INST]</s>")
55
  elif message.role == "assistant":
56
  conversation.append(f"<s>{message.content}</s>")
57
-
58
  return "".join(conversation)
59
 
60
  def load_model():
61
- """Carica il modello Mistral quantizzato."""
62
  global model, status_message
63
  try:
64
  status_message = "Caricamento modello in corso..."
@@ -67,7 +59,7 @@ def load_model():
67
  model_file=MODEL_FILE,
68
  model_type=MODEL_TYPE,
69
  context_length=4096,
70
- threads=4 # Usa 4 thread per lasciare risorse al sistema
71
  )
72
  status_message = "Modello caricato con successo"
73
  return True
@@ -76,14 +68,11 @@ def load_model():
76
  return False
77
 
78
  def generate_response(prompt, temperature=0.7, top_p=0.95, max_tokens=MAX_NEW_TOKENS):
79
- """Genera una risposta dal modello."""
80
  global model, status_message
81
-
82
  if model is None:
83
  if not load_model():
84
  return status_message
85
-
86
- with MODEL_LOCK: # Previene richieste parallele che potrebbero causare OOM
87
  try:
88
  result = model(
89
  prompt,
@@ -103,75 +92,43 @@ def generate_with_timing(text, temp, max_tok):
103
  end_time = time.time()
104
  return result, f"{end_time - start_time:.2f} secondi"
105
 
106
- # Creazione dell'interfaccia Gradio
107
  def create_gradio_interface():
108
  with gr.Blocks(title="Mistral API") as interface:
109
  gr.Markdown("# Mistral-7B API Server")
110
-
111
  with gr.Row():
112
  with gr.Column():
113
  status = gr.Textbox(value=lambda: status_message, label="Stato del modello", interactive=False)
114
  load_button = gr.Button("Carica Modello")
115
  load_button.click(load_model, inputs=[], outputs=[])
116
-
117
  with gr.Row():
118
  with gr.Column():
119
- input_text = gr.Textbox(
120
- lines=5,
121
- label="Input",
122
- placeholder="Inserisci il tuo messaggio qui..."
123
- )
124
-
125
  with gr.Row():
126
- temp_slider = gr.Slider(
127
- minimum=0.1,
128
- maximum=1.0,
129
- value=0.7,
130
- step=0.1,
131
- label="Temperatura"
132
- )
133
-
134
- max_token_slider = gr.Slider(
135
- minimum=100,
136
- maximum=MAX_NEW_TOKENS,
137
- value=1024,
138
- step=100,
139
- label="Max Token"
140
- )
141
-
142
  submit_button = gr.Button("Genera")
143
-
144
  with gr.Column():
145
  output_text = gr.Textbox(lines=12, label="Risposta del modello")
146
-
147
  gen_time = gr.Textbox(label="Tempo di generazione", interactive=False)
148
-
149
  submit_button.click(
150
  generate_with_timing,
151
  inputs=[input_text, temp_slider, max_token_slider],
152
  outputs=[output_text, gen_time]
153
  )
154
-
155
  gr.Markdown("""
156
  ## API Endpoint
157
  Questa applicazione espone un endpoint API compatibile con OpenAI:
158
  - `/v1/chat/completions` - Per richieste di completamento chat
159
  - `/status` - Per verificare lo stato del modello
160
-
161
- L'endpoint è accessibile dall'URL di questo Hugging Face Space.
162
  """)
163
-
164
  return interface
165
 
166
- # Decorator per richiedere la GPU dallo space
167
  @spaces.GPU
168
  def get_gpu():
169
  return "GPU allocata con successo"
170
 
171
- # Crea l'applicazione FastAPI
172
  app = FastAPI()
173
 
174
- # Configura CORS
175
  app.add_middleware(
176
  CORSMiddleware,
177
  allow_origins=["*"],
@@ -180,14 +137,11 @@ app.add_middleware(
180
  allow_headers=["*"],
181
  )
182
 
183
- # API endpoint compatibile con OpenAI
184
  @app.post("/v1/chat/completions", response_model=CompletionResponse)
185
  async def create_completion(request: CompletionRequest):
186
  try:
187
  prompt = format_chat_prompt(request.messages)
188
-
189
- max_tokens = min(request.max_tokens, MAX_NEW_TOKENS) # Limita i token per evitare OOM
190
-
191
  start_time = time.time()
192
  completion_text = generate_response(
193
  prompt,
@@ -196,11 +150,8 @@ async def create_completion(request: CompletionRequest):
196
  max_tokens=max_tokens
197
  )
198
  end_time = time.time()
199
-
200
- # Calcola il numero di token (approssimativo)
201
  input_tokens = len(prompt.split())
202
  output_tokens = len(completion_text.split())
203
-
204
  response = {
205
  "id": f"chatcmpl-{os.urandom(4).hex()}",
206
  "object": "chat.completion",
@@ -222,31 +173,23 @@ async def create_completion(request: CompletionRequest):
222
  "total_tokens": input_tokens + output_tokens,
223
  }
224
  }
225
-
226
  return response
227
  except Exception as e:
228
  raise HTTPException(status_code=500, detail=str(e))
229
 
230
- # API endpoint per verificare lo stato del modello
231
  @app.get("/status")
232
  async def get_status():
233
  return {"status": status_message, "model": MODEL_PATH}
234
 
235
- # Crea l'interfaccia Gradio
236
- demo = create_gradio_interface()
237
-
238
- # Monta Gradio su FastAPI usando il metodo corretto per Gradio 4
239
- app = gr.mount_gradio_app(app, demo, path="/gradio")
240
 
241
- # Precarica il modello all'avvio (usando il nuovo metodo lifespan invece di on_event)
242
  @app.on_event("startup")
243
  async def startup_load_model():
244
- # Assicurati che la GPU sia allocata prima di caricare il modello
245
  get_gpu()
246
  load_model()
247
 
248
- # Per Hugging Face Spaces, assicurati che l'app sia esportata correttamente
249
  if __name__ == "__main__":
250
  import uvicorn
251
- # Usa la porta 7860 che è quella standard per Hugging Face Spaces
252
- uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")
 
14
  model = None
15
  status_message = "Modello non ancora caricato"
16
  MODEL_PATH = "TheBloke/Mistral-7B-Instruct-v0.2-GGUF"
17
+ MODEL_FILE = "mistral-7b-instruct-v0.2.Q4_K_M.gguf"
18
  MODEL_TYPE = "mistral"
19
  MAX_NEW_TOKENS = 2048
20
+ MODEL_LOCK = Lock()
21
 
22
+ # Pydantic models
23
  class Message(BaseModel):
24
  role: str
25
  content: str
 
41
  choices: List[Dict[str, Any]]
42
  usage: Dict[str, int]
43
 
 
44
  def format_chat_prompt(messages: List[Message]) -> str:
 
45
  conversation = []
 
46
  for message in messages:
47
+ if message.role == "system" or message.role == "user":
 
 
 
48
  conversation.append(f"<s>[INST] {message.content} [/INST]</s>")
49
  elif message.role == "assistant":
50
  conversation.append(f"<s>{message.content}</s>")
 
51
  return "".join(conversation)
52
 
53
  def load_model():
 
54
  global model, status_message
55
  try:
56
  status_message = "Caricamento modello in corso..."
 
59
  model_file=MODEL_FILE,
60
  model_type=MODEL_TYPE,
61
  context_length=4096,
62
+ threads=4
63
  )
64
  status_message = "Modello caricato con successo"
65
  return True
 
68
  return False
69
 
70
  def generate_response(prompt, temperature=0.7, top_p=0.95, max_tokens=MAX_NEW_TOKENS):
 
71
  global model, status_message
 
72
  if model is None:
73
  if not load_model():
74
  return status_message
75
+ with MODEL_LOCK:
 
76
  try:
77
  result = model(
78
  prompt,
 
92
  end_time = time.time()
93
  return result, f"{end_time - start_time:.2f} secondi"
94
 
 
95
  def create_gradio_interface():
96
  with gr.Blocks(title="Mistral API") as interface:
97
  gr.Markdown("# Mistral-7B API Server")
 
98
  with gr.Row():
99
  with gr.Column():
100
  status = gr.Textbox(value=lambda: status_message, label="Stato del modello", interactive=False)
101
  load_button = gr.Button("Carica Modello")
102
  load_button.click(load_model, inputs=[], outputs=[])
 
103
  with gr.Row():
104
  with gr.Column():
105
+ input_text = gr.Textbox(lines=5, label="Input", placeholder="Inserisci il tuo messaggio qui...")
 
 
 
 
 
106
  with gr.Row():
107
+ temp_slider = gr.Slider(0.1, 1.0, value=0.7, step=0.1, label="Temperatura")
108
+ max_token_slider = gr.Slider(100, MAX_NEW_TOKENS, value=1024, step=100, label="Max Token")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  submit_button = gr.Button("Genera")
 
110
  with gr.Column():
111
  output_text = gr.Textbox(lines=12, label="Risposta del modello")
 
112
  gen_time = gr.Textbox(label="Tempo di generazione", interactive=False)
 
113
  submit_button.click(
114
  generate_with_timing,
115
  inputs=[input_text, temp_slider, max_token_slider],
116
  outputs=[output_text, gen_time]
117
  )
 
118
  gr.Markdown("""
119
  ## API Endpoint
120
  Questa applicazione espone un endpoint API compatibile con OpenAI:
121
  - `/v1/chat/completions` - Per richieste di completamento chat
122
  - `/status` - Per verificare lo stato del modello
 
 
123
  """)
 
124
  return interface
125
 
 
126
  @spaces.GPU
127
  def get_gpu():
128
  return "GPU allocata con successo"
129
 
 
130
  app = FastAPI()
131
 
 
132
  app.add_middleware(
133
  CORSMiddleware,
134
  allow_origins=["*"],
 
137
  allow_headers=["*"],
138
  )
139
 
 
140
  @app.post("/v1/chat/completions", response_model=CompletionResponse)
141
  async def create_completion(request: CompletionRequest):
142
  try:
143
  prompt = format_chat_prompt(request.messages)
144
+ max_tokens = min(request.max_tokens, MAX_NEW_TOKENS)
 
 
145
  start_time = time.time()
146
  completion_text = generate_response(
147
  prompt,
 
150
  max_tokens=max_tokens
151
  )
152
  end_time = time.time()
 
 
153
  input_tokens = len(prompt.split())
154
  output_tokens = len(completion_text.split())
 
155
  response = {
156
  "id": f"chatcmpl-{os.urandom(4).hex()}",
157
  "object": "chat.completion",
 
173
  "total_tokens": input_tokens + output_tokens,
174
  }
175
  }
 
176
  return response
177
  except Exception as e:
178
  raise HTTPException(status_code=500, detail=str(e))
179
 
 
180
  @app.get("/status")
181
  async def get_status():
182
  return {"status": status_message, "model": MODEL_PATH}
183
 
184
+ # Crea l'interfaccia Gradio e monta su un path dedicato per evitare errori statici
185
+ interface = create_gradio_interface()
186
+ app = gr.mount_gradio_app(app, interface, path="/gradio")
 
 
187
 
 
188
  @app.on_event("startup")
189
  async def startup_load_model():
 
190
  get_gpu()
191
  load_model()
192
 
 
193
  if __name__ == "__main__":
194
  import uvicorn
195
+ uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")