Paulwalker4884 commited on
Commit
5f5d374
·
1 Parent(s): c359186

Initial commit

Browse files
Files changed (1) hide show
  1. app.py +337 -112
app.py CHANGED
@@ -13,163 +13,388 @@ logger = logging.getLogger(__name__)
13
  logger.info("Starting application setup")
14
  qwen_api_key = os.getenv("QWEN_API_KEY")
15
  if not qwen_api_key:
16
- logger.error("QWEN_API_KEY not set")
17
- raise ValueError("QWEN_API_KEY is required. Set it in Spaces Secrets (Settings > Repository secrets > Add secret > Name: QWEN_API_KEY).")
18
-
19
- # تنظیم کلاینت OpenAI برای DashScope
20
- try:
21
- client = OpenAI(
22
- api_key=qwen_api_key,
23
- base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
24
- )
25
- logger.info("Initialized OpenAI client for model qwen3-coder-plus")
26
- except Exception as e:
27
- logger.error(f"Failed to initialize OpenAI client: {e}")
28
- raise
 
 
 
 
 
 
 
 
 
 
29
 
30
  # مسیر فایل دیتابیس
31
- DB_PATH = "chris.db"
32
 
33
  # ایجاد دیتابیس
34
  def init_db():
35
- logger.info("Initializing database")
36
  try:
37
  with sqlite3.connect(DB_PATH) as conn:
38
  cursor = conn.cursor()
39
- cursor.execute('''CREATE TABLE IF NOT EXISTS CHRIS (
40
  id INTEGER PRIMARY KEY AUTOINCREMENT,
41
- user_input TEXT,
42
- task_type TEXT,
43
- prompt TEXT,
44
- response TEXT,
45
- timestamp TEXT
 
46
  )''')
47
  conn.commit()
48
- logger.info("Database initialized")
49
  except Exception as e:
50
- logger.error(f"Database error: {e}")
51
- raise
52
 
53
  # ذخیره در دیتابیس
54
- def save_to_memory(user_input, task_type, prompt, response):
55
- logger.info("Saving to database")
56
  try:
57
  with sqlite3.connect(DB_PATH) as conn:
58
  cursor = conn.cursor()
59
- cursor.execute("INSERT INTO CHRIS (user_input, task_type, prompt, response, timestamp) VALUES (?, ?, ?, ?, ?)",
60
- (user_input, task_type, prompt, response, datetime.now().isoformat()))
 
 
 
61
  conn.commit()
62
- logger.info("Saved to DB")
63
  except Exception as e:
64
- logger.error(f"DB Save Error: {e}")
65
- pass
66
 
67
  # دریافت تاریخچه
68
- def get_history():
69
- logger.info("Retrieving history from database")
70
  try:
71
  with sqlite3.connect(DB_PATH) as conn:
72
  cursor = conn.cursor()
73
- cursor.execute("SELECT id, user_input, task_type, prompt, response, timestamp FROM CHRIS ORDER BY timestamp DESC")
 
 
 
74
  rows = cursor.fetchall()
 
75
  if not rows:
76
- return "هیچ تاریخچه‌ای موجود نیست."
77
- history_text = "=== تاریخچه ===\n"
78
- for row in rows:
79
- history_text += f"ID: {row[0]}\n"
80
- history_text += f"ورودی کاربر: {row[1]}\n"
81
- history_text += f"نوع کار: {row[2]}\n"
82
- history_text += f"پرامپت: {row[3]}\n"
83
- history_text += f"پاسخ: {row[4]}\n"
84
- history_text += f"زمان: {row[5]}\n"
85
- history_text += "-" * 50 + "\n"
 
 
 
86
  return history_text
 
87
  except Exception as e:
88
- logger.error(f"History retrieval error: {e}")
89
- return f"خطا در دریافت تاریخچه: {e}"
90
 
91
  # تولید کد
92
  def generate_code(text, language):
93
- logger.info(f"Processing input: {text}, language: {language}")
 
 
 
 
 
 
 
94
  try:
