AhmedBenElsayedBenAhmed commited on
Commit
e13652c
·
1 Parent(s): ff7f00d

Merge branch 'Ai' into main

Browse files
Files changed (2) hide show
  1. app.py +158 -14
  2. requirements.txt +3 -3
app.py CHANGED
@@ -1,25 +1,18 @@
1
  # ===============================
2
  # 1️⃣ استيراد المكتبات
3
  # ===============================
4
- import os
5
- import threading, torch, json
6
  from flask import Flask, request, jsonify
7
  from flask_cors import CORS
 
8
  from datasets import Dataset
9
- from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
10
- from peft import LoraConfig, get_peft_model, TaskType, PeftModel
11
-
12
- # ===============================
13
- # 🟢 إصلاح مشكلة الكاش في Hugging Face Spaces
14
- # ===============================
15
- os.environ["HF_HOME"] = "/app/cache"
16
- os.environ["TRANSFORMERS_CACHE"] = "/app/cache"
17
 
18
  # ===============================
19
  # 2️⃣ إعداد المتغيرات
20
  # ===============================
21
  MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
22
- FLASK_PORT = 7860 # Spaces بيشتغل على 7860
23
  SAVE_DIR = "./lora_model"
24
  DATASET_FILE = "dataset.json"
25
 
@@ -31,7 +24,7 @@ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
31
  model = AutoModelForCausalLM.from_pretrained(
32
  MODEL_NAME,
33
  device_map="auto",
34
- torch_dtype=torch.float16
35
  )
36
  print("✅ Base model loaded!")
37
 
@@ -56,7 +49,7 @@ if os.path.exists(SAVE_DIR):
56
  base_model = AutoModelForCausalLM.from_pretrained(
57
  MODEL_NAME,
58
  device_map="auto",
59
- torch_dtype=torch.float16
60
  )
61
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
62
  print("✅ LoRA weights auto-loaded from disk! [Fine-tuned model running]")
@@ -74,7 +67,66 @@ CORS(app)
74
  trainer = None
75
  current_dataset = None
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  # 🟢 تحميل الداتا من الملف عند البداية
 
78
  def load_dataset():
79
  global current_dataset
80
  if os.path.exists(DATASET_FILE):
@@ -104,7 +156,99 @@ def load_dataset():
104
  load_dataset()
105
 
106
  # ===============================
107
- # 6️⃣ تشغيل Flask (بدون ngrok في Spaces)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  # ===============================
109
  if __name__ == "__main__":
110
  app.run(host="0.0.0.0", port=FLASK_PORT, threaded=True)
 
1
  # ===============================
2
  # 1️⃣ استيراد المكتبات
3
  # ===============================
4
+ from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
5
+ from peft import LoraConfig, get_peft_model, TaskType, PeftModel
6
  from flask import Flask, request, jsonify
7
  from flask_cors import CORS
8
+ import threading, torch, os, json
9
  from datasets import Dataset
 
 
 
 
 
 
 
 
10
 
11
  # ===============================
12
  # 2️⃣ إعداد المتغيرات
13
  # ===============================
14
  MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
15
+ FLASK_PORT = 7860 # 🚨 Hugging Face Spaces يشتغل على 7860
16
  SAVE_DIR = "./lora_model"
17
  DATASET_FILE = "dataset.json"
18
 
 
24
  model = AutoModelForCausalLM.from_pretrained(
25
  MODEL_NAME,
26
  device_map="auto",
27
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
28
  )
29
  print("✅ Base model loaded!")
30
 
 
49
  base_model = AutoModelForCausalLM.from_pretrained(
50
  MODEL_NAME,
51
  device_map="auto",
52
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
53
  )
54
  model = PeftModel.from_pretrained(base_model, SAVE_DIR)
55
  print("✅ LoRA weights auto-loaded from disk! [Fine-tuned model running]")
 
67
  trainer = None
68
  current_dataset = None
69
 
70
+ # ===============================
71
+ # 5a️⃣ توليد نصوص (generate)
72
+ # ===============================
73
+ @app.route("/generate", methods=["POST"])
74
+ def generate():
75
+ try:
76
+ data = request.json
77
+ prompt = data.get("prompt", "").strip()
78
+
79
+ if current_dataset is None:
80
+ return jsonify({
81
+ "messages": [
82
+ {
83
+ "role": "assistant",
84
+ "content": "⚖️ أنا زين، مساعد ذكي للاستشارات القانونية. برجاء طرح سؤال قانوني."
85
+ }
86
+ ]
87
+ })
88
+
89
+ # البحث في الداتا
90
+ for item in current_dataset:
91
+ lines = item["text"].split("\n")
92
+ for line in lines:
93
+ if line.lower().startswith("user:") and prompt in line:
94
+ response_messages = []
95
+ for l in lines:
96
+ if ":" in l:
97
+ role, content = l.split(":", 1)
98
+ response_messages.append({
99
+ "role": role.strip().lower(),
100
+ "content": content.strip()
101
+ })
102
+ return jsonify({"messages": response_messages})
103
+
104
+ # 🟡 fallback (لو مفيش في الداتا)
105
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
106
+ outputs = model.generate(
107
+ **inputs,
108
+ max_new_tokens=150,
109
+ temperature=0.7,
110
+ do_sample=True
111
+ )
112
+ reply = tokenizer.decode(outputs[0], skip_special_tokens=True)
113
+
114
+ return jsonify({
115
+ "messages": [
116
+ {"role": "assistant", "content": reply}
117
+ ]
118
+ })
119
+
120
+ except Exception as e:
121
+ return jsonify({
122
+ "messages": [
123
+ {"role": "assistant", "content": f"خطأ: {str(e)}"}
124
+ ]
125
+ })
126
+
127
+ # ===============================
128
  # 🟢 تحميل الداتا من الملف عند البداية
