EnzGamers commited on
Commit
f84eddb
·
verified ·
1 Parent(s): 4aedab8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -40
app.py CHANGED
@@ -7,12 +7,9 @@ import time
7
  import uuid
8
  import json
9
  from typing import Optional, List, Union, Dict, Any
10
- import asyncio
11
-
12
- # --- LA SEULE LIGNE À MODIFIER ---
13
- MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct" # Ou "deepseek-ai/deepseek-coder-1.3b-instruct", etc.
14
- # ------------------------------------
15
 
 
 
16
  DEVICE = "cpu"
17
 
18
  # --- Chargement du modèle ---
@@ -23,18 +20,12 @@ model = AutoModelForCausalLM.from_pretrained(
23
  device_map=DEVICE
24
  )
25
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
26
-
27
- # --- Standardisation : Gestion automatique du padding ---
28
- if tokenizer.pad_token is None:
29
- tokenizer.pad_token = tokenizer.eos_token
30
- print("Le pad_token a été défini sur eos_token.")
31
-
32
  print("Modèle et tokenizer chargés avec succès sur le CPU.")
33
 
34
  # --- Création de l'application API ---
35
  app = FastAPI()
36
 
37
- # --- Modèles de données standards pour la compatibilité OpenAI ---
38
  class ContentPart(BaseModel):
39
  type: str
40
  text: str
@@ -51,18 +42,6 @@ class ChatCompletionRequest(BaseModel):
51
  class Config:
52
  extra = Extra.ignore
53
 
54
- class ChatCompletionResponseChoice(BaseModel):
55
- index: int = 0
56
- message: ChatMessage
57
- finish_reason: str = "stop"
58
-
59
- class ChatCompletionResponse(BaseModel):
60
- id: str
61
- object: str = "chat.completion"
62
- created: int
63
- model: str
64
- choices: List[ChatCompletionResponseChoice]
65
-
66
  class ModelData(BaseModel):
67
  id: str
68
  object: str = "model"
@@ -71,7 +50,7 @@ class ModelData(BaseModel):
71
  class ModelList(BaseModel):
72
  object: str = "list"
73
  data: List[ModelData]
74
-
75
  # --- Définition des API ---
76
 
77
  @app.get("/models", response_model=ModelList)
@@ -83,36 +62,74 @@ async def list_models():
83
  async def create_chat_completion(request: ChatCompletionRequest):
84
  """Endpoint principal qui gère la génération de texte en streaming."""
85
 
86
- # --- Standardisation : On ne fait aucune supposition sur le format du message ---
87
- # On passe la liste complète des messages au tokenizer.
88
- messages_for_model = [msg.dict() for msg in request.messages]
89
-
90
- # La fonction apply_chat_template gère automatiquement le "dialecte" de chaque modèle.
91
- text_prompt = tokenizer.apply_chat_template(messages_for_model, tokenize=False, add_generation_prompt=True)
92
-
93
- inputs = tokenizer(text_prompt, return_tensors="pt", padding=True).to(DEVICE)
 
 
 
 
 
 
 
 
94
 
95
- outputs = model.generate(**inputs, max_new_tokens=250, do_sample=True, temperature=0.2, top_k=50, top_p=0.95, num_return_sequences=1, eos_token_id=tokenizer.eos_token_id)
96
-
97
- response_text = tokenizer.decode(outputs[0, inputs['input_ids'].shape[1]:], skip_special_tokens=True)
98
 
 
99
  async def stream_generator():
100
  response_id = f"chatcmpl-{uuid.uuid4()}"
101
 
 
102
  for char in response_text:
103
- chunk = { "id": response_id, "object": "chat.completion.chunk", "created": int(time.time()), "model": MODEL_ID, "choices": [{"index": 0, "delta": {"content": char}, "finish_reason": None }] }
 
 
 
 
 
 
 
 
 
 
104
  yield f"data: {json.dumps(chunk)}\n\n"
105
- await asyncio.sleep(0.01)
106
 
107
- final_chunk = { "id": response_id, "object": "chat.completion.chunk", "created": int(time.time()), "model": MODEL_ID, "choices": [{"index": 0, "delta": {}, "finish_reason": "stop" }] }
 
 
 
 
 
 
 
 
 
 
 
108
  yield f"data: {json.dumps(final_chunk)}\n\n"
 
 
109
  yield "data: [DONE]\n\n"
110
 
 
111
  if request.stream:
112
  return StreamingResponse(stream_generator(), media_type="text/event-stream")
113
  else:
 
114
  return {"choices": [{"message": {"role": "assistant", "content": response_text}}]}