95
- prompt = f"Write a complete, correct, and well-explained code in {language} to: {text}"
96
- logger.info(f"Generated prompt: {prompt}")
97
- response = client.chat.completions.create(
98
- model="qwen3-coder-plus",
99
- messages=[
100
- {"role": "system", "content": "You are a coding assistant that generates complete and well-explained code."},
101
- {"role": "user", "content": prompt}
102
- ],
103
- max_tokens=1024,
104
- temperature=0.7,
105
- top_p=0.8
106
- )
107
- code_output = response.choices[0].message.content.strip()
108
-
109
- # استخراج کد از خروجی (در صورت وجود بلاک کد)
110
- lines = code_output.split('\n')
111
- code = []
112
- is_code = False
113
- for line in lines:
114
- if line.startswith("```"):
115
- is_code = not is_code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  continue
117
- elif is_code:
118
- code.append(line)
119
 
120
- final_code = "\n".join(code).strip() if code else code_output
121
- if not final_code:
122
- logger.warning("Generated code is empty")
123
- final_code = "خطا: کد تولیدشده خالی است"
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- logger.info(f"Generated code: {final_code}")
126
- return prompt, final_code
127
  except Exception as e:
128
- logger.error(f"Code generation error: {e}")
129
- return f"Error prompt: {text}", f"Code generation error: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- # تابع اصلی
132
- def christopher(user_input, language, show_history):
133
- logger.info(f"Processing input: {user_input}, language: {language}, show_history: {show_history}")
 
 
 
 
134
  try:
135
- task_type = "تولید کد"
136
- prompt, response = generate_code(user_input, language)
137
- if "error" in response.lower():
138
- history = get_history() if show_history else ""
139
- return response, history
140
- save_to_memory(user_input, task_type, prompt, response)
141
  history = get_history() if show_history else ""
142
- return response, history
 
 
 
143
  except Exception as e:
144
- logger.error(f"Processing error: {e}")
 
145
  history = get_history() if show_history else ""
146
- return f"خطا: {e}", history
147
 
148
  # رابط گرادیو
149
- def gradio_ui(user_input, language, show_history):
150
- code, history = christopher(user_input, language, show_history)
151
- return code, history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- if __name__ == "__main__":
154
- logger.info("Starting application")
 
 
155
  try:
 
156
  init_db()
157
- logger.info("Launching Gradio interface")
158
- iface = gr.Interface(
159
- fn=gradio_ui,
160
- inputs=[
161
- gr.Textbox(label="توضیح برنامه به فارسی (مثال: یک تابع اعداد زوج)"),
162
- gr.Dropdown(choices=["Python", "JavaScript", "Java", "C++"], label="زبان برنامه‌نویسی"),
163
- gr.Checkbox(label="نمایش تاریخچه درخواست‌ها", value=False)
164
- ],
165
- outputs=[
166
- gr.Textbox(label="کد تولیدشده"),
167
- gr.Textbox(label="تاریخچه درخواست‌ها")
168
- ],
169
- title="کریستوفر - دستیار کدنویسی",
170
- description="توضیح برنامه را به فارسی وارد کنید و زبان برنامه‌نویسی را انتخاب کنید. برای نمایش تاریخچه، گزینه مربوطه را تیک بزنید."
171
  )
172
- iface.launch(server_name="0.0.0.0", server_port=7860)
173
  except Exception as e:
174
- logger.error(f"Startup error: {e}")
175
- raise
 
 
 
 
13
  logger.info("Starting application setup")
14
  qwen_api_key = os.getenv("QWEN_API_KEY")
15
  if not qwen_api_key:
