Update app.py
Browse files
app.py
CHANGED
|
@@ -15,37 +15,73 @@ import fitz # PyMuPDF
|
|
| 15 |
from PIL import Image
|
| 16 |
import io
|
| 17 |
import requests
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
-
# تكوين السجلات
|
| 20 |
logging.basicConfig(
|
| 21 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 22 |
level=logging.INFO
|
| 23 |
)
|
| 24 |
logger = logging.getLogger(__name__)
|
| 25 |
|
| 26 |
-
# التوكنات
|
| 27 |
TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
|
| 28 |
NVAPI_API_KEY = os.environ.get('NVAPI_API_KEY')
|
| 29 |
-
WEBHOOK_URL = os.environ.get('
|
| 30 |
|
| 31 |
-
# تكوين عميل NVIDIA
|
| 32 |
nvidia_client = OpenAI(
|
| 33 |
base_url="https://integrate.api.nvidia.com/v1",
|
| 34 |
api_key=NVAPI_API_KEY
|
| 35 |
)
|
| 36 |
|
| 37 |
-
# مستودع Hugging Face للمواد
|
| 38 |
REPO_ID = "Riy777/Study"
|
| 39 |
|
| 40 |
-
# حالات المحادثة
|
| 41 |
SELECTING_SUBJECT, SELECTING_ACTION, WAITING_FOR_QUESTION = range(3)
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
class MedicalLabBot:
|
| 44 |
def __init__(self):
|
| 45 |
self.conversation_memory = {}
|
| 46 |
self.available_materials = {}
|
| 47 |
self.file_cache = {}
|
| 48 |
self.load_all_materials()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
def load_all_materials(self):
|
| 51 |
"""تحميل جميع المواد والملفات من Hugging Face"""
|
|
@@ -755,37 +791,16 @@ class MedicalLabBot:
|
|
| 755 |
)
|
| 756 |
return SELECTING_ACTION
|
| 757 |
|
| 758 |
-
# إنشاء كائن البوت
|
| 759 |
bot = MedicalLabBot()
|
|
|
|
| 760 |
|
| 761 |
-
#
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
conv_handler = ConversationHandler(
|
| 766 |
-
entry_points=[CommandHandler('start', bot.start)],
|
| 767 |
-
states={
|
| 768 |
-
SELECTING_SUBJECT: [
|
| 769 |
-
CallbackQueryHandler(bot.handle_subject_selection, pattern='^subject_|general_help|refresh_materials$')
|
| 770 |
-
],
|
| 771 |
-
SELECTING_ACTION: [
|
| 772 |
-
CallbackQueryHandler(bot.handle_action_selection),
|
| 773 |
-
CallbackQueryHandler(bot.handle_subject_selection, pattern='^subject_')
|
| 774 |
-
],
|
| 775 |
-
WAITING_FOR_QUESTION: [
|
| 776 |
-
MessageHandler(filters.TEXT & ~filters.COMMAND, bot.handle_message)
|
| 777 |
-
]
|
| 778 |
-
},
|
| 779 |
-
fallbacks=[CommandHandler('start', bot.start)]
|
| 780 |
-
)
|
| 781 |
-
|
| 782 |
-
application.add_handler(conv_handler)
|
| 783 |
-
application.add_handler(CallbackQueryHandler(bot.handle_callback_query, pattern='^more_questions|change_subject|back_to_actions$'))
|
| 784 |
-
|
| 785 |
-
async def setup_webhook():
|
| 786 |
-
"""إعداد Webhook للبوت"""
|
| 787 |
if WEBHOOK_URL:
|
| 788 |
-
await application.bot.set_webhook(
|
| 789 |
url=f"{WEBHOOK_URL}/telegram",
|
| 790 |
allowed_updates=Update.ALL_TYPES
|
| 791 |
)
|
|
@@ -793,7 +808,59 @@ async def setup_webhook():
|
|
| 793 |
else:
|
| 794 |
logger.warning("WEBHOOK_URL not set, using polling instead")
|
| 795 |
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
from PIL import Image
|
| 16 |
import io
|
| 17 |
import requests
|
| 18 |
+
from fastapi import FastAPI, Request, HTTPException
|
| 19 |
+
from fastapi.responses import HTMLResponse
|
| 20 |
+
import uvicorn
|
| 21 |
|
| 22 |
+
# ========== تكوين السجلات ==========
|
| 23 |
logging.basicConfig(
|
| 24 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 25 |
level=logging.INFO
|
| 26 |
)
|
| 27 |
logger = logging.getLogger(__name__)
|
| 28 |
|
| 29 |
+
# ========== التوكنات ومتغيرات البيئة ==========
|
| 30 |
TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
|
| 31 |
NVAPI_API_KEY = os.environ.get('NVAPI_API_KEY')
|
| 32 |
+
WEBHOOK_URL = os.environ.get('SPACE_URL', '')
|
| 33 |
|
| 34 |
+
# ========== تكوين عميل NVIDIA ==========
|
| 35 |
nvidia_client = OpenAI(
|
| 36 |
base_url="https://integrate.api.nvidia.com/v1",
|
| 37 |
api_key=NVAPI_API_KEY
|
| 38 |
)
|
| 39 |
|
| 40 |
+
# ========== مستودع Hugging Face للمواد ==========
|
| 41 |
REPO_ID = "Riy777/Study"
|
| 42 |
|
| 43 |
+
# ========== حالات المحادثة ==========
|
| 44 |
SELECTING_SUBJECT, SELECTING_ACTION, WAITING_FOR_QUESTION = range(3)
|
| 45 |
|
| 46 |
+
# ========== تطبيق FastAPI ==========
|
| 47 |
+
app = FastAPI(title="Medical Lab Bot", version="1.0.0")
|
| 48 |
+
|
| 49 |
+
# ========== فئة البوت الرئيسية ==========
|
| 50 |
class MedicalLabBot:
|
| 51 |
def __init__(self):
|
| 52 |
self.conversation_memory = {}
|
| 53 |
self.available_materials = {}
|
| 54 |
self.file_cache = {}
|
| 55 |
self.load_all_materials()
|
| 56 |
+
self.application = None
|
| 57 |
+
|
| 58 |
+
def initialize_application(self):
|
| 59 |
+
"""تهيئة تطبيق التليجرام"""
|
| 60 |
+
if not self.application:
|
| 61 |
+
self.application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
|
| 62 |
+
self.setup_handlers()
|
| 63 |
+
|
| 64 |
+
def setup_handlers(self):
|
| 65 |
+
"""إعداد معالجات التليجرام"""
|
| 66 |
+
conv_handler = ConversationHandler(
|
| 67 |
+
entry_points=[CommandHandler('start', self.start)],
|
| 68 |
+
states={
|
| 69 |
+
SELECTING_SUBJECT: [
|
| 70 |
+
CallbackQueryHandler(self.handle_subject_selection, pattern='^subject_|general_help|refresh_materials$')
|
| 71 |
+
],
|
| 72 |
+
SELECTING_ACTION: [
|
| 73 |
+
CallbackQueryHandler(self.handle_action_selection),
|
| 74 |
+
CallbackQueryHandler(self.handle_subject_selection, pattern='^subject_')
|
| 75 |
+
],
|
| 76 |
+
WAITING_FOR_QUESTION: [
|
| 77 |
+
MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_message)
|
| 78 |
+
]
|
| 79 |
+
},
|
| 80 |
+
fallbacks=[CommandHandler('start', self.start)]
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
self.application.add_handler(conv_handler)
|
| 84 |
+
self.application.add_handler(CallbackQueryHandler(self.handle_callback_query, pattern='^more_questions|change_subject|back_to_actions$'))
|
| 85 |
|
| 86 |
def load_all_materials(self):
|
| 87 |
"""تحميل جميع المواد والملفات من Hugging Face"""
|
|
|
|
| 791 |
)
|
| 792 |
return SELECTING_ACTION
|
| 793 |
|
| 794 |
+
# ========== إنشاء كائن البوت ==========
|
| 795 |
bot = MedicalLabBot()
|
| 796 |
+
bot.initialize_application()
|
| 797 |
|
| 798 |
+
# ========== دوال FastAPI ==========
|
| 799 |
+
@app.on_event("startup")
|
| 800 |
+
async def on_startup():
|
| 801 |
+
"""إعداد Webhook عند بدء التشغيل"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
if WEBHOOK_URL:
|
| 803 |
+
await bot.application.bot.set_webhook(
|
| 804 |
url=f"{WEBHOOK_URL}/telegram",
|
| 805 |
allowed_updates=Update.ALL_TYPES
|
| 806 |
)
|
|
|
|
| 808 |
else:
|
| 809 |
logger.warning("WEBHOOK_URL not set, using polling instead")
|
| 810 |
|
| 811 |
+
@app.get("/", response_class=HTMLResponse)
|
| 812 |
+
async def root():
|
| 813 |
+
"""الصفحة الرئيسية"""
|
| 814 |
+
return """
|
| 815 |
+
<html>
|
| 816 |
+
<head>
|
| 817 |
+
<title>Medical Lab Bot</title>
|
| 818 |
+
<style>
|
| 819 |
+
body { font-family: Arial, sans-serif; margin: 40px; }
|
| 820 |
+
.container { max-width: 800px; margin: 0 auto; }
|
| 821 |
+
.status { padding: 20px; background: #f0f8ff; border-radius: 10px; }
|
| 822 |
+
</style>
|
| 823 |
+
</head>
|
| 824 |
+
<body>
|
| 825 |
+
<div class="container">
|
| 826 |
+
<h1>🏥 بوت المختبرات الطبية الذكي</h1>
|
| 827 |
+
<div class="status">
|
| 828 |
+
<h2>✅ البوت يعمل بنجاح</h2>
|
| 829 |
+
<p>البوت متصل بـ Telegram وجاهز لاستقبال الرسائل.</p>
|
| 830 |
+
<p>استخدم الرابط التالي للتواصل مع البوت:</p>
|
| 831 |
+
<p><strong>https://t.me/your_bot_username</strong></p>
|
| 832 |
+
</div>
|
| 833 |
+
<h3>المميزات:</h3>
|
| 834 |
+
<ul>
|
| 835 |
+
<li>📚 شرح المواد الدراسية من ملفات PDF وWord</li>
|
| 836 |
+
<li>❓ توليد أسئلة متنوعة للمراجعة</li>
|
| 837 |
+
<li>📖 تلخيص المحتوى الدراسي</li>
|
| 838 |
+
<li>🧪 تفسير المفاهيم العلمية</li>
|
| 839 |
+
<li>🎯 اختبار الفهم</li>
|
| 840 |
+
</ul>
|
| 841 |
+
</div>
|
| 842 |
+
</body>
|
| 843 |
+
</html>
|
| 844 |
+
"""
|
| 845 |
+
|
| 846 |
+
@app.post("/telegram")
|
| 847 |
+
async def handle_telegram_update(request: Request):
|
| 848 |
+
"""معالجة تحديثات Telegram"""
|
| 849 |
+
try:
|
| 850 |
+
update_data = await request.json()
|
| 851 |
+
update = Update.de_json(update_data, bot.application.bot)
|
| 852 |
+
await bot.application.process_update(update)
|
| 853 |
+
return {"status": "ok"}
|
| 854 |
+
except Exception as e:
|
| 855 |
+
logger.error(f"Error processing update: {e}")
|
| 856 |
+
raise HTTPException(status_code=400, detail="Invalid update")
|
| 857 |
+
|
| 858 |
+
@app.get("/health")
|
| 859 |
+
async def health_check():
|
| 860 |
+
"""فحص صحة الخدمة"""
|
| 861 |
+
return {"status": "healthy", "service": "medical-lab-bot"}
|
| 862 |
+
|
| 863 |
+
# ========== التشغيل الرئيسي ==========
|
| 864 |
+
if __name__ == "__main__":
|
| 865 |
+
port = int(os.environ.get("PORT", 7860))
|
| 866 |
+
uvicorn.run(app, host="0.0.0.0", port=port)
|