AhmedBenElsayedBenAhmed commited on
Commit
4205540
·
1 Parent(s): 1fa7a79
Files changed (1) hide show
  1. app.py +87 -21
app.py CHANGED
@@ -6,17 +6,17 @@ os.environ["HF_HOME"] = "/tmp"
6
  os.environ["TRANSFORMERS_CACHE"] = "/tmp"
7
  os.environ["PEFT_HOME"] = "/tmp"
8
 
 
 
9
  from flask import Flask, request, jsonify
10
  from flask_cors import CORS
11
  import threading, torch, json
12
  from datasets import Dataset
13
- from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
14
- from peft import LoraConfig, get_peft_model, TaskType, PeftModel
15
 
16
  # ===============================
17
  # 2️⃣ إعداد المتغيرات
18
  # ===============================
19
- MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
20
  FLASK_PORT = 7860
21
 
22
  SAVE_DIR = "/tmp/lora_model"
@@ -33,29 +33,37 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
33
  print("🔹 Using device:", device)
34
 
35
  # ===============================
36
- # 4️⃣ تحميل الموديل (بدون quantization)
37
  # ===============================
38
  print("🔄 Loading base model...")
39
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
40
 
41
- model = AutoModelForCausalLM.from_pretrained(
42
- MODEL_NAME,
43
- device_map="auto",
44
- trust_remote_code=True
45
- )
46
- print("✅ Base model loaded!")
 
 
 
 
 
 
 
47
 
48
  # ===============================
49
  # 5️⃣ إعداد LoRA
50
  # ===============================
51
  lora_config = LoraConfig(
52
  task_type=TaskType.CAUSAL_LM,
53
- r=8,
54
- lora_alpha=16,
55
- lora_dropout=0.1,
56
  target_modules=["q_proj", "v_proj"]
57
  )
58
  model = get_peft_model(model, lora_config)
 
59
  print("✅ LoRA model ready on device:", device)
60
 
61
  # ===============================
@@ -65,10 +73,13 @@ if os.path.exists(SAVE_DIR):
65
  try:
66
  base_model = AutoModelForCausalLM.from_pretrained(
67
  MODEL_NAME,
68
- device_map="auto",
 
 
69
  trust_remote_code=True
70
  )
71
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
 
72
  print("✅ LoRA weights auto-loaded from disk!")
73
  except Exception as e:
74
  print("⚠️ Failed to auto-load LoRA weights:", e)
@@ -107,10 +118,34 @@ def generate():
107
 
108
  user_name = user_info["name"]
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  inputs = tokenizer(prompt, return_tensors="pt").to(device)
111
  outputs = model.generate(
112
  **inputs,
113
- max_new_tokens=200,
114
  temperature=0.7,
115
  do_sample=True
116
  )
@@ -137,6 +172,7 @@ def load_dataset():
137
  data = json.load(f)
138
  except:
139
  data = []
 
140
  if data:
141
  formatted = []
142
  for item in data:
@@ -167,6 +203,7 @@ def train():
167
  epochs = 1
168
  batch_size = 1
169
 
 
170
  if request.is_json:
171
  body = request.get_json()
172
  if isinstance(body, list):
@@ -175,8 +212,11 @@ def train():
175
  data = body["data"]
176
  else:
177
  return jsonify({"error": "JSON format not recognized"}), 400
 
178
  epochs = int(body.get("epochs", 1)) if isinstance(body, dict) else 1
179
  batch_size = int(body.get("batch_size", 1)) if isinstance(body, dict) else 1
 
 
180
  else:
181
  file = request.files.get("file")
182
  if file:
@@ -186,11 +226,35 @@ def train():
186
  else:
187
  return jsonify({"error": "No file uploaded or JSON provided"}), 400
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  with open(DATASET_FILE, "w", encoding="utf-8") as f:
190
- json.dump(data, f, ensure_ascii=False, indent=2)
191
 
 
192
  formatted = []
193
- for item in data:
194
  if "messages" in item:
195
  conversation = ""
196
  for msg in item["messages"]:
@@ -202,7 +266,7 @@ def train():
202
  current_dataset = Dataset.from_list(formatted)
203
 