16
+ logger.warning("QWEN_API_KEY not found in environment variables")
17
+ # اگه API Key نباشه، ادامه بده ولی خطا نده
18
+ client = None
19
+ else:
20
+ # تنظیم کلاینت OpenAI برای DashScope
21
+ try:
22
+ client = OpenAI(
23
+ api_key=qwen_api_key,
24
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
25
+ timeout=30.0
26
+ )
27
+ logger.info(" OpenAI client initialized successfully")
28
+
29
+ # تست اتصال
30
+ try:
31
+ test_response = client.models.list()
32
+ logger.info("✅ API connection test successful")
33
+ except:
34
+ logger.warning("⚠️ API test failed but client created")
35
+
36
+ except Exception as e:
37
+ logger.error(f"❌ Failed to initialize OpenAI client: {e}")
38
+ client = None
39
 
40
  # مسیر فایل دیتابیس
41
+ DB_PATH = "christopher_history.db"
42
 
43
  # ایجاد دیتابیس
44
  def init_db():
45
+ logger.info("🗄️ Initializing database")
46
  try:
47
  with sqlite3.connect(DB_PATH) as conn:
48
  cursor = conn.cursor()
49
+ cursor.execute('''CREATE TABLE IF NOT EXISTS code_history (
50
  id INTEGER PRIMARY KEY AUTOINCREMENT,
51
+ user_input TEXT NOT NULL,
52
+ language TEXT NOT NULL,
53
+ generated_code TEXT NOT NULL,
54
+ prompt_used TEXT,
55
+ timestamp TEXT NOT NULL,
56
+ success BOOLEAN DEFAULT 1
57
  )''')
58
  conn.commit()
59
+ logger.info("Database initialized successfully")
60
  except Exception as e:
61
+ logger.error(f"Database initialization error: {e}")
 
62
 
63
  # ذخیره در دیتابیس
64
+ def save_to_db(user_input, language, generated_code, prompt_used="", success=True):
65
+ logger.info("💾 Saving to database")
66
  try:
67
  with sqlite3.connect(DB_PATH) as conn:
68
  cursor = conn.cursor()
69
+ cursor.execute("""INSERT INTO code_history
70
+ (user_input, language, generated_code, prompt_used, timestamp, success)
71
+ VALUES (?, ?, ?, ?, ?, ?)""",
72
+ (user_input, language, generated_code, prompt_used,
73
+ datetime.now().isoformat(), success))
74
  conn.commit()
75
+ logger.info(" Successfully saved to database")
76
  except Exception as e:
77
+ logger.error(f" Database save error: {e}")
 
78
 
79
  # دریافت تاریخچه
80
+ def get_history(limit=10):
81
+ logger.info("📜 Retrieving history from database")
82
  try:
83
  with sqlite3.connect(DB_PATH) as conn:
84
  cursor = conn.cursor()
85
+ cursor.execute("""SELECT id, user_input, language, generated_code, timestamp, success
86
+ FROM code_history
87
+ ORDER BY timestamp DESC
88
+ LIMIT ?""", (limit,))
89
  rows = cursor.fetchall()
90
+
91
  if not rows:
92
+ return "📝 هیچ تاریخچه‌ای موجود نیست."
93
+
94
+ history_text = f"📋 **تاریخچه آخرین {len(rows)} درخواست:**\n\n"
95
+
96
+ for i, row in enumerate(rows, 1):
97
+ status_icon = "✅" if row[5] else "❌"
98
+ history_text += f"**{i}. {status_icon} درخواست #{row[0]}**\n"
99
+ history_text += f"📝 **درخواست:** {row[1]}\n"
100
+ history_text += f"🔧 **زبان:** {row[2]}\n"
101
+ history_text += f" **زمان:** {row[4]}\n"
102
+ history_text += f"💻 **کد تولیدشده:**\n```{row[2].lower()}\n{row[3][:200]}{'...' if len(row[3]) > 200 else ''}\n```\n"
103
+ history_text += "─" * 50 + "\n\n"
104
+
105
  return history_text
106
+
107
  except Exception as e:
108
+ logger.error(f"History retrieval error: {e}")
109
+ return f"خطا در دریافت تاریخچه: {str(e)}"
110
 
111
  # تولید کد
112
  def generate_code(text, language):
