AhmedBenElsayedBenAhmed commited on
Commit
62d9b3f
·
1 Parent(s): 4071046

Merge branch 'Ai' into main

Browse files
Files changed (1) hide show
  1. app.py +52 -51
app.py CHANGED
@@ -5,17 +5,17 @@ import os
5
  os.environ["HF_HOME"] = "/tmp"
6
  os.environ["TRANSFORMERS_CACHE"] = "/tmp"
7
  os.environ["PEFT_HOME"] = "/tmp"
 
8
  from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
9
  from peft import LoraConfig, get_peft_model, TaskType, PeftModel
10
  from flask import Flask, request, jsonify
11
  from flask_cors import CORS
12
- import threading, torch, os, json
13
  from datasets import Dataset
14
 
15
  # ===============================
16
  # 2️⃣ إعداد المتغيرات
17
  # ===============================
18
-
19
  MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
20
  FLASK_PORT = 7860
21
 
@@ -26,21 +26,34 @@ os.makedirs(SAVE_DIR, exist_ok=True)
26
 
27
  DATASET_FILE = os.path.join(DATA_DIR, "dataset.json")
28
 
 
 
 
 
 
29
 
30
  # ===============================
31
- # 3️⃣ تحميل الموديل الأساسي
32
  # ===============================
33
  print("🔄 Loading base model...")
34
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
35
- model = AutoModelForCausalLM.from_pretrained(
36
- MODEL_NAME,
37
- device_map="auto",
38
- torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
39
- )
40
- print("✅ Base model loaded!")
 
 
 
 
 
 
 
 
41
 
42
  # ===============================
43
- # 4️⃣ إعداد LoRA
44
  # ===============================
45
  lora_config = LoraConfig(
46
  task_type=TaskType.CAUSAL_LM,
@@ -50,27 +63,31 @@ lora_config = LoraConfig(
50
  target_modules=["q_proj", "v_proj"]
51
  )
52
  model = get_peft_model(model, lora_config)
53
- print("✅ LoRA model ready!")
 
54
 
55
  # ===============================
56
- # 🟢 Auto load LoRA weights on startup
57
  # ===============================
58
  if os.path.exists(SAVE_DIR):
59
  try:
60
  base_model = AutoModelForCausalLM.from_pretrained(
61
  MODEL_NAME,
62
- device_map="auto",
63
- torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
 
 
64
  )
65
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
66
- print("✅ LoRA weights auto-loaded from disk! [Fine-tuned model running]")
 
67
  except Exception as e:
68
- print("⚠️ Failed to auto-load LoRA weights:", str(e))
69
  else:
70
  print("ℹ️ No saved LoRA weights found, running with base model.")
71
 
72
  # ===============================
73
- # 5️⃣ إعداد Flask API
74
  # ===============================
75
  app = Flask(__name__)
76
  CORS(app)
@@ -78,9 +95,7 @@ CORS(app)
78
  trainer = None
79
  current_dataset = None
80
 
81
- # ===============================
82
- # Fake Database (مؤقت للتجربة)
83
- # ===============================
84
  users_db = {
85
  "1": {"name": "Ahmed Elsayed", "role": "Student"},
86
  "2": {"name": "Mona Ali", "role": "Lawyer"},
@@ -88,7 +103,7 @@ users_db = {
88
  }
89
 
90
  # ===============================
91
- # 5a️⃣ توليد نصوص (generate)
92
  # ===============================
93
  @app.route("/generate", methods=["POST"])
94
  def generate():
@@ -97,25 +112,20 @@ def generate():
97
  prompt = data.get("prompt", "").strip()
98
  user_id = str(data.get("userId", "")).strip()
99
 
100
- # 🔍 التحقق من المستخدم
101
  user_info = users_db.get(user_id)
102
  if not user_info:
103
  return jsonify({"error": "User not found"}), 404
104
 
105
  user_name = user_info["name"]
106
 
107
- # 📌 لو مفيش داتا حالياً
108
  if current_dataset is None:
109
  return jsonify({
110
  "messages": [
111
- {
112
- "role": "assistant",
113
- "content": f"⚖️ أهلاً {user_name}! أنا زين، مساعدك الذكي. برجاء طرح سؤال قانوني."
114
- }
115
  ]
116
  })
117
 
118
- # 🔎 البحث في الداتا
119
  for item in current_dataset:
120
  lines = item["text"].split("\n")
121
  for line in lines:
@@ -128,15 +138,11 @@ def generate():
128
  "role": role.strip().lower(),
129
  "content": content.strip()
130
  })
131
- # 📌 إضافة اسم المستخدم في البداية
132
- response_messages.insert(0, {
133
- "role": "assistant",
134
- "content": f"أهلاً {user_name} 👋"
135
- })
136
  return jsonify({"messages": response_messages})
137
 
138
- # 🟡 fallback (لو مفيش في الداتا)
139
- inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
140
  outputs = model.generate(
141
  **inputs,
142
  max_new_tokens=150,
@@ -153,13 +159,10 @@ def generate():
153
  })
154
 
155
  except Exception as e:
156
- return jsonify({
157
- "messages": [
158
- {"role": "assistant", "content": f"خطأ: {str(e)}"}
159
- ]
160
- })
161
  # ===============================
162
- # 🟢 تحميل الداتا من الملف عند البداية
163
  # ===============================
164
  def load_dataset():
165
  global current_dataset
@@ -190,7 +193,7 @@ def load_dataset():
190
  load_dataset()
191
 
192
  # ===============================
193
- # 5b️⃣ تدريب LoRA (Async) + حفظ
194
  # ===============================
195
  @app.route("/train", methods=["POST"])
