Valtry commited on
Commit
f1bab26
·
verified ·
1 Parent(s): 13791ae

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +298 -0
app.py ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import StreamingResponse
3
+ from pydantic import BaseModel
4
+ from transformers import (
5
+ AutoTokenizer,
6
+ AutoModelForCausalLM,
7
+ TextIteratorStreamer
8
+ )
9
+ import torch
10
+ import uvicorn
11
+ import threading
12
+ import json
13
+
14
+ # =========================
15
+ # APP
16
+ # =========================
17
+
18
+ app = FastAPI()
19
+
20
+ stop_flags = {}
21
+
22
+ # =========================
23
+ # MODEL
24
+ # =========================
25
+
26
+ MODEL_ID = "Qwen/Qwen2.5-Coder-1.5B-Instruct"
27
+
28
+ print("🚀 Loading Fast Coder Model...")
29
+
30
+ device = torch.device(
31
+ "cuda" if torch.cuda.is_available() else "cpu"
32
+ )
33
+
34
+ torch.backends.cuda.matmul.allow_tf32 = True
35
+ torch.backends.cudnn.allow_tf32 = True
36
+
37
+ # =========================
38
+ # TOKENIZER
39
+ # =========================
40
+
41
+ tokenizer = AutoTokenizer.from_pretrained(
42
+ MODEL_ID,
43
+ trust_remote_code=True
44
+ )
45
+
46
+ # =========================
47
+ # MODEL
48
+ # =========================
49
+
50
+ model = AutoModelForCausalLM.from_pretrained(
51
+ MODEL_ID,
52
+ trust_remote_code=True,
53
+ torch_dtype=torch.float16 if device.type == "cuda" else torch.float32
54
+ )
55
+
56
+ model = model.to(device)
57
+ model.eval()
58
+
59
+ print(f"✅ Loaded on {device}")
60
+
61
+ # =========================
62
+ # REQUEST
63
+ # =========================
64
+
65
+ class ChatRequest(BaseModel):
66
+ message: str
67
+ conversation_id: str
68
+ temperature: float = 0.1
69
+
70
+ # =========================
71
+ # SYSTEM PROMPT
72
+ # =========================
73
+
74
+ SYSTEM_PROMPT = """
75
+ You are a strict expert programming assistant.
76
+
77
+ CRITICAL RULES:
78
+ - Answer ONLY the user's latest request
79
+ - NEVER continue conversations
80
+ - NEVER generate extra examples unless asked
81
+ - NEVER explain unnecessarily
82
+ - NEVER repeat code
83
+ - NEVER simulate dialogue
84
+ - ALWAYS close markdown code blocks properly
85
+ - ALWAYS return complete executable code
86
+ - Stop immediately after final answer
87
+
88
+ CODE RULES:
89
+ - Use proper markdown
90
+ - Use ```language
91
+ - Keep formatting clean
92
+ - No duplicate code
93
+ - No unfinished code
94
+ """
95
+
96
+ # =========================
97
+ # STOP WORDS
98
+ # =========================
99
+
100
+ STOP_WORDS = [
101
+ "<|im_end|>",
102
+ "<|endoftext|>",
103
+ "<|eot_id|>",
104
+ "User:",
105
+ "Assistant:",
106
+ "Human:"
107
+ ]
108
+
109
+ # =========================
110
+ # CLEAN OUTPUT
111
+ # =========================
112
+
113
+ def clean_output(text):
114
+
115
+ for w in STOP_WORDS:
116
+
117
+ if w in text:
118
+ text = text.split(w)[0]
119
+
120
+ return text.strip()
121
+
122
+ # =========================
123
+ # BUILD INPUTS
124
+ # =========================
125
+
126
+ def build_inputs(message):
127
+
128
+ messages = [
129
+ {
130
+ "role": "system",
131
+ "content": SYSTEM_PROMPT
132
+ },
133
+ {
134
+ "role": "user",
135
+ "content": message
136
+ }
137
+ ]
138
+
139
+ text = tokenizer.apply_chat_template(
140
+ messages,
141
+ tokenize=False,
142
+ add_generation_prompt=True
143
+ )
144
+
145
+ return tokenizer(
146
+ text,
147
+ return_tensors="pt"
148
+ ).to(device)
149
+
150
+ # =========================
151
+ # STOP ENDPOINT
152
+ # =========================
153
+
154
+ @app.post("/v1/stop")
155
+ def stop(data: dict):
156
+
157
+ stop_flags[data.get("conversation_id")] = True
158
+
159
+ return {
160
+ "status": "stopped"
161
+ }
162
+
163
+ # =========================
164
+ # NORMAL CHAT
165
+ # =========================
166
+
167
+ @app.post("/v1/chat")
168
+ def chat(req: ChatRequest):
169
+
170
+ inputs = build_inputs(req.message)
171
+
172
+ with torch.inference_mode():
173
+
174
+ output = model.generate(
175
+ **inputs,
176
+ max_new_tokens=512,
177
+ do_sample=False,
178
+ temperature=req.temperature,
179
+ top_p=1.0,
180
+ repetition_penalty=1.08,
181
+ pad_token_id=tokenizer.eos_token_id,
182
+ eos_token_id=tokenizer.eos_token_id
183
+ )
184
+
185
+ result = tokenizer.decode(
186
+ output[0][inputs.input_ids.shape[1]:],
187
+ skip_special_tokens=True
188
+ )
189
+
190
+ result = clean_output(result)
191
+
192
+ return {
193
+ "response": result
194
+ }
195
+
196
+ # =========================
197
+ # STREAM CHAT
198
+ # =========================
199
+
200
+ @app.post("/v1/chat/stream")
201
+ def stream_chat(req: ChatRequest):
202
+
203
+ inputs = build_inputs(req.message)
204
+
205
+ streamer = TextIteratorStreamer(
206
+ tokenizer,
207
+ skip_prompt=True,
208
+ skip_special_tokens=True
209
+ )
210
+
211
+ generation_kwargs = dict(
212
+ **inputs,
213
+ streamer=streamer,
214
+ max_new_tokens=512,
215
+ do_sample=False,
216
+ temperature=req.temperature,
217
+ top_p=1.0,
218
+ repetition_penalty=1.08,
219
+ pad_token_id=tokenizer.eos_token_id,
220
+ eos_token_id=tokenizer.eos_token_id
221
+ )
222
+
223
+ thread = threading.Thread(
224
+ target=model.generate,
225
+ kwargs=generation_kwargs
226
+ )
227
+
228
+ thread.start()
229
+
230
+ def generate():
231
+
232
+ full_text = ""
233
+
234
+ for token in streamer:
235
+
236
+ if stop_flags.get(req.conversation_id):
237
+
238
+ stop_flags[req.conversation_id] = False
239
+ break
240
+
241
+ if not token:
242
+ continue
243
+
244
+ stop_hit = False
245
+
246
+ for sw in STOP_WORDS:
247
+
248
+ if sw in token:
249
+ token = token.split(sw)[0]
250
+ stop_hit = True
251
+ break
252
+
253
+ if token:
254
+
255
+ full_text += token
256
+
257
+ # stop after completed markdown block
258
+ if full_text.count("```") >= 2:
259
+ yield f"data: {json.dumps({'choices':[{'delta':{'content': token}}]})}\n\n"
260
+ break
261
+
262
+ yield f"data: {json.dumps({'choices':[{'delta':{'content': token}}]})}\n\n"
263
+
264
+ if stop_hit:
265
+ break
266
+
267
+ full_text = clean_output(full_text)
268
+
269
+ yield "event: done\ndata: {}\n\n"
270
+ yield "data: [DONE]\n\n"
271
+
272
+ return StreamingResponse(
273
+ generate(),
274
+ media_type="text/event-stream"
275
+ )
276
+
277
+ # =========================
278
+ # HEALTH
279
+ # =========================
280
+
281
+ @app.get("/")
282
+ def root():
283
+
284
+ return {
285
+ "status": "Fast Coder Running 🚀"
286
+ }
287
+
288
+ # =========================
289
+ # RUN
290
+ # =========================
291
+
292
+ if __name__ == "__main__":
293
+
294
+ uvicorn.run(
295
+ "app:app",
296
+ host="0.0.0.0",
297
+ port=7860
298
+ )