113
+ logger.info(f"🚀 Generating code for: {text[:50]}... in {language}")
114
+
115
+ if client is None:
116
+ error_msg = "❌ خطا: اتصال به API برقرار نشد. لطفاً API Key را بررسی کنید."
117
+ error_code = f"# خطا در اتصال به سرویس\n# درخواست: {text}\nprint('لطفاً API Key را در تنظیمات Hugging Face اضافه کنید')"
118
+ save_to_db(text, language, error_code, error_msg, success=False)
119
+ return error_msg, error_code
120
+
121
  try:
122
+ # لیست مدل‌های مختلف برای تست
123
+ models_to_try = [
124
+ "qwen2.5-coder-32b-instruct",
125
+ "qwen-coder-plus",
126
+ "qwen2.5-coder-7b-instruct"
127
+ ]
128
+
129
+ system_prompt = f"""You are an expert {language} programmer.
130
+ Generate clean, well-documented, and executable code with proper comments.
131
+ Always include error handling where appropriate."""
132
+
133
+ user_prompt = f"""Create a complete {language} program that: {text}
134
+
135
+ Requirements:
136
+ - Write clean, readable code
137
+ - Include helpful comments (both English and Persian if helpful)
138
+ - Add proper error handling
139
+ - Make sure the code is executable
140
+ - Follow {language} best practices
141
+
142
+ Please provide only the code, no extra explanations."""
143
+
144
+ code_generated = False
145
+ response_content = ""
146
+ model_used = ""
147
+
148
+ # تلاش با مدل‌های مختلف
149
+ for model in models_to_try:
150
+ try:
151
+ logger.info(f"🔄 Trying model: {model}")
152
+ response = client.chat.completions.create(
153
+ model=model,
154
+ messages=[
155
+ {"role": "system", "content": system_prompt},
156
+ {"role": "user", "content": user_prompt}
157
+ ],
158
+ max_tokens=1500,
159
+ temperature=0.3,
160
+ )
161
+
162
+ response_content = response.choices[0].message.content.strip()
163
+ model_used = model
164
+ code_generated = True
165
+ logger.info(f"✅ Successfully used model: {model}")
166
+ break
167
+
168
+ except Exception as model_error:
169
+ logger.warning(f"⚠️ Model {model} failed: {model_error}")
170
  continue
 
 
171
 
172
+ if not code_generated:
173
+ error_msg = "❌ همه مدل‌ها شکست خوردند"
174
+ error_code = f"# خطا در تولید کد\n# درخواست: {text}\nprint('خطا در دسترسی به مدل‌های AI')"
175
+ save_to_db(text, language, error_code, error_msg, success=False)
176
+ return error_msg, error_code
177
+
178
+ # پاک‌سازی کد از markdown
179
+ final_code = clean_code_output(response_content)
180
+
181
+ if not final_code or final_code.strip() == "":
182
+ final_code = f"# کد برای: {text}\n# زبان: {language}\nprint('خوش آمدید!')"
183
+
184
+ # ذخیره در دیتابیس
185
+ save_to_db(text, language, final_code, f"Model: {model_used}", success=True)
186
+
187
+ logger.info("✅ Code generated and saved successfully")
188
+ return f"✅ کد با موفقیت تولید شد (مدل: {model_used})", final_code
189
 
 
 
190
  except Exception as e:
191
+ logger.error(f"Code generation error: {e}")
192
+ error_code = f"# خطا در تولید کد: {str(e)}\n# درخواست: {text}\n# زبان: {language}\nprint('متأسفانه خطایی رخ داد')"
193
+ save_to_db(text, language, error_code, str(e), success=False)
194
+ return f"❌ خطا: {str(e)}", error_code
195
+
196
+ def clean_code_output(code_text):
197
+ """پاک‌سازی کد از markdown و متن اضافی"""
198
+ if not code_text:
199
+ return ""
200
+
201
+ # حذف markdown code blocks
202
+ if "```" in code_text:
203
+ import re
204
+ # پیدا کردن همه بلاک‌های کد
205
+ code_blocks = re.findall(r'```(?:\w+\n)?(.*?)```', code_text, re.DOTALL)
206
+ if code_blocks:
207
+ # انتخاب بزرگترین بلاک کد
208
+ largest_block = max(code_blocks, key=len)
209
+ return largest_block.strip()
210
+
211
+ return code_text.strip()
212
 
