AhmedBenElsayedBenAhmed commited on
Commit
f88163d
·
1 Parent(s): 3fff865
Files changed (1) hide show
  1. app.py +49 -55
app.py CHANGED
@@ -17,7 +17,7 @@ import difflib
17
  # ===============================
18
  # 2️⃣ إعداد المتغيرات
19
  # ===============================
20
- MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
21
  FLASK_PORT = 7860
22
 
23
  SAVE_DIR = "/tmp/lora_model"
@@ -31,26 +31,25 @@ DATASET_FILE = os.path.join(DATA_DIR, "dataset.json")
31
  # 3️⃣ تحديد الجهاز
32
  # ===============================
33
  device = "cuda" if torch.cuda.is_available() else "cpu"
34
- print("🔹 Using device:", device)
35
 
36
  # ===============================
37
  # 4️⃣ تحميل الموديل الأساسي
38
  # ===============================
39
- print("🔄 Loading base model...")
40
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
41
 
42
  try:
43
  model = AutoModelForCausalLM.from_pretrained(
44
  MODEL_NAME,
45
- device_map="auto" if device=="cuda" else {"": "cpu"},
46
- torch_dtype=torch.float16 if device=="cuda" else torch.float32,
47
- load_in_8bit=(device=="cuda"),
48
  trust_remote_code=True
49
  )
50
  model.to(device)
51
- print("✅ Base model loaded!")
52
  except Exception as e:
53
- print("⚠️ Failed to load base model:", e)
54
  raise e
55
 
56
  # ===============================
@@ -58,34 +57,33 @@ except Exception as e:
58
  # ===============================
59
  lora_config = LoraConfig(
60
  task_type=TaskType.CAUSAL_LM,
61
- r=2,
62
- lora_alpha=8,
63
- lora_dropout=0.05,
64
  target_modules=["q_proj", "v_proj"]
65
  )
66
  model = get_peft_model(model, lora_config)
67
  model.to(device)
68
- print("✅ LoRA model ready on device:", device)
69
 
70
  # ===============================
71
- # 6️⃣ Auto load LoRA weights
72
  # ===============================
73
  if os.path.exists(SAVE_DIR):
74
  try:
75
  base_model = AutoModelForCausalLM.from_pretrained(
76
  MODEL_NAME,
77
- device_map="auto" if device=="cuda" else {"": "cpu"},
78
- torch_dtype=torch.float16 if device=="cuda" else torch.float32,
79
- load_in_8bit=(device=="cuda"),
80
  trust_remote_code=True
81
  )
82
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
83
  model.to(device)
84
- print("✅ LoRA weights auto-loaded from disk!")
85
  except Exception as e:
86
- print("⚠️ Failed to auto-load LoRA weights:", e)
87
  else:
88
- print("ℹ️ No saved LoRA weights found, running with base model.")
89
 
90
  # ===============================
91
  # 7️⃣ إعداد Flask API
@@ -96,15 +94,15 @@ CORS(app)
96
  trainer = None
97
  current_dataset = None
98
 
99
- # Fake DB
100
  users_db = {
101
- "1": {"name": "Ahmed Elsayed", "role": "Student"},
102
- "2": {"name": "Mona Ali", "role": "Lawyer"},
103
- "3": {"name": "Omar Hassan", "role": "Client"}
104
  }
105
 
106
  # ===============================
107
- # 7a️⃣ توليد نصوص
108
  # ===============================
109
  @app.route("/generate", methods=["POST"])
110
  def generate():
@@ -119,15 +117,13 @@ def generate():
119
  user_name = user_info["name"] if user_info else "مستخدم"
120
 
121
  if not prompt:
122
- return jsonify({"messages": [{"role": "assistant", "content": "⚠️ الرجاء ارسال سؤال أو استفسار صحيح."}]}), 400
123
 
124
- # =====================
125
- # حالة: لا يوجد داتا تدريبية
126
- # =====================
127
  if current_dataset is None:
128
  base_prompt = (
129
- f"أنت مساعد قانوني ذكي اسمه زين 👨‍⚖️.\n"
130
- f"مهمة زين: الإجابة على الأسئلة القانونية بأسلوب واضح ومبسط "
131
  f"مع الحفاظ على الدقة القانونية.\n\n"
132
  f"السؤال:\n{prompt}\n\nالإجابة:"
133
  )
@@ -138,8 +134,8 @@ def generate():
138
 