115
 
116
  @app.get("/")
117
  def root():
118
- return {"status": "API compatible OpenAI en ligne (avec streaming)", "model_id": MODEL_ID}
 
 
 
 
7
  import uuid
8
  import json
9
  from typing import Optional, List, Union, Dict, Any
 
 
 
 
 
10
 
11
+ # --- Configuration ---
12
+ MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
13
  DEVICE = "cpu"
14
 
15
  # --- Chargement du modèle ---
 
20
  device_map=DEVICE
21
  )
22
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
 
 
 
 
 
 
23
  print("Modèle et tokenizer chargés avec succès sur le CPU.")
24
 
25
  # --- Création de l'application API ---
26
  app = FastAPI()
27
 
28
+ # --- Modèles de données pour accepter la structure complexe de l'extension ---
29
  class ContentPart(BaseModel):
30
  type: str
31
  text: str
 
42
  class Config:
43
  extra = Extra.ignore
44
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  class ModelData(BaseModel):
46
  id: str
47
  object: str = "model"
 
50
  class ModelList(BaseModel):
51
  object: str = "list"
52
  data: List[ModelData]
53
+
54
  # --- Définition des API ---
55
 
56
  @app.get("/models", response_model=ModelList)
 
62
  async def create_chat_completion(request: ChatCompletionRequest):
63
  """Endpoint principal qui gère la génération de texte en streaming."""
64
 
65
+ # On extrait le prompt de l'utilisateur de la structure complexe
66
+ user_prompt = ""
67
+ last_message = request.messages[-1]
68
+ if isinstance(last_message.content, list):
69
+ for part in last_message.content:
70
+ if part.type == 'text':
71
+ user_prompt += part.text + "\n"
72
+ elif isinstance(last_message.content, str):
73
+ user_prompt = last_message.content
74
+
75
+ if not user_prompt:
76
+ return {"error": "Prompt non trouvé."}
77
+
78
+ # Préparation pour le modèle DeepSeek
79
+ messages_for_model = [{'role': 'user', 'content': user_prompt}]
80
+ inputs = tokenizer.apply_chat_template(messages_for_model, add_generation_prompt=True, return_tensors="pt").to(DEVICE)
81
 
82
+ # Génération de la réponse complète
83
+ outputs = model.generate(inputs, max_new_tokens=250, do_sample=True, temperature=0.2, top_k=50, top_p=0.95, num_return_sequences=1, eos_token_id=tokenizer.eos_token_id)
84
+ response_text = tokenizer.decode(outputs[0][len(inputs[0]):], skip_special_tokens=True)
85
 
86
+ # Fonction génératrice pour le streaming
87
  async def stream_generator():
88
  response_id = f"chatcmpl-{uuid.uuid4()}"
89
 
90
+ # On envoie la réponse caractère par caractère, au format attendu
91
  for char in response_text:
92
+ chunk = {
93
+ "id": response_id,
94
+ "object": "chat.completion.chunk",
95
+ "created": int(time.time()),
96
+ "model": MODEL_ID,
97
+ "choices": [{
98
+ "index": 0,
99
+ "delta": {"content": char},
100
+ "finish_reason": None
101
+ }]
102
+ }
103
  yield f"data: {json.dumps(chunk)}\n\n"
104
+ await asyncio.sleep(0.01) # Petite pause pour simuler un flux
105
 
106
+ # On envoie le chunk final de fin
107
+ final_chunk = {
108
+ "id": response_id,
109
+ "object": "chat.completion.chunk",
110
+ "created": int(time.time()),
111
+ "model": MODEL_ID,
112
+ "choices": [{
113
+ "index": 0,
114
+ "delta": {},
115
+ "finish_reason": "stop"
116
+ }]
117
+ }
118
  yield f"data: {json.dumps(final_chunk)}\n\n"
119
+
120
+ # On envoie le signal [DONE]
121
  yield "data: [DONE]\n\n"
122
 
123
+ # Si l'extension demande un stream, on renvoie le générateur
124
  if request.stream:
125
  return StreamingResponse(stream_generator(), media_type="text/event-stream")
126
  else:
127
+ # Code de secours si le stream n'est pas demandé (peu probable)
128
  return {"choices": [{"message": {"role": "assistant", "content": response_text}}]}
129
 
130
  @app.get("/")
131
  def root():
132
+ return {"status": "API compatible OpenAI en ligne (avec streaming)", "model_id": MODEL_ID}
133
+
134
+ # On a besoin de asyncio pour la pause dans le stream
135
+ import asyncio