213
+ # تابع اصلی برای پردازش درخواست
214
+ def process_request(user_input, language, show_history):
215
+ logger.info(f"📨 Processing request - Language: {language}, Show History: {show_history}")
216
+
217
+ if not user_input or not user_input.strip():
218
+ return "❌ لطفاً توضیحی برای برنامه وارد کنید.", get_history() if show_history else ""
219
+
220
  try:
221
+ # تولید کد
222
+ status_message, generated_code = generate_code(user_input, language)
223
+
224
+ # دریافت تاریخچه در صورت درخواست
 
 
225
  history = get_history() if show_history else ""
226
+
227
+ logger.info("✅ Request processed successfully")
228
+ return generated_code, history, status_message
229
+
230
  except Exception as e:
231
+ logger.error(f"Processing error: {e}")
232
+ error_response = f"# متأسفانه خطایی رخ داد: {str(e)}\nprint('لطفاً مجدداً تلاش کنید')"
233
  history = get_history() if show_history else ""
234
+ return error_response, history, f"خطا: {str(e)}"
235
 
236
  # رابط گرادیو
237
+ def create_gradio_interface():
238
+ with gr.Blocks(
239
+ theme=gr.themes.Soft(),
240
+ title="کریستوفر - دستیار کدنویسی",
241
+ css="""
242
+ .gradio-container {
243
+ font-family: 'Tahoma', sans-serif;
244
+ direction: rtl;
245
+ }
246
+ .status-success { color: #22c55e; font-weight: bold; }
247
+ .status-error { color: #ef4444; font-weight: bold; }
248
+ """
249
+ ) as demo:
250
+
251
+ gr.Markdown("""
252
+ # 🤖 کریستوفر - دستیار هوشمند کدنویسی
253
+ ### 🚀 با قدرت مدل‌های Qwen2.5-Coder
254
+
255
+ توضیح برنامه‌ای که می‌خواهید را به فارسی وارد کنید و زبان برنامه‌نویسی مورد نظر را انتخاب کنید.
256
+ """)
257
+
258
+ with gr.Row():
259
+ with gr.Column(scale=2):
260
+ user_input = gr.Textbox(
261
+ label="📝 توضیح برنامه به فارسی",
262
+ placeholder="مثال: یک تابع برای محاسبه اعداد فیبوناچی تا عدد n",
263
+ lines=4,
264
+ max_lines=8
265
+ )
266
+
267
+ with gr.Row():
268
+ language = gr.Dropdown(
269
+ choices=["Python", "JavaScript", "Java", "C++", "C#", "Go", "Rust", "PHP", "TypeScript"],
270
+ label="🔧 زبان برنامه‌نویسی",
271
+ value="Python"
272
+ )
273
+
274
+ show_history = gr.Checkbox(
275
+ label="📋 نمایش تاریخچه",
276
+ value=False
277
+ )
278
+
279
+ generate_btn = gr.Button("🚀 تولید کد", variant="primary", size="lg")
280
+
281
+ # نمایش وضعیت
282
+ status_display = gr.Markdown("آماده برای تولید کد...")
283
+
284
+ with gr.Row():
285
+ with gr.Column(scale=3):
286
+ code_output = gr.Code(
287
+ label="💻 کد تولیدشده",
288
+ language="python",
289
+ interactive=False,
290
+ show_label=True
291
+ )
292
+
293
+ with gr.Column(scale=2, visible=False) as history_column:
294
+ history_output = gr.Markdown(
295
+ label="📜 تاریخچه درخواست‌ها",
296
+ value="تاریخچه‌ای موجود نیست."
297
+ )
298
+
299
+ # تنظیم رویدادها
300
+ def update_interface(user_input, language, show_history):
301
+ code, history, status = process_request(user_input, language, show_history)
302
+
303
+ # تنظیم نمایش تاریخچه
304
+ history_visibility = gr.update(visible=show_history)
305
+
306
+ return (
307
+ code, # کد تولیدشده
308
+ history if show_history else "", # تاریخچه
309
+ status, # وضعیت
310
+ history_visibility # نمایش ستون تاریخچه
311
+ )
312
+
313
+ generate_btn.click(
314
+ fn=update_interface,
315
+ inputs=[user_input, language, show_history],
316
+ outputs=[code_output, history_output, status_display, history_column]
317
+ )
318
+
319
+ show_history.change(
320
+ fn=lambda x: gr.update(visible=x),
321
+ inputs=[show_history],
322
+ outputs=[history_column]
323
+ )
324
+
325
+ # مثال‌های نمونه
326
+ gr.Markdown("""
327
+ ### 💡 مثال‌های نمونه درخواست:
328
+
329
+ 🔢 **ریاضی:** "یک تابع برای محاسبه فاکتوریل عدد"
330
+ 📊 **داده:** "برنامه مرتب‌سازی لیست اعداد به صورت صعودی"
331
+ 🎮 **بازی:** "یک بازی حدس عدد ساده"
332
+ 📁 **فایل:** "تابعی برای خواندن و نوشتن فایل متنی"
333
+ 🌐 **وب:** "یک صفحه HTML ساده با فرم ورودی"
334
+ """)
335
+
336
+ # نمایش آمار دیتابیس
337
+ with gr.Row():
338
+ stats_btn = gr.Button("📊 نمایش آمار", size="sm")
339
+ stats_output = gr.Textbox(label="📈 آمار دیتابیس", visible=False)
340
+
341
+ def show_stats():
342
+ try:
343
+ with sqlite3.connect(DB_PATH) as conn:
344
+ cursor = conn.cursor()
345
+ cursor.execute("SELECT COUNT(*) FROM code_history")
346
+ total = cursor.fetchone()[0]
347
+
348
+ cursor.execute("SELECT COUNT(*) FROM code_history WHERE success = 1")
349
+ successful = cursor.fetchone()[0]
350
+
351
+ cursor.execute("SELECT language, COUNT(*) FROM code_history GROUP BY language ORDER BY COUNT(*) DESC")
352
+ lang_stats = cursor.fetchall()
353
+
354
+ stats = f"📊 **آمار کلی:**\n"
355
+ stats += f"🔢 **کل درخواست‌ها:** {total}\n"
356
+ stats += f"✅ **موفق:** {successful}\n"
357
+ stats += f"❌ **ناموفق:** {total - successful}\n\n"
358
+ stats += f"🔧 **زبان‌های پربازدید:**\n"
359
+
360
+ for lang, count in lang_stats:
361
+ stats += f"• {lang}: {count} درخواست\n"
362
+
363
+ return gr.update(value=stats, visible=True)
364
+ except:
365
+ return gr.update(value="خطا در نمایش آمار", visible=True)
366
+
367
+ stats_btn.click(
368
+ fn=show_stats,
369
+ inputs=[],
370
+ outputs=[stats_output]
371
+ )
372
+
373
+ return demo
374
 
375
+ # تابع اصلی برنامه
376
+ def main():
377
+ logger.info("🚀 Starting Christopher - Code Generation Assistant")
378
+
379
  try:
380
+ # مقداردهی اولیه دیتابیس
381
  init_db()
382
+
383
+ # ایجاد رابط گرادیو
384
+ demo = create_gradio_interface()
385
+
386
+ logger.info("🌐 Launching Gradio interface")
387
+ demo.launch(
388
+ server_name="0.0.0.0",
389
+ server_port=7860,
390
+ share=False,
391
+ show_error=True,
392
+ show_api=False
 
 
 
393
  )
394
+
395
  except Exception as e:
396
+ logger.error(f" Application startup error: {e}")
397
+ raise
398
+
399
+ if __name__ == "__main__":
400
+ main()