196
  def train():
@@ -200,14 +203,11 @@ def train():
200
  epochs = 1
201
  batch_size = 1
202
 
203
- # 📌 1) JSON request
204
  if request.is_json:
205
  body = request.get_json()
206
  data = body.get("data", [])
207
  epochs = int(body.get("epochs", 1))
208
  batch_size = int(body.get("batch_size", 1))
209
-
210
- # 📌 2) Form-data request
211
  else:
212
  epochs = int(request.form.get("epochs", 1))
213
  batch_size = int(request.form.get("batch_size", 1))
@@ -217,7 +217,7 @@ def train():
217
  else:
218
  return jsonify({"error": "No file uploaded"}), 400
219
 
220
- # دمج وإزالة التكرارات
221
  old_data = []
222
  if os.path.exists(DATASET_FILE):
223
  with open(DATASET_FILE, "r", encoding="utf-8") as f:
@@ -234,11 +234,11 @@ def train():
234
  seen.add(key)
235
  unique_data.append(item)
236
 
237
- # الحفظ
238
  with open(DATASET_FILE, "w", encoding="utf-8") as f:
239
  json.dump(unique_data, f, ensure_ascii=False, indent=2)
240
 
241
- # تجهيز الداتا
242
  formatted = []
243
  for item in unique_data:
244
  if "messages" in item:
@@ -282,10 +282,8 @@ def train():
282
  return jsonify({"error": str(e)})
283
 
284
  # ===============================
285
- # 6️⃣ تشغيل Flask (بدون ngrok)
286
  # ===============================
287
- if __name__ == "__main__":
288
- app.run(host="0.0.0.0", port=FLASK_PORT, threaded=True)
289
  @app.route("/", methods=["GET"])
290
  def home():
291
  return jsonify({
@@ -293,3 +291,6 @@ def home():
293
  "message": "Graduation Project API is running 🚀",
294
  "endpoints": ["/generate", "/train"]
295
  })
 
 
 
 
5
  os.environ["HF_HOME"] = "/tmp"
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
 
 
26
 
27
  DATASET_FILE = os.path.join(DATA_DIR, "dataset.json")
28
 
29
+ # ===============================
30
+ # 3️⃣ تحديد الجهاز
31
+ # ===============================
32
+ device = "cuda" if torch.cuda.is_available() else "cpu"
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,
 
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
  # ===============================
70
+ # 6️⃣ Auto load LoRA weights
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
+ 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)
86
  else:
87
  print("ℹ️ No saved LoRA weights found, running with base model.")
88
 
89
  # ===============================
90
+ # 7️⃣ إعداد Flask API
91
  # ===============================
92
  app = Flask(__name__)
93
  CORS(app)
 
95
  trainer = None
96
  current_dataset = None
97
 
98
+ # Fake DB
 
 
99
  users_db = {
100
  "1": {"name": "Ahmed Elsayed", "role": "Student"},
101
  "2": {"name": "Mona Ali", "role": "Lawyer"},
 
103
  }
104
 
105
  # ===============================
106
+ # 7a️⃣ توليد نصوص
107
  # ===============================
108
  @app.route("/generate", methods=["POST"])
109
  def generate():
 
112
  prompt = data.get("prompt", "").strip()
113
  user_id = str(data.get("userId", "")).strip()
114
 
 
115
  user_info = users_db.get(user_id)
116
  if not user_info:
117
  return jsonify({"error": "User not found"}), 404
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:
 
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,
 
159
  })
160
 
161
  except Exception as e:
162
+ return jsonify({"messages": [{"role": "assistant", "content": f"خطأ: {str(e)}"}]})
163
+
 
 
 
164
  # ===============================
165
+ # 7b️⃣ تحميل الداتا
166
  # ===============================
167
  def load_dataset():
168
  global current_dataset
 
193
  load_dataset()
194
 
195
  # ===============================
196
+ # 7c️⃣ تدريب LoRA (Async)
197
  # ===============================
198
  @app.route("/train", methods=["POST"])
199
  def train():
 
203
  epochs = 1
204
  batch_size = 1
205
 
 
206
  if request.is_json:
207
  body = request.get_json()
208
  data = body.get("data", [])
209
  epochs = int(body.get("epochs", 1))
210
  batch_size = int(body.get("batch_size", 1))
 
 
211
  else:
212
  epochs = int(request.form.get("epochs", 1))
213
  batch_size = int(request.form.get("batch_size", 1))
 
217
  else:
218
  return jsonify({"error": "No file uploaded"}), 400
219
 
220
+ # Merge & remove duplicates
221
  old_data = []
222
  if os.path.exists(DATASET_FILE):
223
  with open(DATASET_FILE, "r", encoding="utf-8") as f:
 
234
  seen.add(key)
235
  unique_data.append(item)
236
 
237
+ # Save dataset
238
  with open(DATASET_FILE, "w", encoding="utf-8") as f:
239
  json.dump(unique_data, f, ensure_ascii=False, indent=2)
240
 
241
+ # Prepare dataset
242
  formatted = []
243
  for item in unique_data:
244
  if "messages" in item:
 
282
  return jsonify({"error": str(e)})
283
 
284
  # ===============================
285
+ # 8️⃣ تشغيل Flask
286
  # ===============================
 
 
287
  @app.route("/", methods=["GET"])
288
  def home():
289
  return jsonify({
 
291
  "message": "Graduation Project API is running 🚀",
292
  "endpoints": ["/generate", "/train"]
293
  })
294
+
295
+ if __name__ == "__main__":
296
+ app.run(host="0.0.0.0", port=FLASK_PORT, threaded=True)