204
  def tokenize_function(examples):
205
- return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=512)
206
 
207
  tokenized_dataset = current_dataset.map(tokenize_function, batched=True, remove_columns=["text"])
208
 
@@ -210,7 +274,7 @@ def train():
210
  output_dir=SAVE_DIR,
211
  per_device_train_batch_size=batch_size,
212
  num_train_epochs=epochs,
213
- logging_steps=5,
214
  save_strategy="epoch",
215
  fp16=torch.cuda.is_available(),
216
  report_to=None
@@ -218,6 +282,7 @@ def train():
218
 
219
  trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
220
 
 
221
  def run_training():
222
  print("🔄 Training started...")
223
  trainer.train()
@@ -230,12 +295,13 @@ def train():
230
  "status": "training started",
231
  "epochs": epochs,
232
  "batch_size": batch_size,
233
- "records": len(data)
234
  })
235
 
236
  except Exception as e:
237
  return jsonify({"error": str(e)})
238
 
 
239
  # ===============================
240
  # 8️⃣ تشغيل Flask
241
  # ===============================
@@ -243,7 +309,7 @@ def train():
243
  def home():
244
  return jsonify({
245
  "status": "ok",
246
- "message": "Qwen-7B LoRA API is running 🚀",
247
  "endpoints": ["/generate", "/train"]
248
  })
249
 
 
6
  os.environ["TRANSFORMERS_CACHE"] = "/tmp"
7
  os.environ["PEFT_HOME"] = "/tmp"
8
 
9
+ from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
10
+ from peft import LoraConfig, get_peft_model, TaskType, PeftModel
11
  from flask import Flask, request, jsonify
12
  from flask_cors import CORS
13
  import threading, torch, json
14
  from datasets import Dataset
 
 
15
 
16
  # ===============================
17
  # 2️⃣ إعداد المتغيرات
18
  # ===============================
19
+ MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
20
  FLASK_PORT = 7860
21
 
22
  SAVE_DIR = "/tmp/lora_model"
 
33
  print("🔹 Using device:", device)
34
 
35
  # ===============================
36
+ # 4️⃣ تحميل الموديل الأساسي بأمان
37
  # ===============================
38
  print("🔄 Loading base model...")
39
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
40
 
41
+ try:
42
+ model = AutoModelForCausalLM.from_pretrained(
43
+ MODEL_NAME,
44
+ device_map="auto" if device=="cuda" else {"": "cpu"},
45
+ torch_dtype=torch.float16 if device=="cuda" else torch.float32,
46
+ load_in_8bit=(device=="cuda"),
47
+ trust_remote_code=True
48
+ )
49
+ model.to(device)
50
+ print("✅ Base model loaded!")
51
+ except Exception as e:
52
+ print("⚠️ Failed to load base model:", e)
53
+ raise e
54
 
55
  # ===============================
56
  # 5️⃣ إعداد LoRA
57
  # ===============================
58
  lora_config = LoraConfig(
59
  task_type=TaskType.CAUSAL_LM,
60
+ r=2,
61
+ lora_alpha=8,
62
+ lora_dropout=0.05,
63
  target_modules=["q_proj", "v_proj"]
64
  )
65
  model = get_peft_model(model, lora_config)
66
+ model.to(device)
67
  print("✅ LoRA model ready on device:", device)
68
 
69
  # ===============================
 
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
+ load_in_8bit=(device=="cuda"),
79
  trust_remote_code=True
80
  )
81
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
82
+ model.to(device)
83
  print("✅ LoRA weights auto-loaded from disk!")
84
  except Exception as e:
85
  print("⚠️ Failed to auto-load LoRA weights:", e)
 
118
 
119
  user_name = user_info["name"]
120
 