129
+ # ===============================
130
  def load_dataset():
131
  global current_dataset
132
  if os.path.exists(DATASET_FILE):
 
156
  load_dataset()
157
 
158
  # ===============================
159
+ # 5b️⃣ تدريب LoRA (Async) + حفظ
160
+ # ===============================
161
+ @app.route("/train", methods=["POST"])
162
+ def train():
163
+ global trainer, current_dataset, model
164
+ try:
165
+ data = []
166
+ epochs = 1
167
+ batch_size = 1
168
+
169
+ # 📌 1) JSON request
170
+ if request.is_json:
171
+ body = request.get_json()
172
+ data = body.get("data", [])
173
+ epochs = int(body.get("epochs", 1))
174
+ batch_size = int(body.get("batch_size", 1))
175
+
176
+ # 📌 2) Form-data request
177
+ else:
178
+ epochs = int(request.form.get("epochs", 1))
179
+ batch_size = int(request.form.get("batch_size", 1))
180
+ file = request.files.get("file")
181
+ if file:
182
+ data = json.load(file)
183
+ else:
184
+ return jsonify({"error": "No file uploaded"}), 400
185
+
186
+ # دمج وإزالة التكرارات
187
+ old_data = []
188
+ if os.path.exists(DATASET_FILE):
189
+ with open(DATASET_FILE, "r", encoding="utf-8") as f:
190
+ try:
191
+ old_data = json.load(f)
192
+ except:
193
+ old_data = []
194
+
195
+ combined = old_data + data
196
+ unique_data, seen = [], set()
197
+ for item in combined:
198
+ key = json.dumps(item, ensure_ascii=False)
199
+ if key not in seen:
200
+ seen.add(key)
201
+ unique_data.append(item)
202
+
203
+ # الحفظ
204
+ with open(DATASET_FILE, "w", encoding="utf-8") as f:
205
+ json.dump(unique_data, f, ensure_ascii=False, indent=2)
206
+
207
+ # تجهيز الداتا
208
+ formatted = []
209
+ for item in unique_data:
210
+ if "messages" in item:
211
+ conversation = ""
212
+ for msg in item["messages"]:
213
+ conversation += f"{msg['role'].capitalize()}: {msg['content']}\n"
214
+ formatted.append({"text": conversation.strip()})
215
+ elif "text" in item:
216
+ formatted.append({"text": item["text"]})
217
+
218
+ current_dataset = Dataset.from_list(formatted)
219
+
220
+ def tokenize_function(examples):
221
+ return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=256)
222
+
223
+ tokenized_dataset = current_dataset.map(tokenize_function, batched=True, remove_columns=["text"])
224
+
225
+ training_args = TrainingArguments(
226
+ output_dir=SAVE_DIR,
227
+ per_device_train_batch_size=batch_size,
228
+ num_train_epochs=epochs,
229
+ logging_steps=2,
230
+ save_strategy="epoch",
231
+ fp16=torch.cuda.is_available(),
232
+ report_to=None
233
+ )
234
+
235
+ trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
236
+
237
+ def run_training():
238
+ print("🔄 Training started...")
239
+ trainer.train()
240
+ trainer.save_model(SAVE_DIR)
241
+ print("✅ Training completed & model saved!")
242
+
243
+ threading.Thread(target=run_training, daemon=True).start()
244
+
245
+ return jsonify({"status": "training started", "epochs": epochs, "batch_size": batch_size, "records": len(unique_data)})
246
+
247
+ except Exception as e:
248
+ return jsonify({"error": str(e)})
249
+
250
+ # ===============================
251
+ # 6️⃣ تشغيل Flask (بدون ngrok)
252
  # ===============================
253
  if __name__ == "__main__":
254
  app.run(host="0.0.0.0", port=FLASK_PORT, threaded=True)
requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
- flask
2
- flask-cors
3
  transformers
4
- torch
5
  peft
 
6
  datasets
 
 
 
 
 
1
  transformers
 
2
  peft
3
+ torch
4
  datasets
5
+ flask
6
+ flask-cors