turns-00079.parquet:38289
63650dd97169c16fe03e45d1degenerate_repetitionAbsentFinal dense release
Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.
63650dd97169c16fe03e45d1User: hi, how are you? User: hi, how are you? Assistant:
Hello! I'm doing well, thank you. How can I assist you today?
6017c85c3a25e5a50ebeee88User: acara jumpa fans dimana saja User: acara jumpa fans dimana saja Assistant:
Acara jumpa fans biasanya diadakan di berbagai tempat, antara lain: 1. Mall atau pusat perbelanjaan 2. Aula atau gedung serbaguna 3. Kafe atau restoran yang memiliki area khusus 4. Studio televisi atau radio saat acara siaran langsung 5. Tempat konser atau festival musik 6. Event khusus seperti peluncuran album, film, atau produk 7. Convention center atau pameran Jika kamu ingin tahu jadwal atau lokasi jumpa fans dari artis tertentu, biasanya informasi tersebut diumumkan di media sosial resmi artis atau melalui situs resmi penyelenggara acara. Apakah kamu mencari informasi jumpa fans dari artis atau grup tertentu?
f31aa9f06cb152d5b35ddddeUser: Setiap suara di alam semesta terdengar oleh Allah SWT. Pendengaran-Nya tidak terbatas, tidak ada satu suarapun yang luput dari-Nya. Dalam hal ini Allah SWT memiliki sifat……... * 2 points Al-Sami Al-Basir Al-Alim Al-Khabir 2. Untuk membuktikan kebenaran Allah SWt. Dapat dipergunakan dalil naqli dan dalil aqli. Dalil naqli adalah dalil yang berdasarkan…….. * 2 points Pemikiran yang matang Pendapat cendikiawan Al-Qur’an dan hadist Hukum yang berlaku 3. Orang yang melaksanakan sholat semata-mata karena Allah Swt, dan berkeinginan hanya untuk menggapai keridhoannnya. Merupakan perwujudan dari salah satu sasaran tujuan melaksanakan salat yaitu…….. * 2 points Timbulnya keinkhlasan Timbulnya ketaqwaan kepada Allah Swt Adanya perasaan nyaman dan tentram Timbulnya kekacauan 4. Berikut ini hikmah salat fardu dalam menjadi kehidupan, kecuali……… * 2 points Membiasakan disiplin Membiasakan hidup bersosial Mendapatkan kebahagiaan dunia Saran pembentukan kepribadian muslim 5. Ketika sedang melakukan salat magrib ransi ragu terhadapa jumlah rakaatnya, sehingga sebelum salam ia melakukan sujud…… * 2 points Tilawah Syukur Sujud rukun Sahwi 6. Pada saat menerima pengumuman hasil ujian seorang siswa SMP ternyata memperoleh nilai yang memuaskan. Sebagai seorang seorang muslim yang baik, disunahkan untuk mengerjakan sujud……. * 2 points Syukur Tilawah Sahwi Rukun 7. Angga mengerjakan soal ujian tanpa menyontek, walaupun banyak kesempatan dan tidak ada pengawas di ruangan. Sikap tersebut menunjukkan bahwa ia beriman kepada malaikat…….. * 2 points Jibril Mikail Rakib dan Atid Israfil 8. Kita harus sesalu melaksanakan semua perintah Allah Swt. Dan menjauhi segala larangan-nya agar di akhirat dapat balasan surganya Allah Swt. Hal ini cerminan dari iman kepada malaikat……….. * 2 points Ridwan Jibril MIkail Israfil 9. Membicaarakan Aib yang ada pada diri seseorang dengan maksud untuk merendahkan harga dirinya dinamakan……. * 2 points Hasud Gibah Dendam Buruk Sangka 10. Ketika mendengar berita dari media sosial yang merugikan kita, sikap kita adalah……….. * 2 points Menerima berita dengan senang hati Mencari sumber berita tersebut Marah dengan yang memberikan berita Mengklarifikasi berita tersebut terlebih dahulu 11. Salah satu sifat terpuji Nabi Muhammad SAW adalah tabligh. Arti dari tabligh adalah... * 2 points Jujur dapat di percaya Menyampaikan cerdas 12. Perintah untuk menuntut ilmu tercantum dalam Al-Qur’an surat... * 2 points Al-Falaq Al-‘Alaq Al-Kautsar Al-Ikhlas 13. Tujuan utama Allah SWT menurunkan rasul kepada umat manusia adalah... * 2 points Menjadi pemimpin negara Menjelaskan hukum-hukum dunia Memberi kabar gembira dan peringatan Mengetahui sejarah dunia 14. Iman kepada rasul termasuk rukun iman yang ke... * 2 points 1 2 3 4 15. Rasul yang pertama kali menerima wahyu berupa kitab adalah... * 2 points Nabi Musa AS Nabi Isa AS Nabi Muhammad SAW Nabi Ibrahim AS 16. Perilaku yang mencerminkan iman kepada rasul adalah... * 2 points suka mencontek saat ujian Meneladani akhlak Rasulullah SAW Malas beribadah Memusuhi teman yang berbeda agama 17. Nabi yang mendapat gelar Khalilullah adalah... * 2 points Nabi Nuh AS Nabi Isa AS Nabi Ibrahim AS Nabi Muhammad SAW 18. Nabi Muhammad SAW diangkat menjadi rasul pada usia... * 2 points 25 tahun 30 tahun 35 tahun 40 tahun 19. Berikut ini adalah contoh sikap toleransi dalam kehidupan sehari-hari, kecuali... * 2 points Menghargai teman yang berbeda agama saat mereka beribadah Menyela ibadah teman karena ingin bermain Mengucapkan selamat kepada teman saat hari rayanya Menghormati perbedaan pendapat dalam diskusi 20. Toleransi dalam Islam berarti... * 2 points Menyamakan semua ajaran agama Membiarkan orang lain melakukan kesalahan Menghormati perbedaan tanpa meninggalkan keyakinan sendiri Mengikuti semua tradisi yang berbeda 21. Bacaan nun mati atau tanwin yang dibaca jelas dan tidak berdengung disebut... * 2 points Idgham idzhar ikhfa iklab 22. Contoh bacaan ikhfa adalah... * 2 points مِنْ رَبِّهِمْ مَنْ يَقُولُ أَنْعَمْتَ مِنْ بَعْدِ 23. Hukum bacaan nun mati apabila bertemu huruf-huruf idgham adalah... * 2 points Dibaca jelas Dibaca samar Dimasukkan Dibalik 24. Di bawah ini merupakan huruf-huruf idgham bighunnah, kecuali... * 2 points ي م ن و 25. Hukum bacaan nun mati pada lafal "مِنْ بَعْدِ" adalah... * 2 points iklab ikhfa idghom idzhar 26. Salah satu manfaat menuntut ilmu menurut ajaran Islam adalah... * 2 points Memperoleh kekayaan secara cepat Meninggikan derajat seseorang di sisi Allah Menjadi terkenal di masyarakat Bisa membantah orang lain 27. Ayat pertama yang turun kepada Nabi Muhammad SAW berisi perintah untuk... * 2 points bergadang sholat beribadah membaca 28. Salah satu tanda orang yang meyakini hari akhir adalah... * 2 points Selalu mengejar kesenangan dunia Menjaga amal dan menjauhi maksiat Tidak peduli pada ibadah Menunda-nunda kebaikan 29. Hari akhir disebut juga dengan hari pembalasan karena... * 2 points Semua orang akan kembali muda Semua amalan manusia akan dibalas Dunia akan menjadi lebih indah Waktu akan berhenti berjalan 30. Meyakini datangnya hari akhir dapat menumbuhkan sikap... * 2 points Serakah dalam mencari harta Putus asa terhadap masa depan Tanggung jawab dan mawas diri Takut bersaing dengan orang lain 31. Salah satu adab berbicara dalam Islam adalah... * 2 points Menaikkan suara agar didengar Menghina lawan bicara jika salah Berkata benar dan tidak menyakiti Menyela pembicaraan orang lain 32. Etika pergaulan terhadap lawan jenis yang benar menurut Islam adalah... * 2 points Bebas bergaul asal tidak berduaan Menjaga pandangan dan sikap sopan Saling bersentuhan jika sudah akrab Tidak perlu membatasi hubungan 33. Firman Allah dalam QS. Al-Hujurat ayat 11 melarang kita untuk... * 2 points Berpuasa tanpa sahur Berdebat dengan keras Mengolok-olok dan mencela orang lain Bertanya tentang hal ghaib 34. Dampak dari komunikasi yang baik dalam pergaulan adalah... 2 points Mudah dipengaruhi pergaulan bebas Dijauhi karena terlalu serius Terjalinnya hubungan harmonis dan damai Sering terjadi konflik dan salah paham 35. Mengapa kita dianjurkan untuk melaksanakan akikah setelah kelahiran anak...... * 2 points Sebagai bentuk pesta untuk keluarga Agar anak cepat tumbuh besar Sebagai bentuk rasa syukur kepada Allah Untuk menunjukkan kekayaan orang tua 36. Apa persamaan dari akikah dan kurban? * 2 points Dilakukan di bulan Ramadan Wujud syukur dan saling berbagi kepada sesama Sebagai bentuk pengorbanan pribadi Keduanya hanya wajib bagi laki-laki 37. Hewan yang disembelih untuk aqiqah adalah...... 2 points Kambing atau domba sapi dan unta ayam dan kambing sapi dan kerbau 38. Berapa jumlah kambing yang disunnahkan untuk anak laki-laki dalam aqiqah..... * 2 points 1 ekor 2 ekor 3 ekor 4 ekor 39. Kapan waktu yang paling utama untuk melaksanakan aqiqah.......... * 2 points hari ke 6 hari ke 7 hari ke 8 hari ke 9 40. Salah satu sunnah ketika melakukan aqiqah adalah........ * 2 points Memandikan anak dengan air zam-zam Memberi nama anak dan mencukur rambutnya Mengundang semua warga desa Memberikan susu kepada anak yatim 41. Apa yang menjadi ciri utama sistem pemerintahan Daulah Utsmaniyah....... * 2 points Monarki absolut Demokrasi langsung Khilafah Islamiyah Republik parlementer 42. Siapakah pendiri Daulah Utsmaniyah........ * 2 points Sultan Mehmed II Osman I Selim I Murad II 43. Kota manakah yang ditaklukkan oleh Sultan Mehmed II dan dijadikan ibu kota Daulah Utsmaniyah..... * 2 points Damaskus Konstatinopel Baghdad Kairo 44. Arti dari qada secara bahasa adalah… * 2 points Ukuran ketentuan balasan takdir 45. Meyakini bahwa segala sesuatu yang terjadi di dunia ini telah ditetapkan oleh Allah SWT termasuk dalam… * 2 points Rukun Islam rukun iman Hukum syariat ilmu kalam 46. Ciri utama seni dalam Islam adalah… * 2 points Bebas tanpa batas Meniru seni Barat Menjaga nilai-nilai tauhid dan etika Islam Mengagungkan manusia 47. Gaya arsitektur masjid yang khas dalam seni Islam ditandai dengan… * 2 points Patung-patung salib Kubah dan menara Lukisan makhluk hidup 48. Mazhab yang dikenal paling luas diikuti di wilayah Asia Tenggara adalah... * 2 points Hanafi maliki Syafi’i hambali 49. Mazhab Hanafi banyak dianut di wilayah... * 2 points Afrika Utara India, Pakistan, Turki Indonesia dan Malaysia Arab Saudi 50. Manakah dari imam berikut yang hidup paling awal.......... * 2 points Imam Abu Hanifah Imam Syafi’i Imam Malik Imam Ahmad bin Hanbal User: Setiap suara di alam semesta terdengar oleh Allah SWT. Pendengaran-Nya tidak terbatas, tidak ada satu suarapun yang luput dari-Nya. Dalam hal ini Allah SWT memiliki sifat……... * 2 points Al-Sami Al-Basir Al-Alim Al-Khabir 2. Untuk membuktikan kebenaran Allah SWt. Dapat dipergunakan dalil naqli dan dalil aqli. Dalil naqli adalah dalil yang berdasarkan…….. * 2 points Pemikiran yang matang Pendapat cendikiawan Al-Qur’an dan hadist Hukum yang berlaku 3. Orang yang melaksanakan sholat semata-mata karena Allah Swt, dan berkeinginan hanya untuk menggapai keridhoannnya. Merupakan perwujudan dari salah satu sasaran tujuan melaksanakan salat yaitu…….. * 2 points Timbulnya keinkhlasan Timbulnya ketaqwaan kepada Allah Swt Adanya perasaan nyaman dan tentram Timbulnya kekacauan 4. Berikut ini hikmah salat fardu dalam menjadi kehidupan, kecuali……… * 2 points Membiasakan disiplin Membiasakan hidup bersosial Mendapatkan kebahagiaan dunia Saran pembentukan kepribadian muslim 5. Ketika sedang melakukan salat magrib ransi ragu terhadapa jumlah rakaatnya, sehingga sebelum salam ia melakukan sujud…… * 2 points Tilawah Syukur Sujud rukun Sahwi 6. Pada saat menerima pengumuman hasil ujian seorang siswa SMP ternyata memperoleh nilai yang memuaskan. Sebagai seorang seorang muslim yang baik, disunahkan untuk mengerjakan sujud……. * 2 points Syukur Tilawah Sahwi Rukun 7. Angga mengerjakan soal ujian tanpa menyontek, walaupun banyak kesempatan dan tidak ada pengawas di ruangan. Sikap tersebut menunjukkan bahwa ia beriman kepada malaikat…….. * 2 points Jibril Mikail Rakib dan Atid Israfil 8. Kita harus sesalu melaksanakan semua perintah Allah Swt. Dan menjauhi segala larangan-nya agar di akhirat dapat balasan surganya Allah Swt. Hal ini cerminan dari iman kepada malaikat……….. * 2 points Ridwan Jibril MIkail Israfil 9. Membicaarakan Aib yang ada pada diri seseorang dengan maksud untuk merendahkan harga dirinya dinamakan……. * 2 points Hasud Gibah Dendam Buruk Sangka 10. Ketika mendengar berita dari media sosial yang merugikan kita, sikap kita adalah……….. * 2 points Menerima berita dengan senang hati Mencari sumber berita tersebut Marah dengan yang memberikan berita Mengklarifikasi berita tersebut terlebih dahulu 11. Salah satu sifat terpuji Nabi Muhammad SAW adalah tabligh. Arti dari tabligh adalah... * 2 points Jujur dapat di percaya Menyampaikan cerdas 12. Perintah untuk menuntut ilmu tercantum dalam Al-Qur’an surat... * 2 points Al-Falaq Al-‘Alaq Al-Kautsar Al-Ikhlas 13. Tujuan utama Allah SWT menurunkan rasul kepada umat manusia adalah... * 2 points Menjadi pemimpin negara Menjelaskan hukum-hukum dunia Memberi kabar gembira dan peringatan Mengetahui sejarah dunia 14. Iman kepada rasul termasuk rukun iman yang ke... * 2 points 1 2 3 4 15. Rasul yang pertama kali menerima wahyu berupa kitab adalah... * 2 points Nabi Musa AS Nabi Isa AS Nabi Muhammad SAW Nabi Ibrahim AS 16. Perilaku yang mencerminkan iman kepada rasul adalah... * 2 points suka mencontek saat ujian Meneladani akhlak Rasulullah SAW Malas beribadah Memusuhi teman yang berbeda agama 17. Nabi yang mendapat gelar Khalilullah adalah... * 2 points Nabi Nuh AS Nabi Isa AS Nabi Ibrahim AS Nabi Muhammad SAW 18. Nabi Muhammad SAW diangkat menjadi rasul pada usia... * 2 points 25 tahun 30 tahun 35 tahun 40 tahun 19. Berikut ini adalah contoh sikap toleransi dalam kehidupan sehari-hari, kecuali... * 2 points Menghargai teman yang berbeda agama saat mereka beribadah Menyela ibadah teman karena ingin bermain Mengucapkan selamat kepada teman saat hari rayanya Menghormati perbedaan pendapat dalam diskusi 20. Toleransi dalam Islam berarti... * 2 points Menyamakan semua ajaran agama Membiarkan orang lain melakukan kesalahan Menghormati perbedaan tanpa meninggalkan keyakinan sendiri Mengikuti semua tradisi yang berbeda 21. Bacaan nun mati atau tanwin yang dibaca jelas dan tidak berdengung disebut... * 2 points Idgham idzhar ikhfa iklab 22. Contoh bacaan ikhfa adalah... * 2 points مِنْ رَبِّهِمْ مَنْ يَقُولُ أَنْعَمْتَ مِنْ بَعْدِ 23. Hukum bacaan nun mati apabila bertemu huruf-huruf idgham adalah... * 2 points Dibaca jelas Dibaca samar Dimasukkan Dibalik 24. Di bawah ini merupakan huruf-huruf idgham bighunnah, kecuali... * 2 points ي م ن و 25. Hukum bacaan nun mati pada lafal "مِنْ بَعْدِ" adalah... * 2 points iklab ikhfa idghom idzhar 26. Salah satu manfaat menuntut ilmu menurut ajaran Islam adalah... * 2 points Memperoleh kekayaan secara cepat Meninggikan derajat seseorang di sisi Allah Menjadi terkenal di masyarakat Bisa membantah orang lain 27. Ayat pertama yang turun kepada Nabi Muhammad SAW berisi perintah untuk... * 2 points bergadang sholat beribadah membaca 28. Salah satu tanda orang yang meyakini hari akhir adalah... * 2 points Selalu mengejar kesenangan dunia Menjaga amal dan menjauhi maksiat Tidak peduli pada ibadah Menunda-nunda kebaikan 29. Hari akhir disebut juga dengan hari pembalasan karena... * 2 points Semua orang akan kembali muda Semua amalan manusia akan dibalas Dunia akan menjadi lebih indah Waktu akan berhenti berjalan 30. Meyakini datangnya hari akhir dapat menumbuhkan sikap... * 2 points Serakah dalam mencari harta Putus asa terhadap masa depan Tanggung jawab dan mawas diri Takut bersaing dengan orang lain 31. Salah satu adab berbicara dalam Islam adalah... * 2 points Menaikkan suara agar didengar Menghina lawan bicara jika salah Berkata benar dan tidak menyakiti Menyela pembicaraan orang lain 32. Etika pergaulan terhadap lawan jenis yang benar menurut Islam adalah... * 2 points Bebas bergaul asal tidak berduaan Menjaga pandangan dan sikap sopan Saling bersentuhan jika sudah akrab Tidak perlu membatasi hubungan 33. Firman Allah dalam QS. Al-Hujurat ayat 11 melarang kita untuk... * 2 points Berpuasa tanpa sahur Berdebat dengan keras Mengolok-olok dan mencela orang lain Bertanya tentang hal ghaib 34. Dampak dari komunikasi yang baik dalam pergaulan adalah... 2 points Mudah dipengaruhi pergaulan bebas Dijauhi karena terlalu serius Terjalinnya hubungan harmonis dan damai Sering terjadi konflik dan salah paham 35. Mengapa kita dianjurkan untuk melaksanakan akikah setelah kelahiran anak...... * 2 points Sebagai bentuk pesta untuk keluarga Agar anak cepat tumbuh besar Sebagai bentuk rasa syukur kepada Allah Untuk menunjukkan kekayaan orang tua 36. Apa persamaan dari akikah dan kurban? * 2 points Dilakukan di bulan Ramadan Wujud syukur dan saling berbagi kepada sesama Sebagai bentuk pengorbanan pribadi Keduanya hanya wajib bagi laki-laki 37. Hewan yang disembelih untuk aqiqah adalah...... 2 points Kambing atau domba sapi dan unta ayam dan kambing sapi dan kerbau 38. Berapa jumlah kambing yang disunnahkan untuk anak laki-laki dalam aqiqah..... * 2 points 1 ekor 2 ekor 3 ekor 4 ekor 39. Kapan waktu yang paling utama untuk melaksanakan aqiqah.......... * 2 points hari ke 6 hari ke 7 hari ke 8 hari ke 9 40. Salah satu sunnah ketika melakukan aqiqah adalah........ * 2 points Memandikan anak dengan air zam-zam Memberi nama anak dan mencukur rambutnya Mengundang semua warga desa Memberikan susu kepada anak yatim 41. Apa yang menjadi ciri utama sistem pemerintahan Daulah Utsmaniyah....... * 2 points Monarki absolut Demokrasi langsung Khilafah Islamiyah Republik parlementer 42. Siapakah pendiri Daulah Utsmaniyah........ * 2 points Sultan Mehmed II Osman I Selim I Murad II 43. Kota manakah yang ditaklukkan oleh Sultan Mehmed II dan dijadikan ibu kota Daulah Utsmaniyah..... * 2 points Damaskus Konstatinopel Baghdad Kairo 44. Arti dari qada secara bahasa adalah… * 2 points Ukuran ketentuan balasan takdir 45. Meyakini bahwa segala sesuatu yang terjadi di dunia ini telah ditetapkan oleh Allah SWT termasuk dalam… * 2 points Rukun Islam rukun iman Hukum syariat ilmu kalam 46. Ciri utama seni dalam Islam adalah… * 2 points Bebas tanpa batas Meniru seni Barat Menjaga nilai-nilai tauhid dan etika Islam Mengagungkan manusia 47. Gaya arsitektur masjid yang khas dalam seni Islam ditandai dengan… * 2 points Patung-patung salib Kubah dan menara Lukisan makhluk hidup 48. Mazhab yang dikenal paling luas diikuti di wilayah Asia Tenggara adalah... * 2 points Hanafi maliki Syafi’i hambali 49. Mazhab Hanafi banyak dianut di wilayah... * 2 points Afrika Utara India, Pakistan, Turki Indonesia dan Malaysia Arab Saudi 50. Manakah dari imam berikut yang hidup paling awal.......... * 2 points Imam Abu Hanifah Imam Syafi’i Imam Malik Imam Ahmad bin Hanbal Assistant:
Berikut adalah jawaban untuk pertanyaan yang Anda berikan: 1. **Al-Sami** 2. **Al-Qur’an dan hadist** 3. **Timbulnya keikhlasan** 4. **Mendapatkan kebahagiaan dunia** 5. **Sahwi** 6. **Syukur** 7. **Rakib dan Atid** 8. **Ridwan** 9. **Gibah** 10. **Mengklarifikasi berita tersebut terlebih dahulu** 11. **Menyampaikan** 12. **Al-‘Alaq** 13. **Memberi kabar gembira dan peringatan** 14. **2** 15. **Nabi Musa AS** 16. **Meneladani akhlak Rasulullah SAW** 17. **Nabi Ibrahim AS** 18. **40 tahun** 19. **Menyela ibadah teman karena ingin bermain** 20. **Menghormati perbedaan tanpa meninggalkan keyakinan sendiri** 21. **idzhar** 22. **مِنْ رَبِّهِمْ** 23. **Dimasukkan** 24. **ن** 25. **ikhfa** 26. **Meninggikan derajat seseorang di sisi Allah** 27. **membaca** 28. **Menjaga amal dan menjauhi maksiat** 29. **Semua amalan manusia akan dibalas** 30. **Tanggung jawab dan mawas diri** 31. **Berkata benar dan tidak menyakiti** 32. **Menjaga pandangan dan sikap sopan** 33. **Mengolok-olok dan mencela orang lain** 34. **Terjalinnya hubungan harmonis dan damai** 35. **Sebagai bentuk rasa syukur kepada Allah** 36. **Wujud syukur dan saling berbagi kepada sesama** 37. **Kambing atau domba** 38. **2 ekor** 39. **hari ke 7** 40. **Memberi nama anak dan mencukur rambutnya** 41. **Khilafah Islamiyah** 42. **Osman I** 43. **Konstatinopel** 44. **ketentuan** 45. **rukun iman** 46. **Menjaga nilai-nilai tauhid dan etika Islam** 47. **Kubah dan menara** 48. **Syafi’i** 49. **India, Pakistan, Turki** 50. **Imam Abu Hanifah** Semoga membantu! Jika ada pertanyaan tambahan, silakan ditanyakan.
767ba7b9ef23b3b5f8e25626hola
¡Hola! ¿En qué puedo ayudarte hoy?
e7a402a58bc2861b77ce9cceاريد اضافة باقي الاوقات
import requests
from bs4 import BeautifulSoup
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (ApplicationBuilder, CommandHandler, MessageHandler,
ContextTypes, filters, CallbackQueryHandler,
ConversationHandler)
import logging
import json
import os
from datetime import datetime, timedelta
import pytz
from tabulate import tabulate
# Flask و threading لخدمة الويب
from flask import Flask
import threading
app = Flask('')
@app.route('/')
def home():
return "Bot is alive!"
def run():
app.run(host="0.0.0.0", port=8080)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
ADD_NUMBER, DELETE_NUMBER, SCHEDULE_HOUR = range(3)
SAVED_NUMBERS_FILE = "saved_numbers.json"
SCHEDULED_TIMES_FILE = "scheduled_times.json"
YEMEN_TZ = pytz.timezone('Asia/Aden')
# --- التعديل: التحميل وحفظ حسب chat_id ---
def load_saved_numbers():
if os.path.exists(SAVED_NUMBERS_FILE):
try:
with open(SAVED_NUMBERS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأرقام المحفوظة: {e}")
return {}
else:
return {}
def load_scheduled_times():
if os.path.exists(SCHEDULED_TIMES_FILE):
try:
with open(SCHEDULED_TIMES_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأوقات المجدولة: {e}")
return {}
else:
return {}
def save_numbers_to_file(numbers):
try:
with open(SAVED_NUMBERS_FILE, 'w', encoding='utf-8') as f:
json.dump(numbers, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأرقام المحفوظة: {e}")
def save_scheduled_times(times):
try:
with open(SCHEDULED_TIMES_FILE, 'w', encoding='utf-8') as f:
json.dump(times, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأوقات المجدولة: {e}")
saved_numbers_all = load_saved_numbers()
scheduled_times = load_scheduled_times()
scheduled_jobs = {}
ADSL_URL = "https://adsl-yemen.com/adsl4.php"
def get_adsl_info(phone_number):
try:
data = {"mobile": phone_number, "action": "query"}
response = requests.post(ADSL_URL, data=data)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
results = soup.find_all("div", class_="result-box")
data_dict = {}
for box in results:
title_div = box.find("div", class_="result-title")
value_div = box.find("div", class_="result-value")
if title_div and value_div:
title = title_div.text.strip()
value = value_div.text.strip()
data_dict[title] = value
data_dict['timestamp'] = datetime.now(YEMEN_TZ).strftime("%Y-%m-%d %H:%M:%S")
return data_dict
else:
return None
except Exception as e:
logger.error(f"حدث خطأ أثناء استعلام الرصيد: {e}")
return None
async def send_balance_info(update, phone_number, info):
if info:
response = (
f"🌟 *نتائج استعلام رصيد ADSL*\n"
f"══════════════════════════\n"
f"📱 *الرقم:* `{phone_number}`\n\n"
f"💳 *الرصيد الحالي:* `{info.get('الرصيد الحالي', 'غير متوفر')}`\n"
f"📦 *قيمة الباقة:* `{info.get('قيمة الباقة', 'غير متوفر')}`\n"
f"⏳ *تاريخ الانتهاء:* `{info.get('تاريخ الانتهاء', 'غير متوفر')}`\n\n"
f"🔄 يمكنك إضافة هذا الرقم إلى المحفوظات للاستعلام عنه لاحقاً")
else:
response = ("⚠️ *عذراً، تعذر الحصول على معلومات الرصيد*\n"
"══════════════════════════\n"
"🛑 *الأسباب المحتملة:*\n"
"• الرقم غير مسجل في خدمة ADSL\n"
"• وجود مشكلة تقنية مؤقتة\n"
"• خطأ في الاتصال بالخادم\n\n"
"🔍 يرجى التأكد من الرقم والمحاولة لاحقاً")
if isinstance(update, Update):
await update.message.reply_text(response, parse_mode='Markdown')
else:
await update.reply_text(response, parse_mode='Markdown')
async def add_number(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *رقم غير صحيح!*\nيجب أن يتكون الرقم من 8 أرقام فقط.\nمثال: 71234567",
parse_mode='Markdown')
return ADD_NUMBER
# تحقق وحفظ الرقم للمستخدم فقط
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await update.message.reply_text(f"✅ تم حفظ الرقم {phone_number} بنجاح!",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
welcome_message = (
f"✨ *مرحباً بك {user.first_name} في بوت استعلام رصيد ADSL اليمن* ✨\n\n"
"🚀 *خدمات البوت المتكاملة:*\n"
"• 📲 استعلام فوري عن رصيد أي خط ADSL\n"
"• 💾 إدارة الأرقام المحفوظة بسهولة\n"
"• ⏰ جدولة استعلامات تلقائية يومية\n"
"• 📊 عرض التقارير المفصلة\n\n"
"📌 *كيفية الاستخدام:*\n"
"• أرسل رقم الهاتف مباشرة للاستعلام الفوري\n"
"• أو استخدم القائمة أدناه للوصول إلى جميع الميزات")
keyboard = [[
InlineKeyboardButton("📲 استعلام فوري", callback_data='new_query'),
InlineKeyboardButton("💾 إدارة الأرقام", callback_data='manage_numbers')
],
[
InlineKeyboardButton("⏰ جدولة تلقائية",
callback_data='schedule_query'),
InlineKeyboardButton("📊 الاستعلام الجماعي",
callback_data='query_numbers')
], [InlineKeyboardButton("ℹ️ المساعدة", callback_data='help')]]
reply_markup = InlineKeyboardMarkup(keyboard)
if update.message:
await update.message.reply_text(welcome_message,
reply_markup=reply_markup,
parse_mode='Markdown')
else:
await update.callback_query.edit_message_text(
welcome_message, reply_markup=reply_markup, parse_mode='Markdown')
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *يرجى إدخال رقم هاتف صحيح*\n"
"══════════════════════════\n"
"📌 *الشروط المطلوبة:*\n"
"• يجب أن يتكون الرقم من 8 أرقام\n"
"• يجب أن يحتوي على أرقام فقط\n"
"• مثال: `71234567`",
parse_mode='Markdown')
return
processing_msg = await update.message.reply_text(
"⏳ *جاري معالجة طلبك...*\n"
"══════════════════════════\n"
"📡 يتم الآن الاتصال بخادم ADSL\n"
"⏱️ قد يستغرق الأمر بضع ثوانٍ...",
parse_mode='Markdown')
info = get_adsl_info(phone_number)
await processing_msg.delete()
await send_balance_info(update, phone_number, info)
# عرض خيار حفظ الرقم للمستخدم فقط
if info:
user_numbers = saved_numbers_all.get(chat_id, {})
if phone_number not in user_numbers:
keyboard = [[
InlineKeyboardButton("💾 حفظ الرقم",
callback_data=f'save_{phone_number}'),
InlineKeyboardButton("🔄 استعلام جديد", callback_data='new_query')
], [InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"❔ *هل ترغب في حفظ هذا الرقم للاستعلام عنه لاحقاً؟*",
reply_markup=reply_markup,
parse_mode='Markdown')
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data == 'add_number':
await query.edit_message_text(
"📝 *إضافة رقم جديد للمحفوظات*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: `71234567`\n\n"
"🔙 للعودة اضغط /start",
parse_mode='Markdown')
return ADD_NUMBER
elif query.data == 'manage_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم تقم بإضافة أي أرقام إلى المحفوظات بعد\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]),
parse_mode='Markdown')
return
keyboard = []
for num in user_numbers:
keyboard.append([
InlineKeyboardButton(f"🗑️ حذف {num}", callback_data=f'delete_{num}')
])
keyboard.append([InlineKeyboardButton("➕ إضافة رقم جديد", callback_data='add_number')])
keyboard.append([InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"🗂️ *إدارة الأرقام المحفوظة*\n"
"══════════════════════════\n"
"🔘 اختر الرقم الذي تريد إدارته:\n\n"
"🗑️ زر الحذف - لإزالة الرقم من المحفوظات",
reply_markup=reply_markup,
parse_mode='Markdown')
return DELETE_NUMBER
elif query.data == 'query_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"📊 *الاستعلام الجماعي*\n"
"══════════════════════════\n"
"⚠️ لا توجد أرقام محفوظة حالياً\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]),
parse_mode='Markdown')
return
processing_msg = await query.message.reply_text(
"⏳ *جاري استعلام الأرقام المحفوظة*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن جميع الأرقام\n"
"⏱️ قد تستغرق العملية بعض الوقت...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
if info:
table_data.append([
num,
info.get('الرصيد الحالي', 'غير متوفر'),
info.get('تاريخ الانتهاء', 'غير متوفر')
])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("📊 *نتائج الاستعلام الجماعي*\n"
"══════════════════════════\n"
f"```\n{table}\n```\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await query.message.reply_text(response, parse_mode='Markdown')
elif query.data == 'schedule_query':
keyboard = [[
InlineKeyboardButton("🕘 9 صباحاً", callback_data='hour_9_AM'),
InlineKeyboardButton("🕛 12 ظهراً", callback_data='hour_12_PM')
],
[
InlineKeyboardButton("🕓 4 عصراً", callback_data='hour_4_PM'),
InlineKeyboardButton("🕗 8 مساءً", callback_data='hour_8_PM')
],
[
InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"⏰ *جدولة الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📅 يرجى تحديد الوقت المفضل للاستعلام اليومي\n\n"
"⏱️ سيتم إجراء الاستعلام تلقائياً في الوقت المحدد\n\n"
"🏠 يمكنك العودة للمباشرة",
reply_markup=reply_markup,
parse_mode='Markdown')
return SCHEDULE_HOUR
elif query.data == 'help':
help_text = ("ℹ️ *دليل استخدام البوت*\n"
"══════════════════════════\n"
"🔹 *استعلام فوري*:\n"
" - أرسل الرقم مباشرة (8 أرقام)\n"
" - أو اضغط على 'استعلام فوري'\n\n"
"🔹 *إدارة الأرقام*:\n"
" - حفظ الأرقام للاستعلام الجماعي\n"
" - حذف الأرقام المحفوظة\n\n"
"🔹 *الاستعلام الجماعي*:\n"
" - استعلام جميع الأرقام المحفوظة دفعة واحدة\n\n"
"🔹 *جدولة استعلام*:\n"
" - ضبط استعلام تلقائي يومي في وقت محدد\n\n"
"📌 *ملاحظات مهمة*:\n"
" - يجب أن يتكون الرقم من 8 أرقام\n"
" - الخدمة متوفرة لجميع عملاء ADSL اليمن\n\n"
"🏠 اضغط للعودة إلى الرئيسية")
keyboard = [[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(help_text, reply_markup=reply_markup, parse_mode='Markdown')
elif query.data == 'back':
await start(update, context)
elif query.data == 'new_query':
keyboard = [[InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"🔍 *استعلام جديد*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: `71234567`",
reply_markup=reply_markup,
parse_mode='Markdown')
elif query.data.startswith('save_'):
phone_number = query.data[5:]
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحفظ بنجاح*\n"
f"══════════════════════════\n"
f"تم حفظ الرقم `{phone_number}` في المحفوظات\n\n"
f"📋 يمكنك الآن إجراء استعلام جماعي أو جدولة استعلامات تلقائية",
parse_mode='Markdown')
await start(update, context)
async def delete_number(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('delete_'):
num_to_delete = query.data[7:]
user_numbers = saved_numbers_all.get(chat_id, {})
if num_to_delete in user_numbers:
del user_numbers[num_to_delete]
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحذف بنجاح*\n"
f"══════════════════════════\n"
f"• *الرقم المحذوف:* `{num_to_delete}`\n\n"
f"📋 يمكنك إضافة أرقام جديدة من القائمة الرئيسية",
parse_mode='Markdown')
else:
await query.edit_message_text(
"⚠️ *تعذر الحذف*\n"
"══════════════════════════\n"
"• الرقم المطلوب غير موجود في المحفوظات\n\n"
"📋 يرجى التحقق من الأرقام المحفوظة والمحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def schedule_hour(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('hour_'):
time_parts = query.data.split('_')
hour = int(time_parts[1])
ampm = time_parts[2]
# تحويل إلى 24 ساعة
if ampm == 'PM' and hour < 12:
hour += 12
elif ampm == 'AM' and hour == 12:
hour = 0
# حفظ الجدولة (وقت واحد فقط لكل مستخدم)
scheduled_times[chat_id] = {'hour': hour, 'minute': 0, 'ampm': ampm}
save_scheduled_times(scheduled_times)
now = datetime.now(YEMEN_TZ)
scheduled_time = now.replace(hour=hour, minute=0, second=0, microsecond=0)
if scheduled_time < now:
scheduled_time += timedelta(days=1)
# إزالة الجدولة السابقة إن وجدت
if chat_id in scheduled_jobs:
scheduled_jobs[chat_id].schedule_removal()
try:
job = context.application.job_queue.run_repeating(
auto_query_callback,
interval=timedelta(days=1),
first=timedelta(seconds=(scheduled_time - now).total_seconds()),
chat_id=int(chat_id))
scheduled_jobs[chat_id] = job
await query.edit_message_text(
f"✅ *تمت الجدولة بنجاح*\n"
f"══════════════════════════\n"
f"• *وقت الاستعلام:* {time_parts[1]} {'صباحاً' if ampm == 'AM' else 'مساءً'}\n"
f"• سيبدأ الاستعلام التلقائي يومياً في الوقت المحدد\n\n"
f"📋 يمكنك تعديل الإعدادات مرة واحدة يومياً من القائمة الرئيسية",
parse_mode='Markdown')
except Exception as e:
logger.error(f"خطأ في الجدولة: {e}")
await query.edit_message_text(
"⚠️ *تعذر إعداد الجدولة*\n"
"══════════════════════════\n"
"حدث خطأ تقني أثناء محاولة جدولة الاستعلام\n\n"
"🔄 يرجى المحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def auto_query_callback(context: ContextTypes.DEFAULT_TYPE):
job = context.job
chat_id = str(job.chat_id)
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await context.bot.send_message(
job.chat_id, "⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم يتم العثور على أي أرقام محفوظة للاستعلام عنها\n\n"
"➕ يرجى إضافة أرقام أولاً من القائمة الرئيسية",
parse_mode='Markdown')
return
processing_msg = await context.bot.send_message(
job.chat_id, "⏳ *جاري تنفيذ الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن الأرقام المحفوظة\n"
"⏱️ يرجى الانتظار...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
if info:
table_data.append([
num,
info.get('الرصيد الحالي', 'غير متوفر'),
info.get('تاريخ الانتهاء', 'غير متوفر')
])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("⏰ *نتائج الاستعلام التلقائي*\n"
"══════════════════════════\n"
f"```\n{table}\n```\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await context.bot.send_message(job.chat_id, response, parse_mode='Markdown')
async def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.error(msg="حدث خطأ في البوت:", exc_info=context.error)
if update.message:
await update.message.reply_text(
"⛔ *عذراً، حدث خطأ غير متوقع*\n"
"══════════════════════════\n"
"لقد واجهنا مشكلة تقنية أثناء معالجة طلبك\n\n"
"🔄 يرجى المحاولة مرة أخرى لاحقاً",
parse_mode='Markdown')
def main():
server_thread = threading.Thread(target=run)
server_thread.start()
application = ApplicationBuilder().token(
"7563226990:AAFg2E5-f6EcVEjBK7ph5w8Q064P4daZlj0").build()
conv_handler = ConversationHandler(
entry_points=[CallbackQueryHandler(button_handler)],
states={
ADD_NUMBER: [MessageHandler(filters.TEXT & ~filters.COMMAND, add_number)],
DELETE_NUMBER: [CallbackQueryHandler(delete_number)],
SCHEDULE_HOUR: [CallbackQueryHandler(schedule_hour)]
},
fallbacks=[CommandHandler("start", start)],
per_message=True)
application.add_handler(CommandHandler("start", start))
application.add_handler(conv_handler)
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
application.add_error_handler(error_handler)
logger.info("🤖 البوت يعمل...")
application.run_polling()
if __name__ == '__main__':
main()
واريد مطابقة وقت انتهاء الرصيد للارقام في حال تبقاء خمس ايام اريد تغيير شكل الاشعارلإضافة أوقات جدول استعلام إضافية (بخلاف الأوقات الموجودة 9 صباحاً، 12 ظهراً، 4 عصراً، 8 مساءً)، يمكنك ببساطة إضافة أزرار جديدة مع قيمة `callback_data` مناسبة في مكان عرض خيارات الجدولة، بالإضافة إلى التعامل مع القيم الجديدة في دالة `schedule_hour`.
كذلك بالنسبة لمطابقة وقت انتهاء الرصيد والتحقق إذا كان تبقى 5 أيام أو أقل لتغيير شكل الإشعار، يمكنك تعديل جزء بناء رسالة الإشعار بحيث يتضمن تحقق الفرق بين التاريخ الحالي وتاريخ انتهاء الاشتراك.
---
## 1. إضافة باقي الأوقات المطلوب جدولتها
مثلاً تريد إضافة 7 صباحاً و 10 مساءً مثلاً:
في الكود عند عرض أزرار الجدولة:
```python
elif query.data == 'schedule_query':
keyboard = [[
InlineKeyboardButton("🕖 7 صباحاً", callback_data='hour_7_AM'),
InlineKeyboardButton("🕘 9 صباحاً", callback_data='hour_9_AM'),
InlineKeyboardButton("🕛 12 ظهراً", callback_data='hour_12_PM')
],
[
InlineKeyboardButton("🕓 4 عصراً", callback_data='hour_4_PM'),
InlineKeyboardButton("🕗 8 مساءً", callback_data='hour_8_PM'),
InlineKeyboardButton("🕥 10 مساءً", callback_data='hour_10_PM')
],
[
InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"⏰ *جدولة الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📅 يرجى تحديد الوقت المفضل للاستعلام اليومي\n\n"
"⏱️ سيتم إجراء الاستعلام تلقائياً في الوقت المحدد\n\n"
"🏠 يمكنك العودة للمباشرة",
reply_markup=reply_markup,
parse_mode='Markdown')
return SCHEDULE_HOUR
```
وبعد إضافة callback_data جديد في شكل `hour_7_AM` أو `hour_10_PM`، لا حاجة لتعديل دالة `schedule_hour` لأن الكود يعالج جميع الأوقات التي تبدأ بـ `hour_` بشكل ديناميكي.
---
## 2. تعديل شكل الإشعار عند انتهاء الرصيد خلال 5 أيام أو أقل
بما أن لديك ملف `info` يحتوي على مفتاح `'تاريخ الانتهاء'` مثل `"2024-06-30"`, تحتاج لتحليل هذا التاريخ ومقارنته مع التاريخ الحالي.
مثلاً، في دالة `send_balance_info` أو في المكان الذي تبني فيه رسالة الاستعلام، عدل الكود ليكون:
```python
async def send_balance_info(update, phone_number, info):
if info:
# جلب تاريخ الانتهاء بشكل صحيح
end_date_str = info.get('تاريخ الانتهاء', None)
warning_text = ""
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
days_left = (end_date - now_date).days
if days_left <= 5 and days_left >= 0:
warning_text = f"\n⚠️ *تنبيه:* تبقى فقط {days_left} يوم على انتهاء الباقة!"
elif days_left < 0:
warning_text = "\n❗️ انتهت صلاحية الباقة."
except Exception as e:
logger.error(f"خطأ في تحليل تاريخ الانتهاء: {e}")
# لا تفعل شيء خاص إذا فشل التحليل
response = (
f"🌟 *نتائج استعلام رصيد ADSL*\n"
f"══════════════════════════\n"
f"📱 *الرقم:* `{phone_number}`\n\n"
f"💳 *الرصيد الحالي:* `{info.get('الرصيد الحالي', 'غير متوفر')}`\n"
f"📦 *قيمة الباقة:* `{info.get('قيمة الباقة', 'غير متوفر')}`\n"
f"⏳ *تاريخ الانتهاء:* `{end_date_str if end_date_str else 'غير متوفر'}`"
f"{warning_text}\n\n"
f"🔄 يمكنك إضافة هذا الرقم إلى المحفوظات للاستعلام عنه لاحقاً")
else:
response = ("⚠️ *عذراً، تعذر الحصول على معلومات الرصيد*\n"
"══════════════════════════\n"
"🛑 *الأسباب المحتملة:*\n"
"• الرقم غير مسجل في خدمة ADSL\n"
"• وجود مشكلة تقنية مؤقتة\n"
"• خطأ في الاتصال بالخادم\n\n"
"🔍 يرجى التأكد من الرقم والمحاولة لاحقاً")
if isinstance(update, Update):
await update.message.reply_text(response, parse_mode='Markdown')
else:
await update.reply_text(response, parse_mode='Markdown')
```
أيضًا من الأفضل تكرار هذا المنطق عند إرسال رسالة الجدولة التلقائية `auto_query_callback` لتغيير الشكل هناك كذلك.
مثلاً داخل الحلقة التي تبني الجدول يمكن تعديل نص الرصيد ليشمل علامة تنبيه في حالة قرب انتهاء الاشتراك.
مثال قصير لتوضيح داخل `auto_query_callback`:
```python
for num in user_numbers:
info = get_adsl_info(num)
end_date_str = info.get('تاريخ الانتهاء', '') if info else ''
remaining_days = None
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
remaining_days = (end_date - now_date).days
except:
remaining_days = None
if info:
balance = info.get('الرصيد الحالي', 'غير متوفر')
# أضف علامة تنبيه إذا تبقى 5 أيام أو أقل
if remaining_days is not None:
if remaining_days < 0:
balance += " ❗️ (انتهى الاشتراك)"
elif remaining_days <= 5:
balance += f" ⚠️ ({remaining_days} أيام متبقية)"
table_data.append([
num,
balance,
info.get('تاريخ الانتهاء', 'غير متوفر')
])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
```
---
## الملخص
- لإضافة أوقات: أضف أزرار مع callback_data منسقة مثل `hour_7_AM` و`hour_10_PM`.
- في دالة `schedule_hour` يتم التعامل مع أي قيمة تبدأ بـ `hour_` بشكل تلقائي.
- لمطابقة الوقت وإضافة تحذيرات عند تبقى 5 أيام أو أقل على انتهاء الرصيد، افحص تاريخ الانتهاء وقارن مع التاريخ الحالي، وأضف نص تحذير في الإشعار.
- طبق هذا في دالة `send_balance_info` وكذلك في تقرير الجدولة التلقائية داخل `auto_query_callback`.
---
إذا احتجت مساعدة في أي نقطة أو دمج التعديلات كاملة، فقط أخبرني!f035674896d28e785b066fd4اعطيني الكود الكامل بعد التعديل لاقوم باستخدامة مباشرة
بالطبع، إليك الكود الكامل بعد إضافة الأوقات الإضافية (7 صباحاً، 10 مساءً) وتعديل رسالة الإشعار بحيث يتم التنبيه إذا تبقى 5 أيام أو أقل على انتهاء الباقة.
يرجى استبدال الجزء السابق من الكود بهذا الكود مباشرة:
```python
import requests
from bs4 import BeautifulSoup
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (ApplicationBuilder, CommandHandler, MessageHandler,
ContextTypes, filters, CallbackQueryHandler,
ConversationHandler)
import logging
import json
import os
from datetime import datetime, timedelta
import pytz
from tabulate import tabulate
# Flask و threading لخدمة الويب
from flask import Flask
import threading
app = Flask('')
@app.route('/')
def home():
return "Bot is alive!"
def run():
app.run(host="0.0.0.0", port=8080)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
ADD_NUMBER, DELETE_NUMBER, SCHEDULE_HOUR = range(3)
SAVED_NUMBERS_FILE = "saved_numbers.json"
SCHEDULED_TIMES_FILE = "scheduled_times.json"
YEMEN_TZ = pytz.timezone('Asia/Aden')
# --- التعديل: التحميل وحفظ حسب chat_id ---
def load_saved_numbers():
if os.path.exists(SAVED_NUMBERS_FILE):
try:
with open(SAVED_NUMBERS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأرقام المحفوظة: {e}")
return {}
else:
return {}
def load_scheduled_times():
if os.path.exists(SCHEDULED_TIMES_FILE):
try:
with open(SCHEDULED_TIMES_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأوقات المجدولة: {e}")
return {}
else:
return {}
def save_numbers_to_file(numbers):
try:
with open(SAVED_NUMBERS_FILE, 'w', encoding='utf-8') as f:
json.dump(numbers, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأرقام المحفوظة: {e}")
def save_scheduled_times(times):
try:
with open(SCHEDULED_TIMES_FILE, 'w', encoding='utf-8') as f:
json.dump(times, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأوقات المجدولة: {e}")
saved_numbers_all = load_saved_numbers()
scheduled_times = load_scheduled_times()
scheduled_jobs = {}
ADSL_URL = "https://adsl-yemen.com/adsl4.php"
def get_adsl_info(phone_number):
try:
data = {"mobile": phone_number, "action": "query"}
response = requests.post(ADSL_URL, data=data)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
results = soup.find_all("div", class_="result-box")
data_dict = {}
for box in results:
title_div = box.find("div", class_="result-title")
value_div = box.find("div", class_="result-value")
if title_div and value_div:
title = title_div.text.strip()
value = value_div.text.strip()
data_dict[title] = value
data_dict['timestamp'] = datetime.now(YEMEN_TZ).strftime("%Y-%m-%d %H:%M:%S")
return data_dict
else:
return None
except Exception as e:
logger.error(f"حدث خطأ أثناء استعلام الرصيد: {e}")
return None
async def send_balance_info(update, phone_number, info):
if info:
end_date_str = info.get('تاريخ الانتهاء', None)
warning_text = ""
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
days_left = (end_date - now_date).days
if 0 <= days_left <= 5:
warning_text = f"\n⚠️ *تنبيه:* تبقى فقط {days_left} يوم على انتهاء الباقة!"
elif days_left < 0:
warning_text = "\n❗️ انتهت صلاحية الباقة."
except Exception as e:
logger.error(f"خطأ في تحليل تاريخ الانتهاء: {e}")
response = (
f"🌟 *نتائج استعلام رصيد ADSL*\n"
f"══════════════════════════\n"
f"📱 *الرقم:* `{phone_number}`\n\n"
f"💳 *الرصيد الحالي:* `{info.get('الرصيد الحالي', 'غير متوفر')}`\n"
f"📦 *قيمة الباقة:* `{info.get('قيمة الباقة', 'غير متوفر')}`\n"
f"⏳ *تاريخ الانتهاء:* `{end_date_str if end_date_str else 'غير متوفر'}`"
f"{warning_text}\n\n"
f"🔄 يمكنك إضافة هذا الرقم إلى المحفوظات للاستعلام عنه لاحقاً")
else:
response = ("⚠️ *عذراً، تعذر الحصول على معلومات الرصيد*\n"
"══════════════════════════\n"
"🛑 *الأسباب المحتملة:*\n"
"• الرقم غير مسجل في خدمة ADSL\n"
"• وجود مشكلة تقنية مؤقتة\n"
"• خطأ في الاتصال بالخادم\n\n"
"🔍 يرجى التأكد من الرقم والمحاولة لاحقاً")
if isinstance(update, Update):
await update.message.reply_text(response, parse_mode='Markdown')
else:
await update.reply_text(response, parse_mode='Markdown')
async def add_number(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *رقم غير صحيح!*\nيجب أن يتكون الرقم من 8 أرقام فقط.\nمثال: 71234567",
parse_mode='Markdown')
return ADD_NUMBER
# تحقق وحفظ الرقم للمستخدم فقط
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await update.message.reply_text(f"✅ تم حفظ الرقم {phone_number} بنجاح!",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
welcome_message = (
f"✨ *مرحباً بك {user.first_name} في بوت استعلام رصيد ADSL اليمن* ✨\n\n"
"🚀 *خدمات البوت المتكاملة:*\n"
"• 📲 استعلام فوري عن رصيد أي خط ADSL\n"
"• 💾 إدارة الأرقام المحفوظة بسهولة\n"
"• ⏰ جدولة استعلامات تلقائية يومية\n"
"• 📊 عرض التقارير المفصلة\n\n"
"📌 *كيفية الاستخدام:*\n"
"• أرسل رقم الهاتف مباشرة للاستعلام الفوري\n"
"• أو استخدم القائمة أدناه للوصول إلى جميع الميزات")
keyboard = [[
InlineKeyboardButton("📲 استعلام فوري", callback_data='new_query'),
InlineKeyboardButton("💾 إدارة الأرقام", callback_data='manage_numbers')
],
[
InlineKeyboardButton("⏰ جدولة تلقائية",
callback_data='schedule_query'),
InlineKeyboardButton("📊 الاستعلام الجماعي",
callback_data='query_numbers')
], [InlineKeyboardButton("ℹ️ المساعدة", callback_data='help')]]
reply_markup = InlineKeyboardMarkup(keyboard)
if update.message:
await update.message.reply_text(welcome_message,
reply_markup=reply_markup,
parse_mode='Markdown')
else:
await update.callback_query.edit_message_text(
welcome_message, reply_markup=reply_markup, parse_mode='Markdown')
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *يرجى إدخال رقم هاتف صحيح*\n"
"══════════════════════════\n"
"📌 *الشروط المطلوبة:*\n"
"• يجب أن يتكون الرقم من 8 أرقام\n"
"• يجب أن يحتوي على أرقام فقط\n"
"• مثال: `71234567`",
parse_mode='Markdown')
return
processing_msg = await update.message.reply_text(
"⏳ *جاري معالجة طلبك...*\n"
"══════════════════════════\n"
"📡 يتم الآن الاتصال بخادم ADSL\n"
"⏱️ قد يستغرق الأمر بضع ثوانٍ...",
parse_mode='Markdown')
info = get_adsl_info(phone_number)
await processing_msg.delete()
await send_balance_info(update, phone_number, info)
# عرض خيار حفظ الرقم للمستخدم فقط
if info:
user_numbers = saved_numbers_all.get(chat_id, {})
if phone_number not in user_numbers:
keyboard = [[
InlineKeyboardButton("💾 حفظ الرقم",
callback_data=f'save_{phone_number}'),
InlineKeyboardButton("🔄 استعلام جديد", callback_data='new_query')
], [InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"❔ *هل ترغب في حفظ هذا الرقم للاستعلام عنه لاحقاً؟*",
reply_markup=reply_markup,
parse_mode='Markdown')
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data == 'add_number':
await query.edit_message_text(
"📝 *إضافة رقم جديد للمحفوظات*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: `71234567`\n\n"
"🔙 للعودة اضغط /start",
parse_mode='Markdown')
return ADD_NUMBER
elif query.data == 'manage_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم تقم بإضافة أي أرقام إلى المحفوظات بعد\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]),
parse_mode='Markdown')
return
keyboard = []
for num in user_numbers:
keyboard.append([
InlineKeyboardButton(f"🗑️ حذف {num}", callback_data=f'delete_{num}')
])
keyboard.append([InlineKeyboardButton("➕ إضافة رقم جديد", callback_data='add_number')])
keyboard.append([InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"🗂️ *إدارة الأرقام المحفوظة*\n"
"══════════════════════════\n"
"🔘 اختر الرقم الذي تريد إدارته:\n\n"
"🗑️ زر الحذف - لإزالة الرقم من المحفوظات",
reply_markup=reply_markup,
parse_mode='Markdown')
return DELETE_NUMBER
elif query.data == 'query_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"📊 *الاستعلام الجماعي*\n"
"══════════════════════════\n"
"⚠️ لا توجد أرقام محفوظة حالياً\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]),
parse_mode='Markdown')
return
processing_msg = await query.message.reply_text(
"⏳ *جاري استعلام الأرقام المحفوظة*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن جميع الأرقام\n"
"⏱️ قد تستغرق العملية بعض الوقت...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
end_date_str = info.get('تاريخ الانتهاء', '') if info else ''
remaining_days = None
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
remaining_days = (end_date - now_date).days
except:
remaining_days = None
if info:
balance = info.get('الرصيد الحالي', 'غير متوفر')
if remaining_days is not None:
if remaining_days < 0:
balance += " ❗️ (انتهى الاشتراك)"
elif remaining_days <= 5:
balance += f" ⚠️ ({remaining_days} أيام متبقية)"
table_data.append([
num,
balance,
info.get('تاريخ الانتهاء', 'غير متوفر')
])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("📊 *نتائج الاستعلام الجماعي*\n"
"══════════════════════════\n"
f"```\n{table}\n```\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await query.message.reply_text(response, parse_mode='Markdown')
elif query.data == 'schedule_query':
keyboard = [[
InlineKeyboardButton("🕖 7 صباحاً", callback_data='hour_7_AM'),
InlineKeyboardButton("🕘 9 صباحاً", callback_data='hour_9_AM'),
InlineKeyboardButton("🕛 12 ظهراً", callback_data='hour_12_PM')
],
[
InlineKeyboardButton("🕓 4 عصراً", callback_data='hour_4_PM'),
InlineKeyboardButton("🕗 8 مساءً", callback_data='hour_8_PM'),
InlineKeyboardButton("🕥 10 مساءً", callback_data='hour_10_PM')
],
[
InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"⏰ *جدولة الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📅 يرجى تحديد الوقت المفضل للاستعلام اليومي\n\n"
"⏱️ سيتم إجراء الاستعلام تلقائياً في الوقت المحدد\n\n"
"🏠 يمكنك العودة للمباشرة",
reply_markup=reply_markup,
parse_mode='Markdown')
return SCHEDULE_HOUR
elif query.data == 'help':
help_text = ("ℹ️ *دليل استخدام البوت*\n"
"══════════════════════════\n"
"🔹 *استعلام فوري*:\n"
" - أرسل الرقم مباشرة (8 أرقام)\n"
" - أو اضغط على 'استعلام فوري'\n\n"
"🔹 *إدارة الأرقام*:\n"
" - حفظ الأرقام للاستعلام الجماعي\n"
" - حذف الأرقام المحفوظة\n\n"
"🔹 *الاستعلام الجماعي*:\n"
" - استعلام جميع الأرقام المحفوظة دفعة واحدة\n\n"
"🔹 *جدولة استعلام*:\n"
" - ضبط استعلام تلقائي يومي في وقت محدد\n\n"
"📌 *ملاحظات مهمة*:\n"
" - يجب أن يتكون الرقم من 8 أرقام\n"
" - الخدمة متوفرة لجميع عملاء ADSL اليمن\n\n"
"🏠 اضغط للعودة إلى الرئيسية")
keyboard = [[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(help_text, reply_markup=reply_markup, parse_mode='Markdown')
elif query.data == 'back':
await start(update, context)
elif query.data == 'new_query':
keyboard = [[InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')]]
await query.edit_message_text(
"🔍 *استعلام جديد*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: `71234567`",
reply_markup=InlineKeyboardMarkup(keyboard),
parse_mode='Markdown')
elif query.data.startswith('save_'):
phone_number = query.data[5:]
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحفظ بنجاح*\n"
f"══════════════════════════\n"
f"تم حفظ الرقم `{phone_number}` في المحفوظات\n\n"
f"📋 يمكنك الآن إجراء استعلام جماعي أو جدولة استعلامات تلقائية",
parse_mode='Markdown')
await start(update, context)
async def delete_number(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('delete_'):
num_to_delete = query.data[7:]
user_numbers = saved_numbers_all.get(chat_id, {})
if num_to_delete in user_numbers:
del user_numbers[num_to_delete]
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحذف بنجاح*\n"
f"══════════════════════════\n"
f"• *الرقم المحذوف:* `{num_to_delete}`\n\n"
f"📋 يمكنك إضافة أرقام جديدة من القائمة الرئيسية",
parse_mode='Markdown')
else:
await query.edit_message_text(
"⚠️ *تعذر الحذف*\n"
"══════════════════════════\n"
"• الرقم المطلوب غير موجود في المحفوظات\n\n"
"📋 يرجى التحقق من الأرقام المحفوظة والمحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def schedule_hour(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('hour_'):
time_parts = query.data.split('_') # ['hour', '7', 'AM'] مثلاً
hour = int(time_parts[1])
ampm = time_parts[2]
# تحويل إلى 24 ساعة
if ampm == 'PM' and hour < 12:
hour += 12
elif ampm == 'AM' and hour == 12:
hour = 0
# حفظ الجدولة (وقت واحد فقط لكل مستخدم)
scheduled_times[chat_id] = {'hour': hour, 'minute': 0, 'ampm': ampm}
save_scheduled_times(scheduled_times)
now = datetime.now(YEMEN_TZ)
scheduled_time = now.replace(hour=hour, minute=0, second=0, microsecond=0)
if scheduled_time < now:
scheduled_time += timedelta(days=1)
# إزالة الجدولة السابقة إن وجدت
if chat_id in scheduled_jobs:
scheduled_jobs[chat_id].schedule_removal()
try:
job = context.application.job_queue.run_repeating(
auto_query_callback,
interval=timedelta(days=1),
first=timedelta(seconds=(scheduled_time - now).total_seconds()),
chat_id=int(chat_id))
scheduled_jobs[chat_id] = job
await query.edit_message_text(
f"✅ *تمت الجدولة بنجاح*\n"
f"══════════════════════════\n"
f"• *وقت الاستعلام:* {time_parts[1]} {'صباحاً' if ampm == 'AM' else 'مساءً'}\n"
f"• سيبدأ الاستعلام التلقائي يومياً في الوقت المحدد\n\n"
f"📋 يمكنك تعديل الإعدادات مرة واحدة يومياً من القائمة الرئيسية",
parse_mode='Markdown')
except Exception as e:
logger.error(f"خطأ في الجدولة: {e}")
await query.edit_message_text(
"⚠️ *تعذر إعداد الجدولة*\n"
"══════════════════════════\n"
"حدث خطأ تقني أثناء محاولة جدولة الاستعلام\n\n"
"🔄 يرجى المحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def auto_query_callback(context: ContextTypes.DEFAULT_TYPE):
job = context.job
chat_id = str(job.chat_id)
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await context.bot.send_message(
job.chat_id, "⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم يتم العثور على أي أرقام محفوظة للاستعلام عنها\n\n"
"➕ يرجى إضافة أرقام أولاً من القائمة الرئيسية",
parse_mode='Markdown')
return
processing_msg = await context.bot.send_message(
job.chat_id, "⏳ *جاري تنفيذ الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن الأرقام المحفوظة\n"
"⏱️ يرجى الانتظار...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
end_date_str = info.get('تاريخ الانتهاء', '') if info else ''
remaining_days = None
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
remaining_days = (end_date - now_date).days
except:
remaining_days = None
if info:
balance = info.get('الرصيد الحالي', 'غير متوفر')
if remaining_days is not None:
if remaining_days < 0:
balance += " ❗️ (انتهى الاشتراك)"
elif remaining_days <= 5:
balance += f" ⚠️ ({remaining_days} أيام متبقية)"
table_data.append([
num,
balance,
info.get('تاريخ الانتهاء', 'غير متوفر')
])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("⏰ *نتائج الاستعلام التلقائي*\n"
"══════════════════════════\n"
f"```\n{table}\n```\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await context.bot.send_message(job.chat_id, response, parse_mode='Markdown')
async def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
logger.error(msg="حدث خطأ في البوت:", exc_info=context.error)
if update.message:
await update.message.reply_text(
"⛔ *عذراً، حدث خطأ غير متوقع*\n"
"══════════════════════════\n"
"لقد واجهنا مشكلة تقنية أثناء معالجة طلبك\n\n"
"🔄 يرجى المحاولة مرة أخرى لاحقاً",
parse_mode='Markdown')
def main():
server_thread = threading.Thread(target=run)
server_thread.start()
application = ApplicationBuilder().token(
"7563226990:AAFg2E5-f6EcVEjBK7ph5w8Q064P4daZlj0").build()
conv_handler = ConversationHandler(
entry_points=[CallbackQueryHandler(button_handler)],
states={
ADD_NUMBER: [MessageHandler(filters.TEXT & ~filters.COMMAND, add_number)],
DELETE_NUMBER: [CallbackQueryHandler(delete_number)],
SCHEDULE_HOUR: [CallbackQueryHandler(schedule_hour)]
},
fallbacks=[CommandHandler("start", start)],
per_message=True)
application.add_handler(CommandHandler("start", start))
application.add_handler(conv_handler)
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
application.add_error_handler(error_handler)
logger.info("🤖 البوت يعمل...")
application.run_polling()
if __name__ == '__main__':
main()
```
---
## ملاحظات هامة
- الكود أضاف خيارين وقت جدولة جديدين: 7 صباحاً و10 مساءً (يمكنك تعديل أو إضافة أوقات أخرى بنفس النمط).
- تم تعديل رسالة الاستعلام الفردي (`send_balance_info`) وجدول الاستعلام الجماعي والتلقائي (`query_numbers`, `auto_query_callback`) لإظهار تحذير إذا تبقى 5 أيام أو أقل أو انتهاء الاشتراك.
- تأكد من استبدال `token` في `ApplicationBuilder()` بالتوكن الخاص بالبوت عندك.
- يرجى اختبار الكود في بيئة مناسبة وتجربته.
إذا أردت أي مساعدة إضافية في تعديل أو شرح أي جزء لا تتردد بمراسلتنا. بالتوفيق!df780aceabc7a7af751f6cecهل هذا الكود جاهز لاستخدامة في موقع https://pulsetic.com/uptimerobot-alternative/
للعلم الكود
import requests
from bs4 import BeautifulSoup
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (ApplicationBuilder, CommandHandler, MessageHandler,
ContextTypes, filters, CallbackQueryHandler,
ConversationHandler)
import logging
import json
import os
from datetime import datetime, timedelta
import pytz
from tabulate import tabulate
# Flask و threading لخدمة الويب
from flask import Flask
import threading
app = Flask('')
@app.route('/')
def home():
return "Bot is alive!"
def run():
app.run(host="0.0.0.0", port=8080)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
ADD_NUMBER, DELETE_NUMBER, SCHEDULE_HOUR = range(3)
SAVED_NUMBERS_FILE = "saved_numbers.json"
SCHEDULED_TIMES_FILE = "scheduled_times.json"
YEMEN_TZ = pytz.timezone('Asia/Aden')
# --- التعديل: التحميل وحفظ حسب chat_id ---
def load_saved_numbers():
if os.path.exists(SAVED_NUMBERS_FILE):
try:
with open(SAVED_NUMBERS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأرقام المحفوظة: {e}")
return {}
else:
return {}
def load_scheduled_times():
if os.path.exists(SCHEDULED_TIMES_FILE):
try:
with open(SCHEDULED_TIMES_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"خطأ في تحميل الأوقات المجدولة: {e}")
return {}
else:
return {}
def save_numbers_to_file(numbers):
try:
with open(SAVED_NUMBERS_FILE, 'w', encoding='utf-8') as f:
json.dump(numbers, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأرقام المحفوظة: {e}")
def save_scheduled_times(times):
try:
with open(SCHEDULED_TIMES_FILE, 'w', encoding='utf-8') as f:
json.dump(times, f, ensure_ascii=False, indent=4)
except Exception as e:
logger.error(f"خطأ في حفظ الأوقات المجدولة: {e}")
saved_numbers_all = load_saved_numbers()
scheduled_times = load_scheduled_times()
scheduled_jobs = {}
ADSL_URL = "https://adsl-yemen.com/adsl4.php"
def get_adsl_info(phone_number):
try:
data = {"mobile": phone_number, "action": "query"}
response = requests.post(ADSL_URL, data=data)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
results = soup.find_all("div", class_="result-box")
data_dict = {}
for box in results:
title_div = box.find("div", class_="result-title")
value_div = box.find("div", class_="result-value")
if title_div and value_div:
title = title_div.text.strip()
value = value_div.text.strip()
data_dict[title] = value
data_dict['timestamp'] = datetime.now(YEMEN_TZ).strftime(
"%Y-%m-%d %H:%M:%S")
return data_dict
else:
return None
except Exception as e:
logger.error(f"حدث خطأ أثناء استعلام الرصيد: {e}")
return None
async def send_balance_info(update, phone_number, info):
if info:
end_date_str = info.get('تاريخ الانتهاء', None)
warning_text = ""
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
days_left = (end_date - now_date).days
if 0 <= days_left <= 5:
warning_text = f"\n⚠️ *تنبيه:* تبقى فقط {days_left} يوم على انتهاء الباقة!"
elif days_left < 0:
warning_text = "\n❗️ انتهت صلاحية الباقة."
except Exception as e:
logger.error(f"خطأ في تحليل تاريخ الانتهاء: {e}")
response = (
f"🌟 *نتائج استعلام رصيد ADSL*\n"
f"══════════════════════════\n"
f"📱 *الرقم:* {phone_number}\n\n"
f"💳 *الرصيد الحالي:* {info.get('الرصيد الحالي', 'غير متوفر')}\n"
f"📦 *قيمة الباقة:* {info.get('قيمة الباقة', 'غير متوفر')}\n"
f"⏳ *تاريخ الانتهاء:* {end_date_str if end_date_str else 'غير متوفر'}"
f"{warning_text}\n\n"
f"🔄 يمكنك إضافة هذا الرقم إلى المحفوظات للاستعلام عنه لاحقاً")
else:
response = ("⚠️ *عذراً، تعذر الحصول على معلومات الرصيد*\n"
"══════════════════════════\n"
"🛑 *الأسباب المحتملة:*\n"
"• الرقم غير مسجل في خدمة ADSL\n"
"• وجود مشكلة تقنية مؤقتة\n"
"• خطأ في الاتصال بالخادم\n\n"
"🔍 يرجى التأكد من الرقم والمحاولة لاحقاً")
if isinstance(update, Update):
await update.message.reply_text(response, parse_mode='Markdown')
else:
await update.reply_text(response, parse_mode='Markdown')
async def add_number(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> int:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *رقم غير صحيح!*\nيجب أن يتكون الرقم من 8 أرقام فقط.\nمثال: 71234567",
parse_mode='Markdown')
return ADD_NUMBER
# تحقق وحفظ الرقم للمستخدم فقط
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await update.message.reply_text(f"✅ تم حفظ الرقم {phone_number} بنجاح!",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
welcome_message = (
f"✨ *مرحباً بك {user.first_name} في بوت استعلام رصيد ADSL اليمن* ✨\n\n"
"🚀 *خدمات البوت المتكاملة:*\n"
"• 📲 استعلام فوري عن رصيد أي خط ADSL\n"
"• 💾 إدارة الأرقام المحفوظة بسهولة\n"
"• ⏰ جدولة استعلامات تلقائية يومية\n"
"• 📊 عرض التقارير المفصلة\n\n"
"📌 *كيفية الاستخدام:*\n"
"• أرسل رقم الهاتف مباشرة للاستعلام الفوري\n"
"• أو استخدم القائمة أدناه للوصول إلى جميع الميزات")
keyboard = [[
InlineKeyboardButton("📲 استعلام فوري", callback_data='new_query'),
InlineKeyboardButton("💾 إدارة الأرقام", callback_data='manage_numbers')
],
[
InlineKeyboardButton("⏰ جدولة تلقائية",
callback_data='schedule_query'),
InlineKeyboardButton("📊 الاستعلام الجماعي",
callback_data='query_numbers')
], [InlineKeyboardButton("ℹ️ المساعدة", callback_data='help')]]
reply_markup = InlineKeyboardMarkup(keyboard)
if update.message:
await update.message.reply_text(welcome_message,
reply_markup=reply_markup,
parse_mode='Markdown')
else:
await update.callback_query.edit_message_text(
welcome_message, reply_markup=reply_markup, parse_mode='Markdown')
async def handle_message(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> None:
chat_id = str(update.effective_chat.id)
phone_number = update.message.text.strip()
if not phone_number.isdigit() or len(phone_number) != 8:
await update.message.reply_text(
"⚠️ *يرجى إدخال رقم هاتف صحيح*\n"
"══════════════════════════\n"
"📌 *الشروط المطلوبة:*\n"
"• يجب أن يتكون الرقم من 8 أرقام\n"
"• يجب أن يحتوي على أرقام فقط\n"
"• مثال: 71234567",
parse_mode='Markdown')
return
processing_msg = await update.message.reply_text(
"⏳ *جاري معالجة طلبك...*\n"
"══════════════════════════\n"
"📡 يتم الآن الاتصال بخادم ADSL\n"
"⏱️ قد يستغرق الأمر بضع ثوانٍ...",
parse_mode='Markdown')
info = get_adsl_info(phone_number)
await processing_msg.delete()
await send_balance_info(update, phone_number, info)
# عرض خيار حفظ الرقم للمستخدم فقط
if info:
user_numbers = saved_numbers_all.get(chat_id, {})
if phone_number not in user_numbers:
keyboard = [[
InlineKeyboardButton("💾 حفظ الرقم",
callback_data=f'save_{phone_number}'),
InlineKeyboardButton("🔄 استعلام جديد",
callback_data='new_query')
],
[
InlineKeyboardButton("🏠 القائمة الرئيسية",
callback_data='back')
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"❔ *هل ترغب في حفظ هذا الرقم للاستعلام عنه لاحقاً؟*",
reply_markup=reply_markup,
parse_mode='Markdown')
async def button_handler(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> None:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data == 'add_number':
await query.edit_message_text(
"📝 *إضافة رقم جديد للمحفوظات*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: 71234567\n\n"
"🔙 للعودة اضغط /start",
parse_mode='Markdown')
return ADD_NUMBER
elif query.data == 'manage_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم تقم بإضافة أي أرقام إلى المحفوظات بعد\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton("🏠 الرئيسية", callback_data='back')
]]),
parse_mode='Markdown')
return
keyboard = []
for num in user_numbers:
keyboard.append([
InlineKeyboardButton(f"🗑️ حذف {num}",
callback_data=f'delete_{num}')
])
keyboard.append([
InlineKeyboardButton("➕ إضافة رقم جديد",
callback_data='add_number')
])
keyboard.append(
[InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"🗂️ *إدارة الأرقام المحفوظة*\n"
"══════════════════════════\n"
"🔘 اختر الرقم الذي تريد إدارته:\n\n"
"🗑️ زر الحذف - لإزالة الرقم من المحفوظات",
reply_markup=reply_markup,
parse_mode='Markdown')
return DELETE_NUMBER
elif query.data == 'query_numbers':
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await query.edit_message_text(
"📊 *الاستعلام الجماعي*\n"
"══════════════════════════\n"
"⚠️ لا توجد أرقام محفوظة حالياً\n\n"
"➕ يمكنك إضافة أرقام جديدة من القائمة الرئيسية\n\n"
"🏠 اضغط للعودة إلى الرئيسية",
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton("🏠 الرئيسية", callback_data='back')
]]),
parse_mode='Markdown')
return
processing_msg = await query.message.reply_text(
"⏳ *جاري استعلام الأرقام المحفوظة*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن جميع الأرقام\n"
"⏱️ قد تستغرق العملية بعض الوقت...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
end_date_str = info.get('تاريخ الانتهاء', '') if info else ''
remaining_days = None
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
remaining_days = (end_date - now_date).days
except:
remaining_days = None
if info:
balance = info.get('الرصيد الحالي', 'غير متوفر')
if remaining_days is not None:
if remaining_days < 0:
balance += " ❗️ (انتهى الاشتراك)"
elif remaining_days <= 5:
balance += f" ⚠️ ({remaining_days} أيام متبقية)"
table_data.append(
[num, balance,
info.get('تاريخ الانتهاء', 'غير متوفر')])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("📊 *نتائج الاستعلام الجماعي*\n"
"══════════════════════════\n"
f"
\n{table}\n
\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await query.message.reply_text(response, parse_mode='Markdown')
elif query.data == 'schedule_query':
keyboard = [[
InlineKeyboardButton("🕖 7 صباحاً", callback_data='hour_7_AM'),
InlineKeyboardButton("🕘 9 صباحاً", callback_data='hour_9_AM'),
InlineKeyboardButton("🕛 12 ظهراً", callback_data='hour_12_PM')
],
[
InlineKeyboardButton("🕓 4 عصراً",
callback_data='hour_4_PM'),
InlineKeyboardButton("🕗 8 مساءً",
callback_data='hour_8_PM'),
InlineKeyboardButton("🕥 10 مساءً",
callback_data='hour_10_PM')
],
[
InlineKeyboardButton("🏠 القائمة الرئيسية",
callback_data='back')
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"⏰ *جدولة الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📅 يرجى تحديد الوقت المفضل للاستعلام اليومي\n\n"
"⏱️ سيتم إجراء الاستعلام تلقائياً في الوقت المحدد\n\n"
"🏠 يمكنك العودة للمباشرة",
reply_markup=reply_markup,
parse_mode='Markdown')
return SCHEDULE_HOUR
elif query.data == 'help':
help_text = ("ℹ️ *دليل استخدام البوت*\n"
"══════════════════════════\n"
"🔹 *استعلام فوري*:\n"
" - أرسل الرقم مباشرة (8 أرقام)\n"
" - أو اضغط على 'استعلام فوري'\n\n"
"🔹 *إدارة الأرقام*:\n"
" - حفظ الأرقام للاستعلام الجماعي\n"
" - حذف الأرقام المحفوظة\n\n"
"🔹 *الاستعلام الجماعي*:\n"
" - استعلام جميع الأرقام المحفوظة دفعة واحدة\n\n"
"🔹 *جدولة استعلام*:\n"
" - ضبط استعلام تلقائي يومي في وقت محدد\n\n"
"📌 *ملاحظات مهمة*:\n"
" - يجب أن يتكون الرقم من 8 أرقام\n"
" - الخدمة متوفرة لجميع عملاء ADSL اليمن\n\n"
"🏠 اضغط للعودة إلى الرئيسية")
keyboard = [[InlineKeyboardButton("🏠 الرئيسية", callback_data='back')]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(help_text,
reply_markup=reply_markup,
parse_mode='Markdown')
elif query.data == 'back':
await start(update, context)
elif query.data == 'new_query':
keyboard = [[
InlineKeyboardButton("🏠 القائمة الرئيسية", callback_data='back')
]]
await query.edit_message_text(
"🔍 *استعلام جديد*\n"
"══════════════════════════\n"
"📱 يرجى إرسال رقم الهاتف المكون من 8 أرقام\n"
"✏️ مثال: 71234567",
reply_markup=InlineKeyboardMarkup(keyboard),
parse_mode='Markdown')
elif query.data.startswith('save_'):
phone_number = query.data[5:]
if chat_id not in saved_numbers_all:
saved_numbers_all[chat_id] = {}
saved_numbers_all[chat_id][phone_number] = True
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحفظ بنجاح*\n"
f"══════════════════════════\n"
f"تم حفظ الرقم {phone_number} في المحفوظات\n\n"
f"📋 يمكنك الآن إجراء استعلام جماعي أو جدولة استعلامات تلقائية",
parse_mode='Markdown')
await start(update, context)
async def delete_number(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('delete_'):
num_to_delete = query.data[7:]
user_numbers = saved_numbers_all.get(chat_id, {})
if num_to_delete in user_numbers:
del user_numbers[num_to_delete]
save_numbers_to_file(saved_numbers_all)
await query.edit_message_text(
f"✅ *تم الحذف بنجاح*\n"
f"══════════════════════════\n"
f"• *الرقم المحذوف:* {num_to_delete}\n\n"
f"📋 يمكنك إضافة أرقام جديدة من القائمة الرئيسية",
parse_mode='Markdown')
else:
await query.edit_message_text(
"⚠️ *تعذر الحذف*\n"
"══════════════════════════\n"
"• الرقم المطلوب غير موجود في المحفوظات\n\n"
"📋 يرجى التحقق من الأرقام المحفوظة والمحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def schedule_hour(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> int:
query = update.callback_query
chat_id = str(query.message.chat.id)
await query.answer()
if query.data.startswith('hour_'):
time_parts = query.data.split('_') # ['hour', '7', 'AM'] مثلاً
hour = int(time_parts[1])
ampm = time_parts[2]
# تحويل إلى 24 ساعة
if ampm == 'PM' and hour < 12:
hour += 12
elif ampm == 'AM' and hour == 12:
hour = 0
# حفظ الجدولة (وقت واحد فقط لكل مستخدم)
scheduled_times[chat_id] = {'hour': hour, 'minute': 0, 'ampm': ampm}
save_scheduled_times(scheduled_times)
now = datetime.now(YEMEN_TZ)
scheduled_time = now.replace(hour=hour,
minute=0,
second=0,
microsecond=0)
if scheduled_time < now:
scheduled_time += timedelta(days=1)
# إزالة الجدولة السابقة إن وجدت
if chat_id in scheduled_jobs:
scheduled_jobs[chat_id].schedule_removal()
try:
job = context.application.job_queue.run_repeating(
auto_query_callback,
interval=timedelta(days=1),
first=timedelta(seconds=(scheduled_time -
now).total_seconds()),
chat_id=int(chat_id))
scheduled_jobs[chat_id] = job
await query.edit_message_text(
f"✅ *تمت الجدولة بنجاح*\n"
f"══════════════════════════\n"
f"• *وقت الاستعلام:* {time_parts[1]} {'صباحاً' if ampm == 'AM' else 'مساءً'}\n"
f"• سيبدأ الاستعلام التلقائي يومياً في الوقت المحدد\n\n"
f"📋 يمكنك تعديل الإعدادات مرة واحدة يومياً من القائمة الرئيسية",
parse_mode='Markdown')
except Exception as e:
logger.error(f"خطأ في الجدولة: {e}")
await query.edit_message_text(
"⚠️ *تعذر إعداد الجدولة*\n"
"══════════════════════════\n"
"حدث خطأ تقني أثناء محاولة جدولة الاستعلام\n\n"
"🔄 يرجى المحاولة مرة أخرى",
parse_mode='Markdown')
await start(update, context)
return ConversationHandler.END
async def auto_query_callback(context: ContextTypes.DEFAULT_TYPE):
job = context.job
chat_id = str(job.chat_id)
user_numbers = saved_numbers_all.get(chat_id, {})
if not user_numbers:
await context.bot.send_message(
job.chat_id, "⚠️ *لا توجد أرقام محفوظة*\n"
"══════════════════════════\n"
"لم يتم العثور على أي أرقام محفوظة للاستعلام عنها\n\n"
"➕ يرجى إضافة أرقام أولاً من القائمة الرئيسية",
parse_mode='Markdown')
return
processing_msg = await context.bot.send_message(
job.chat_id, "⏳ *جاري تنفيذ الاستعلام التلقائي*\n"
"══════════════════════════\n"
"📡 يتم الآن جلب أحدث المعلومات عن الأرقام المحفوظة\n"
"⏱️ يرجى الانتظار...",
parse_mode='Markdown')
table_data = []
for num in user_numbers:
info = get_adsl_info(num)
end_date_str = info.get('تاريخ الانتهاء', '') if info else ''
remaining_days = None
if end_date_str:
try:
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
now_date = datetime.now(YEMEN_TZ).replace(tzinfo=None)
remaining_days = (end_date - now_date).days
except:
remaining_days = None
if info:
balance = info.get('الرصيد الحالي', 'غير متوفر')
if remaining_days is not None:
if remaining_days < 0:
balance += " ❗️ (انتهى الاشتراك)"
elif remaining_days <= 5:
balance += f" ⚠️ ({remaining_days} أيام متبقية)"
table_data.append(
[num, balance,
info.get('تاريخ الانتهاء', 'غير متوفر')])
else:
table_data.append([num, "❌ فشل", "❌ فشل"])
headers = ["📱 الرقم", "💵 الرصيد", "📅 الانتهاء"]
table = tabulate(table_data, headers=headers, tablefmt="grid")
response = ("⏰ *نتائج الاستعلام التلقائي*\n"
"══════════════════════════\n"
f"
\n{table}\n
\n"
f"🔢 *عدد الأرقام:* {len(user_numbers)}\n\n"
"✨ تم الانتهاء من عملية الاستعلام بنجاح")
await processing_msg.delete()
await context.bot.send_message(job.chat_id,
response,
parse_mode='Markdown')
async def error_handler(update: Update,
context: ContextTypes.DEFAULT_TYPE) -> None:
logger.error(msg="حدث خطأ في البوت:", exc_info=context.error)
if update.message:
await update.message.reply_text(
"⛔ *عذراً، حدث خطأ غير متوقع*\n"
"══════════════════════════\n"
"لقد واجهنا مشكلة تقنية أثناء معالجة طلبك\n\n"
"🔄 يرجى المحاولة مرة أخرى لاحقاً",
parse_mode='Markdown')
def main():
server_thread = threading.Thread(target=run)
server_thread.start()
application = ApplicationBuilder().token(
"7563226990:AAFg2E5-f6EcVEjBK7ph5w8Q064P4daZlj0").build()
conv_handler = ConversationHandler(
entry_points=[CallbackQueryHandler(button_handler)],
states={
ADD_NUMBER:
[MessageHandler(filters.TEXT & ~filters.COMMAND, add_number)],
DELETE_NUMBER: [CallbackQueryHandler(delete_number)],
SCHEDULE_HOUR: [CallbackQueryHandler(schedule_hour)]
},
fallbacks=[CommandHandler("start", start)],
per_message=True)
application.add_handler(CommandHandler("start", start))
application.add_handler(conv_handler)
application.add_handler(
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
application.add_error_handler(error_handler)
logger.info("🤖 البوت يعمل...")
application.run_polling()
if __name__ == '__main__':
main()نعم، الكود الذي أرفقته بشكل عام جاهز للعمل مع خدمة مثل https://pulsetic.com/uptimerobot-alternative/ طالما أنها تدعم تشغيل بوتات Python مع إمكانية فتح خدمة ويب (وهو ما قمت بتوفيره عبر Flask على المنفذ 8080).
بعض النقاط المهمة للتأكد منها لكي يعمل بوتك بشكل صحيح في بيئة مثل pulsetic أو أي خدمة استضافة مشابهة:
1. **الخدمة تعتمد على بقاء البرنامج شغّالًا (Persistent Running Process):**
هذا ضروري لأن بوت تلغرام يعمل كعملية مستمرة (long polling). الكود يستخدم `application.run_polling()` مع Flask يخدم على الويب في خيط منفصل.
2. **المنفذ 8080 مفتوح ومسموح به في الخدمة:**
لأن Flask مقدم خدمة ويب على هذا المنفذ (`app.run(host="0.0.0.0", port=8080)`) ليتمكن pulsetic من ping-ها على `/` endpoint للتأكد من أن البوت يعمل (خاصية الـ Uptime Monitoring).
3. **مكتبات البايثون اللازمة مثبتة:**
مثل `python-telegram-bot`, `requests`, `beautifulsoup4`, `flask`, `pytz`, و `tabulate`
(يمكنك إضافتهم ضمن ملف `requirements.txt` في بيئة الاستضافة الخاصة بك).
4. **توكن البوت صالح ومفعّل:**
أي توكن البوت الذي تضعه في
```python
application = ApplicationBuilder().token(
"7563226990:AAFg2E5-f6EcVEjBK7ph5w8Q064P4daZlj0").build()
```
يجب أن يكون مدخل صحيح.
5. **التعامل مع الملفات (json) مسموح وذات صلاحيات كتابة:**
نظرًا لأن الكود يحفظ ويقرأ من ملفات `saved_numbers.json` و`scheduled_times.json` في مجلد العمل الحالي، تأكد أنه يمكن للطور تنفيذ عمليات القراءة والكتابة على الملفات على الخادم.
---
### ملحوظة:
- البنية الحالية تستخدم **long polling** وعند استضافة في سيرفرات تقدم الـ webhook فقد تحتاج إلى تعديل ليعمل Webhook بدل polling، لكن معظم خدمات الاستضافة التي تسمح لك بتشغيل سيرفر Python منها بدون مشاكل **polling** تعمل بشكل جيد.
- تأكد من أن عملية بوت تلغرام تعمل كعملية دائمة ولا تنقطع — وإذا كنت تستخدم pulsetic فهذا يناسب تمامًا.
---
### خلاصة:
- **الكود جاهز للاستخدام في pulsetic** طالما تم توفير متطلبات تشغيل البيئة (مكتبات، صلاحيات الملفات).
- يحتفظ بخدمة ويب خفيفة على `/` لمراقبة uptime وهو مطلوب في pulsetic لتحديد ما إذا كان البوت ما زال قيد العمل.
---
إذا أردت، يمكنني مساعدتك في كتابة ملف `requirements.txt` أو تقديم تعليمات أخرى لتهيئة البوت في تلك المنصة. فقط أخبرني!063c5b68dd0ef6760f804fb4ماهو الرابط الذي اقوم بتقديمة لموقع https://pulsetic.com/uptimerobot-alternative/
في حالة بوت Telegram الذي تستخدمه مع كودك الحالي، فإنك فتحت خادم ويب صغير عبر Flask على المنفذ 8080، والذي يقدم رد ثابت على مسار `/`:
```python
@app.route('/')
def home():
return "Bot is alive!"
```
---
### إذًا:
- **الرابط الذي ستقدمه لـ pulsetic (أو أي خدمة مراقبة uptime)** هو الرابط الكامل إلى سيرفرك مع المنفذ 8080 والمسار `/`، مثلاً:
```
http://YOUR_SERVER_IP_OR_DOMAIN:8080/
```
---
### أمثلة:
- لو استضفت بوتك في سيرفر له IP مثل: `123.45.67.89`، فإن الرابط هو:
`http://123.45.67.89:8080/`
- لو لديك اسم نطاق (Domain) مرتبط بالسيرفر مثل: `mybot.example.com`، استخدم:
`http://mybot.example.com:8080/`
---
### ملاحظات مهمة:
1. **التأكد من أن المنفذ 8080 مفتوح ومُسموح بالوصول عبر الشبكة** (بما في ذلك جدار الحماية للـ VPS أو مزود الاستضافة).
2. **إذا كان مزود الاستضافة يمنع الوصول إلى المنافذ غير الشائعة**، قد تحتاج لاستخدام منفذ 80 (HTTP القياسي) أو 443 (HTTPS)، وسيستلزم تعديل:
```python
def run():
app.run(host="0.0.0.0", port=80)
```
وتعديل إعدادات سيرفرك accordingly.
3. **إذا كنت تستخدم خدمة مثل pulsetic بدل سيرفر فعلي (مجانية محدودة مثلاً) ولا يسمحون بوصل المنفذ 8080** فقد تحتاج إلى تضمين خادم الويب على المنفذ 80 أو 443.
---
### خلاصة:
- **رابط المونيتور في pulsetic هو:**
`http://<your-server-ip-or-domain>:8080/`
- هذا الرابط يجب أن يعيد نص `"Bot is alive!"` تأكيدًا على أن البوت يعمل.
---
إذا كنت ستستخدم خدمة استضافة (مثل Heroku أو غيرها) يختلف الرابط حسب نطاق الاستضافة، لكن مبدأ عرض الصفحة `/` على المنفذ المستخدم هو نفسه.
---
إذا أردت مساعدة في ضبط الرابط أو ضبط المنفذ بما يناسب بيئتك، شاركني نوع الاستضافة وسأساعدك بخطوات تفصيلية.63650dd97169c16fe03e45d1User: hi, how are you? User: hi, how are you? Assistant:
Hello! I'm doing well, thank you. How can I assist you today?
7251fdad2d63fd003fea4aa9User: hewan yang melompat dan memanjet User: hewan yang melompat dan memanjet Assistant:
Hewan yang dapat melompat dan memanjat antara lain: 1. Kucing – terkenal karena kemampuannya melompat jauh dan memanjat pohon atau dinding. 2. Kelinci – ahli dalam melompat jauh, meskipun kemampuannya memanjat terbatas. 3. Tupai – sangat gesit dalam melompat dari satu cabang ke cabang lain dan memanjat pohon dengan mudah. 4. Katak – hebat dalam melompat, meskipun kemampuan memanjatnya tergantung spesies. 5. Monkeys (Monyet) – selain memanjat, mereka juga bisa melompat dari pohon ke pohon. Apakah ada hewan tertentu yang ingin kamu ketahui lebih detail?