121
+ if current_dataset is None:
122
+ return jsonify({
123
+ "messages": [
124
+ {"role": "assistant", "content": f"⚖️ أهلاً {user_name}! أنا زين، مساعدك الذكي. برجاء طرح سؤال قانوني."}
125
+ ]
126
+ })
127
+
128
+ # Search in dataset
129
+ for item in current_dataset:
130
+ lines = item["text"].split("\n")
131
+ for line in lines:
132
+ if line.lower().startswith("user:") and prompt in line:
133
+ response_messages = []
134
+ for l in lines:
135
+ if ":" in l:
136
+ role, content = l.split(":", 1)
137
+ response_messages.append({
138
+ "role": role.strip().lower(),
139
+ "content": content.strip()
140
+ })
141
+ response_messages.insert(0, {"role": "assistant", "content": f"أهلاً {user_name} 👋"})
142
+ return jsonify({"messages": response_messages})
143
+
144
+ # Fallback: generate
145
  inputs = tokenizer(prompt, return_tensors="pt").to(device)
146
  outputs = model.generate(
147
  **inputs,
148
+ max_new_tokens=150,
149
  temperature=0.7,
150
  do_sample=True
151
  )
 
172
  data = json.load(f)
173
  except:
174
  data = []
175
+
176
  if data:
177
  formatted = []
178
  for item in data:
 
203
  epochs = 1
204
  batch_size = 1
205
 
206
+ # 1️⃣ JSON مباشر
207
  if request.is_json:
208
  body = request.get_json()
209
  if isinstance(body, list):
 
212
  data = body["data"]
213
  else:
214
  return jsonify({"error": "JSON format not recognized"}), 400
215
+
216
  epochs = int(body.get("epochs", 1)) if isinstance(body, dict) else 1
217
  batch_size = int(body.get("batch_size", 1)) if isinstance(body, dict) else 1
218
+
219
+ # 2️⃣ form-data ملف
220
  else:
221
  file = request.files.get("file")
222
  if file:
 
226
  else:
227
  return jsonify({"error": "No file uploaded or JSON provided"}), 400
228
 
229
+ # دمج وإزالة التكرارات حسب محتوى الرسائل
230
+ old_data = []
231
+ if os.path.exists(DATASET_FILE):
232
+ with open(DATASET_FILE, "r", encoding="utf-8") as f:
233
+ try:
234
+ old_data = json.load(f)
235
+ except:
236
+ old_data = []
237
+
238
+ combined = old_data + data
239
+ unique_data, seen_texts = [], set()
240
+ for item in combined:
241
+ if "messages" in item:
242
+ text_key = "\n".join([f"{m['role'].strip().lower()}:{m['content'].strip()}" for m in item["messages"]])
243
+ elif "text" in item:
244
+ text_key = item["text"].strip()
245
+ else:
246
+ continue
247
+ if text_key not in seen_texts:
248
+ seen_texts.add(text_key)
249
+ unique_data.append(item)
250
+
251
+ # الحفظ
252
  with open(DATASET_FILE, "w", encoding="utf-8") as f:
253
+ json.dump(unique_data, f, ensure_ascii=False, indent=2)
254
 
255
+ # تجهيز Dataset للتدريب
256
  formatted = []
257
+ for item in unique_data:
258
  if "messages" in item:
259
  conversation = ""
260
  for msg in item["messages"]:
 
266
  current_dataset = Dataset.from_list(formatted)
267
 
268
  def tokenize_function(examples):
269
+ return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=256)
270
 
271
  tokenized_dataset = current_dataset.map(tokenize_function, batched=True, remove_columns=["text"])
272
 
 
274
  output_dir=SAVE_DIR,
275
  per_device_train_batch_size=batch_size,
276
  num_train_epochs=epochs,
277
+ logging_steps=2,
278
  save_strategy="epoch",
279
  fp16=torch.cuda.is_available(),
280
  report_to=None
 
282
 
283
  trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
284
 
285
+ # تشغيل التدريب في Thread منفصل
286
  def run_training():
287
  print("🔄 Training started...")
288
  trainer.train()
 
295
  "status": "training started",
296
  "epochs": epochs,
297
  "batch_size": batch_size,
298
+ "records": len(unique_data)
299
  })
300
 
301
  except Exception as e:
302
  return jsonify({"error": str(e)})
303
 
304
+
305
  # ===============================
306
  # 8️⃣ تشغيل Flask
307
  # ===============================
 
309
  def home():
310
  return jsonify({
311
  "status": "ok",
312
+ "message": "Graduation Project API is running 🚀",
313
  "endpoints": ["/generate", "/train"]
314
  })
315