139
  outputs = model.generate(
140
  **inputs,
141
- max_new_tokens=200,
142
- temperature=0.7,
143
  top_p=0.9,
144
  do_sample=True,
145
  pad_token_id=tokenizer.eos_token_id,
@@ -150,15 +146,13 @@ def generate():
150
 
151
  return jsonify({
152
  "messages": [
153
- {"role": "assistant", "content": f"أهلاً {user_name} 👋"},
154
  {"role": "assistant", "content": reply}
155
  ],
156
  "meta": {"mode": "base"}
157
  })
158
 
159
- # =====================
160
- # حالة: يوجد داتا تدريبية
161
- # =====================
162
  candidates = []
163
  for item in current_dataset:
164
  text = item.get("text", "")
@@ -181,14 +175,14 @@ def generate():
181
  elif role.startswith("assistant") or role.startswith("ai") or role.startswith("system"):
182
  a_lines.append(content.strip())
183
  if u_lines or a_lines:
184
- context_parts.append("User: " + " ".join(u_lines) + "\nAssistant: " + " ".join(a_lines))
185
 
186
  context_text = "\n\n---\n\n".join(context_parts)
187
 
188
  instruction = (
189
- "التعليمات: استعن بالأمثلة التدريبية كمرجع أساسي، "
190
- "لكن أجب بأسلوبك الخاص وبكلمات مختلفة. "
191
- "حافظ على صحة المعلومة القانونية ولا تنسخ النصوص كما هي."
192
  )
193
 
194
  if context_text and focus_level > 0.0:
@@ -201,14 +195,14 @@ def generate():
201
  else:
202
  final_prompt = f"{instruction}\n\nالسؤال:\n{prompt}\n\nالإجابة:"
203
 
204
- # ==== توليد
205
  inputs = tokenizer(final_prompt, return_tensors="pt", truncation=True, max_length=1024)
206
  inputs = {k: v.to(model.device) for k, v in inputs.items()}
207
  input_len = inputs["input_ids"].shape[-1]
208
 
209
  outputs = model.generate(
210
  **inputs,
211
- max_new_tokens=200,
212
  temperature=0.6,
213
  top_p=0.9,
214
  do_sample=True,
@@ -220,7 +214,7 @@ def generate():
220
 
221
  return jsonify({
222
  "messages": [
223
- {"role": "assistant", "content": f"أهلاً {user_name} 👋"},
224
  {"role": "assistant", "content": reply}
225
  ],
226
  "meta": {
@@ -231,10 +225,10 @@ def generate():
231
  })
232
 
233
  except Exception as e:
234
- return jsonify({"messages": [{"role": "assistant", "content": f"❌ خطأ: {str(e)}"}]})
235
 
236
  # ===============================
237
- # 7b️⃣ تحميل الداتا
238
  # ===============================
239
  def load_dataset():
240
  global current_dataset
@@ -255,7 +249,7 @@ def load_dataset():
255
  elif "text" in item:
256
  formatted.append({"text": item["text"]})
257
  current_dataset = Dataset.from_list(formatted)
258
- print(f"✅ Loaded {len(formatted)} records from dataset.json")
259
  else:
260
  current_dataset = None
261
  else:
@@ -264,7 +258,7 @@ def load_dataset():
264
  load_dataset()
265
 
266
  # ===============================
267
- # 7c️⃣ تدريب LoRA (Async)
268
  # ===============================
269
  @app.route("/train", methods=["POST"])
270
  def train():
@@ -281,7 +275,7 @@ def train():
281
  elif isinstance(body, dict) and "data" in body:
282
  data = body["data"]
283
  else:
284
- return jsonify({"error": "JSON format not recognized"}), 400
285
 
286
  epochs = int(body.get("epochs", 1)) if isinstance(body, dict) else 1
287
  batch_size = int(body.get("batch_size", 1)) if isinstance(body, dict) else 1
@@ -292,7 +286,7 @@ def train():
292
  epochs = int(request.form.get("epochs", 1))
293
  batch_size = int(request.form.get("batch_size", 1))
294
  else:
295
- return jsonify({"error": "No file uploaded or JSON provided"}), 400
296
 
297
  old_data = []
298
  if os.path.exists(DATASET_FILE):
@@ -347,15 +341,15 @@ def train():
347
  trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
348
 
349
  def run_training():
350
- print("🔄 Training started...")
351
  trainer.train()
352
  trainer.save_model(SAVE_DIR)
353
- print("✅ Training completed & model saved!")
354
 
355
  threading.Thread(target=run_training, daemon=True).start()
356
 
357
  return jsonify({
358
- "status": "training started",
359
  "epochs": epochs,
360
  "batch_size": batch_size,
361
  "records": len(unique_data)
@@ -365,13 +359,13 @@ def train():
365
  return jsonify({"error": str(e)})
366
 
367
  # ===============================
368
- # 8️⃣ تشغيل Flask
369
  # ===============================
370
  @app.route("/", methods=["GET"])
371
  def home():
372
  return jsonify({
373
- "status": "ok",
374
- "message": "Graduation Project API is running 🚀",
375
  "endpoints": ["/generate", "/train"]
376
  })
377
 
 
17
  # ===============================
18
  # 2️⃣ إعداد المتغيرات
19
  # ===============================
20
+ MODEL_NAME = "Qwen/Qwen2.5-1.5B-Instruct" # موديل أكبر وأكثر دقة
21
  FLASK_PORT = 7860
22
 
23
  SAVE_DIR = "/tmp/lora_model"
 
31
  # 3️⃣ تحديد الجهاز
32
  # ===============================
33
  device = "cuda" if torch.cuda.is_available() else "cpu"
34
+ print("🔹 الجهاز المستخدم:", device)
35
 
36
  # ===============================
37
  # 4️⃣ تحميل الموديل الأساسي
38
  # ===============================
39
+ print("🔄 جاري تحميل الموديل الأساسي...")
40
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
41
 
42
  try:
43
  model = AutoModelForCausalLM.from_pretrained(
44
  MODEL_NAME,
45
+ device_map="auto" if device == "cuda" else {"": "cpu"},
46
+ torch_dtype=torch.float16 if device == "cuda" else torch.float32,
 
47
  trust_remote_code=True
48
  )
49
  model.to(device)
50
+ print("✅ تم تحميل الموديل الأساسي بنجاح.")
51
  except Exception as e:
52
+ print("⚠️ فشل تحميل الموديل:", e)
53
  raise e
54
 
55
  # ===============================
 
57
  # ===============================
58
  lora_config = LoraConfig(
59
  task_type=TaskType.CAUSAL_LM,
60
+ r=4,
61
+ lora_alpha=16,
62
+ lora_dropout=0.1,
63
  target_modules=["q_proj", "v_proj"]
64
  )
65
  model = get_peft_model(model, lora_config)
66
  model.to(device)
67
+ print("✅ تم تفعيل LoRA على الموديل.")
68
 
69
  # ===============================
70
+ # 6️⃣ تحميل أوزان LoRA إذا وجدت
71
  # ===============================
72
  if os.path.exists(SAVE_DIR):
73
  try:
74
  base_model = AutoModelForCausalLM.from_pretrained(
75
  MODEL_NAME,
76
+ device_map="auto" if device == "cuda" else {"": "cpu"},
77
+ torch_dtype=torch.float16 if device == "cuda" else torch.float32,
 
78
  trust_remote_code=True
79
  )
80
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
81
  model.to(device)
82
+ print("✅ تم تحميل أوزان LoRA المحفوظة.")
83
  except Exception as e:
84
+ print("⚠️ لم يتم تحميل أوزان LoRA:", e)
85
  else:
86
+ print("ℹ️ لا يوجد أوزان محفوظة. سيتم استخدام الموديل الأساسي فقط.")
87
 
88
  # ===============================
89
  # 7️⃣ إعداد Flask API
 
94
  trainer = None
95
  current_dataset = None
96
 
97
+ # قاعدة بيانات تجريبية للمستخدمين
98
  users_db = {
99
+ "1": {"name": "أحمد السيد", "role": "طالب"},
100
+ "2": {"name": "منى علي", "role": "محامية"},
101
+ "3": {"name": "عمر حسن", "role": "عميل"}
102
  }
103
 
104
  # ===============================
105
+ # 7a️⃣ توليد النصوص
106
  # ===============================
107
  @app.route("/generate", methods=["POST"])
108
  def generate():
 
117
  user_name = user_info["name"] if user_info else "مستخدم"
118
 
119
  if not prompt:
120
+ return jsonify({"messages": [{"role": "assistant", "content": "⚠️ من فضلك أرسل سؤال أو استفسار صحيح."}]}), 400
121
 
122
+ # في حالة عدم وجود بيانات تدريبية
 
 
123
  if current_dataset is None:
124
  base_prompt = (
125
+ f"أنت مساعد قانوني اسمه ��ين.\n"
126
+ f"مهمتك: الرد على الأسئلة القانونية بلغة عربية واضحة وبسيطة "
127
  f"مع الحفاظ على الدقة القانونية.\n\n"
128
  f"السؤال:\n{prompt}\n\nالإجابة:"
129
  )
 
134
 
135
  outputs = model.generate(
136
  **inputs,
137
+ max_new_tokens=300,
138
+ temperature=0.6,
139
  top_p=0.9,
140
  do_sample=True,
141
  pad_token_id=tokenizer.eos_token_id,
 
146
 
147
  return jsonify({
148
  "messages": [
149
+ {"role": "assistant", "content": f"مرحباً {user_name}"},
150
  {"role": "assistant", "content": reply}
151
  ],
152
  "meta": {"mode": "base"}
153
  })
154
 
155
+ # في حالة وجود بيانات تدريبية
 
 
156
  candidates = []
157
  for item in current_dataset:
158
  text = item.get("text", "")
 
175
  elif role.startswith("assistant") or role.startswith("ai") or role.startswith("system"):
176
  a_lines.append(content.strip())
177
  if u_lines or a_lines:
178
+ context_parts.append("المستخدم: " + " ".join(u_lines) + "\nالمساعد: " + " ".join(a_lines))
179
 
180
  context_text = "\n\n---\n\n".join(context_parts)
181
 
182
  instruction = (
183
+ "التعليمات: استخدم الأمثلة التدريبية كمصدر مرجعي، "
184
+ "لكن أجب بصياغة جديدة وبأسلوبك الخاص. "
185
+ "حافظ على صحة المعلومات القانونية وتجنب النسخ الحرفي."
186
  )
187
 
188
  if context_text and focus_level > 0.0:
 
195
  else:
196
  final_prompt = f"{instruction}\n\nالسؤال:\n{prompt}\n\nالإجابة:"
197
 
198
+ # توليد النص
199
  inputs = tokenizer(final_prompt, return_tensors="pt", truncation=True, max_length=1024)
200
  inputs = {k: v.to(model.device) for k, v in inputs.items()}
201
  input_len = inputs["input_ids"].shape[-1]
202
 
203
  outputs = model.generate(
204
  **inputs,
205
+ max_new_tokens=300,
206
  temperature=0.6,
207
  top_p=0.9,
208
  do_sample=True,
 
214
 
215
  return jsonify({
216
  "messages": [
217
+ {"role": "assistant", "content": f"مرحباً {user_name}"},
218
  {"role": "assistant", "content": reply}
219
  ],
220
  "meta": {
 
225
  })
226
 
227
  except Exception as e:
228
+ return jsonify({"messages": [{"role": "assistant", "content": f"خطأ: {str(e)}"}]})
229
 
230
  # ===============================
231
+ # 7b️⃣ تحميل البيانات
232
  # ===============================
233
  def load_dataset():
234
  global current_dataset
 
249
  elif "text" in item:
250
  formatted.append({"text": item["text"]})
251
  current_dataset = Dataset.from_list(formatted)
252
+ print(f"✅ تم تحميل {len(formatted)} سجل من قاعدة البيانات.")
253
  else:
254
  current_dataset = None
255
  else:
 
258
  load_dataset()
259
 
260
  # ===============================
261
+ # 7c️⃣ تدريب الموديل (LoRA)
262
  # ===============================
263
  @app.route("/train", methods=["POST"])
264
  def train():
 
275
  elif isinstance(body, dict) and "data" in body:
276
  data = body["data"]
277
  else:
278
+ return jsonify({"error": "صيغة JSON غير صحيحة"}), 400
279
 
280
  epochs = int(body.get("epochs", 1)) if isinstance(body, dict) else 1
281
  batch_size = int(body.get("batch_size", 1)) if isinstance(body, dict) else 1
 
286
  epochs = int(request.form.get("epochs", 1))
287
  batch_size = int(request.form.get("batch_size", 1))
288
  else:
289
+ return jsonify({"error": "لم يتم رفع ملف أو إرسال JSON"}), 400
290
 
291
  old_data = []
292
  if os.path.exists(DATASET_FILE):
 
341
  trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
342
 
343
  def run_training():
344
+ print("🔄 بدأ التدريب...")
345
  trainer.train()
346
  trainer.save_model(SAVE_DIR)
347
+ print("✅ انتهى التدريب وتم حفظ الموديل.")
348
 
349
  threading.Thread(target=run_training, daemon=True).start()
350
 
351
  return jsonify({
352
+ "status": "بدأ التدريب",
353
  "epochs": epochs,
354
  "batch_size": batch_size,
355
  "records": len(unique_data)
 
359
  return jsonify({"error": str(e)})
360
 
361
  # ===============================
362
+ # 8️⃣ نقطة البداية
363
  # ===============================
364
  @app.route("/", methods=["GET"])
365
  def home():
366
  return jsonify({
367
+ "status": "جاهز",
368
+ "message": "واجهة برمجة التخرج تعمل الآن",
369
  "endpoints": ["/generate", "/train"]
370
  })
371