"""
حضور و غیاب ساده — Bale Bot (نسخه رایگان)
Single-class attendance tracker for schools.
بازوساز | hi@botban.ir
"""
import os, sqlite3, logging, time
from datetime import date
from typing import Optional
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
ADMIN_ID: int = int(os.getenv("ADMIN_USER_ID", "0"))
DB_PATH: str = "attendance.db"
API_BASE: str = f"https://tapi.bale.ai/bot{TOKEN}"
def init_db() -> None:
with sqlite3.connect(DB_PATH) as con:
con.execute("""
CREATE TABLE IF NOT EXISTS attendance (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('present','absent')),
day TEXT NOT NULL
)
""")
con.commit()
def mark(student: str, status: str) -> None:
today = str(date.today())
with sqlite3.connect(DB_PATH) as con:
con.execute("DELETE FROM attendance WHERE student=? AND day=?", (student, today))
con.execute("INSERT INTO attendance (student,status,day) VALUES (?,?,?)", (student, status, today))
con.commit()
START_KEYBOARD = {
"inline_keyboard": [
[
{"text": "✅ حاضر کردن دانشآموز", "callback_data": "help_present"},
{"text": "❌ غایب کردن دانشآموز", "callback_data": "help_absent"},
],
[{"text": "📋 گزارش امروز", "callback_data": "report"},
{"text": "⭐ نسخه حرفهای", "callback_data": "upgrade"}],
]
}
def handle_report(chat_id: int, user_id: int) -> None:
if user_id != ADMIN_ID:
send(chat_id, "⛔ فقط مدیر میتواند گزارش ببیند.")
return
rows = get_report()
present = [r[0] for r in rows if r[1] == "present"]
absent = [r[0] for r in rows if r[1] == "absent"]
lines = [f"📋 گزارش حضور — {date.today()}\n"]
if present:
lines.append("✅ حاضر:")
lines.extend(f" • {n}" for n in present)
if absent:
lines.append("\n❌ غایب:")
lines.extend(f" • {n}" for n in absent)
lines.append(f"\n👥 جمع: {len(present)} حاضر / {len(absent)} غایب")
send(chat_id, "\n".join(lines))
# ... ادامه کد (تا ۱۳۵ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
اطلاعیهرسان — Bale Bot (نسخه رایگان)
Broadcast to subscribed parents/students.
Free limits: 100 subscribers, 5 broadcasts/day.
بازوساز | hi@botban.ir
"""
import os, sqlite3, logging, time
from datetime import date
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
ADMIN_ID: int = int(os.getenv("ADMIN_USER_ID", "0"))
DB_PATH: str = "broadcast.db"
API_BASE: str = f"https://tapi.bale.ai/bot{TOKEN}"
MAX_SUBSCRIBERS: int = 100
MAX_DAILY_BROADCASTS: int = 5
KB_ADMIN = {"inline_keyboard": [
[{"text": "📊 آمار", "callback_data": "stats"},
{"text": "📜 تاریخچه", "callback_data": "history"}],
[{"text": "⭐ نسخه حرفهای", "callback_data": "upgrade"}],
]}
def init_db() -> None:
with sqlite3.connect(DB_PATH) as con:
con.execute("CREATE TABLE IF NOT EXISTS subscribers (user_id INTEGER PRIMARY KEY, name TEXT, joined_at TEXT NOT NULL)")
con.execute("CREATE TABLE IF NOT EXISTS broadcasts (id INTEGER PRIMARY KEY AUTOINCREMENT, message TEXT NOT NULL, sent_at TEXT NOT NULL, sent_count INTEGER NOT NULL DEFAULT 0)")
con.commit()
def add_subscriber(user_id: int, name: str) -> bool:
with sqlite3.connect(DB_PATH) as con:
if con.execute("SELECT 1 FROM subscribers WHERE user_id=?", (user_id,)).fetchone():
return False
con.execute("INSERT INTO subscribers (user_id,name,joined_at) VALUES (?,?,?)", (user_id, name, str(date.today())))
con.commit()
return True
def handle_broadcast(chat_id: int, user_id: int, body: str) -> None:
if user_id != ADMIN_ID:
send(chat_id, "⛔ فقط مدیر میتواند اطلاعیه بفرستد.")
return
msg = body.strip()
daily = daily_broadcast_count()
if daily >= MAX_DAILY_BROADCASTS:
send(chat_id, f"⛔ سقف روزانه ({MAX_DAILY_BROADCASTS}) پر شد.")
return
subscribers = all_subscriber_ids()
sent = 0
for uid in subscribers:
if api("sendMessage", {"chat_id": uid, "text": f"📢 اطلاعیه:\n\n{msg}"}).get("ok"):
sent += 1
time.sleep(0.05) # rate-limit friendly
record_broadcast(msg, sent)
send(chat_id, f"✅ اطلاعیه برای {sent} نفر ارسال شد.")
# ... ادامه کد (تا ۱۳۳ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
کوییز و آزمون — Bale Bot (نسخه رایگان)
Single fixed quiz with inline answers & leaderboard.
بازوساز | hi@botban.ir
"""
import os, json, sqlite3, logging, time
from typing import Optional
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
DB_PATH: str = "quiz.db"
QUIZ_FILE: str = os.path.join(os.path.dirname(os.path.abspath(__file__)), "quiz.json")
API_BASE: str = f"https://tapi.bale.ai/bot{TOKEN}"
OPTION_LABELS = ["الف", "ب", "ج", "د"]
def load_questions() -> list[dict]:
try:
with open(QUIZ_FILE, encoding="utf-8") as f:
return json.load(f)
except Exception as exc:
log.error("Cannot load quiz.json: %s", exc)
return []
QUESTIONS: list[dict] = load_questions()
TOTAL: int = len(QUESTIONS)
def init_db() -> None:
with sqlite3.connect(DB_PATH) as con:
con.execute("CREATE TABLE IF NOT EXISTS sessions (user_id INTEGER PRIMARY KEY, current_q INTEGER NOT NULL DEFAULT 0, correct_count INTEGER NOT NULL DEFAULT 0, started_at TEXT NOT NULL)")
con.execute("CREATE TABLE IF NOT EXISTS scores (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, name TEXT NOT NULL, score INTEGER NOT NULL, total INTEGER NOT NULL, finished_at TEXT NOT NULL)")
con.commit()
def question_keyboard(q_index: int) -> dict:
q = QUESTIONS[q_index]
return {"inline_keyboard": [[{"text": f"{OPTION_LABELS[i]}) {opt}", "callback_data": f"ans_{q_index}_{i}"}] for i, opt in enumerate(q["options"])]}
def motivational(score: int) -> str:
pct = score / TOTAL if TOTAL else 0
if pct == 1.0: return "🏆 آفرین! نمره کامل!"
if pct >= 0.8: return "🌟 عالی بود!"
if pct >= 0.6: return "💪 خیلی خوب!"
return "📚 تمرین کن، میتونی!"
def top_scores(limit: int = 5) -> list[tuple]:
with sqlite3.connect(DB_PATH) as con:
return con.execute(
"SELECT name, MAX(score) as best, total FROM scores GROUP BY user_id ORDER BY best DESC LIMIT ?",
(limit,)
).fetchall()
def handle_answer(cb: dict) -> None:
uid = cb["from"]["id"]
name = cb["from"].get("first_name", "دانشآموز")
chat_id = cb["message"]["chat"]["id"]
parts = cb.get("data", "").split("_")
q_index, choice = int(parts[1]), int(parts[2])
correct_idx: int = QUESTIONS[q_index]["answer"]
is_correct = choice == correct_idx
feedback = "✅ درسته!" if is_correct else f"❌ جواب: {OPTION_LABELS[correct_idx]})"
send(chat_id, feedback)
# ... ادامه کد (تا ۱۳۹ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
بات منوی رستوران — نسخه رایگان
Restaurant Menu Bot (Bale) — Free Version
بازوساز | hi@botban.ir
"""
import os, json, time, logging
from typing import Any
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
BASE_URL: str = f"https://tapi.bale.ai/bot{TOKEN}"
MAX_MENU_ITEMS: int = 20 # محدودیت نسخه رایگان
# بارگذاری منو از فایل JSON
with open(os.path.join(os.path.dirname(__file__), "menu.json"), encoding="utf-8") as f:
MENU: dict = json.load(f)
# سبد خرید در حافظه (user_id -> list of item dicts)
carts: dict[int, list[dict]] = {}
def format_price(price: int) -> str:
return f"{price:,} تومان"
def categories_keyboard() -> dict:
"""کیبورد دستهبندیهای منو"""
buttons = [
[{"text": data["label"], "callback_data": f"cat:{key}"}]
for key, data in MENU["categories"].items()
]
buttons.append([{"text": "🛒 سبد خرید من", "callback_data": "myorder"}])
return {"inline_keyboard": buttons}
def find_item(item_id: str) -> dict | None:
for cat in MENU["categories"].values():
for item in cat["items"]:
if item["id"] == item_id:
return item
return None
def handle_add_to_cart(chat_id: int, item_id: str) -> None:
item = find_item(item_id)
if not item:
return
cart = carts.setdefault(chat_id, [])
for entry in cart:
if entry["id"] == item_id:
entry["qty"] += 1
send_message(chat_id, f"✅ {item['name']} ({entry['qty']} عدد) در سبد.")
return
cart.append({"id": item_id, "name": item["name"], "price": item["price"], "qty": 1})
send_message(chat_id, f"✅ {item['name']} به سبد اضافه شد.\n💰 {format_price(item['price'])}")
def handle_my_order(chat_id: int) -> None:
cart = carts.get(chat_id, [])
if not cart:
send_message(chat_id, "🛒 سبد خریدت خالیه!", categories_keyboard())
return
lines = ["🛒 سبد خرید شما:\n"]
total = 0
for entry in cart:
lines.append(f"• {entry['name']} × {entry['qty']} — {format_price(entry['price'] * entry['qty'])}")
total += entry["price"] * entry["qty"]
lines.append(f"\n💰 جمع کل: {format_price(total)}")
send_message(chat_id, "\n".join(lines))
# ... ادامه کد (تا ۱۷۳ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
بات نوبتدهی کلینیک — نسخه رایگان
Clinic Appointment Bot (Bale)
بازوساز | hi@botban.ir
"""
import os, time, sqlite3, logging
from datetime import date, timedelta
from typing import Any
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
BASE_URL: str = f"https://tapi.bale.ai/bot{TOKEN}"
DB_PATH: str = os.path.join(os.path.dirname(__file__), "appointments.db")
DOCTOR_IDS: set[int] = {int(x) for x in os.getenv("DOCTOR_IDS","").split(",") if x.strip().isdigit()}
# محدودیت نسخه رایگان: فقط ۲ پزشک، فقط فردا
DOCTORS: dict[str, dict] = {
"dr_rezavi": {
"name": "دکتر رضوی",
"specialty": "اطفال",
"slots": ["۱۶:۳۰", "۱۷:۰۰", "۱۷:۳۰", "۱۸:۰۰"],
},
"dr_karimi": {
"name": "دکتر کریمی",
"specialty": "داخلی",
"slots": ["۹:۰۰", "۹:۳۰", "۱۰:۰۰", "۱۰:۳۰", "۱۱:۰۰"],
},
}
sessions: dict[int, dict] = {}
def tomorrow_str() -> str:
return (date.today() + timedelta(days=1)).strftime("%Y-%m-%d")
def doctors_keyboard() -> dict:
return {"inline_keyboard": [
[{"text": f"👨⚕️ {d['name']} ({d['specialty']})", "callback_data": f"doc:{key}"}]
for key, d in DOCTORS.items()
]}
def slots_keyboard(doctor_key: str, appt_date: str) -> dict:
booked = get_booked_slots(doctor_key, appt_date)
doctor = DOCTORS[doctor_key]
buttons = [
[{"text": f"🔴 {s} پر", "callback_data": "slot_taken"}] if s in booked
else [{"text": f"🟢 {s}", "callback_data": f"slot:{doctor_key}:{appt_date}:{s}"}]
for s in doctor["slots"]
]
buttons.append([{"text": "🔙 بازگشت", "callback_data": "back_doctors"}])
return {"inline_keyboard": buttons}
def book_appointment(user_id: int, user_name: str, doctor_key: str, appt_date: str, slot: str) -> int:
return db_run(
"INSERT INTO appointments (user_id,user_name,doctor_key,appt_date,slot) VALUES (?,?,?,?,?)",
(user_id, user_name, doctor_key, appt_date, slot)
)
# ... ادامه کد (تا ۱۳۷ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
بات رزرو آرایشگاه — نسخه رایگان
Salon Booking Bot (Bale)
بازوساز | hi@botban.ir
"""
import os, time, sqlite3, logging
from datetime import date
from typing import Any
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
BASE_URL: str = f"https://tapi.bale.ai/bot{TOKEN}"
DB_PATH: str = os.path.join(os.path.dirname(__file__), "salon.db")
ADMIN_ID: int = int(os.getenv("ADMIN_USER_ID", "0"))
# محدودیت نسخه رایگان: ۳ سرویس، ۲ استایلیست
SERVICES: dict[str, dict] = {
"haircut": {"name": "✂️ کوتاهی مو", "duration": 45, "price": 120_000},
"color": {"name": "🎨 رنگ مو", "duration": 90, "price": 350_000},
"eyebrow": {"name": "👁️ اصلاح ابرو","duration": 20, "price": 80_000},
}
STAFF: dict[str, dict] = {
"mahdavi": {"name": "خانم مهدوی ⭐ ۴.۹", "slots": ["۱۵:۰۰","۱۶:۰۰","۱۷:۳۰","۱۸:۳۰"]},
"ranjbar": {"name": "خانم رنجبر ⭐ ۴.۸", "slots": ["۱۰:۳۰","۱۱:۳۰","۱۴:۰۰","۱۶:۳۰"]},
}
sessions: dict[int, dict] = {}
def format_price(p: int) -> str:
return f"{p:,} تومان"
def services_keyboard() -> dict:
return {"inline_keyboard": [
[{"text": f"{s['name']} — {format_price(s['price'])}", "callback_data": f"svc:{key}"}]
for key, s in SERVICES.items()
]}
def staff_keyboard(service_key: str) -> dict:
buttons = [
[{"text": st['name'], "callback_data": f"stf:{service_key}:{key}"}]
for key, st in STAFF.items()
]
buttons.append([{"text": "🔙 بازگشت", "callback_data": "back_services"}])
return {"inline_keyboard": buttons}
def save_booking(user_id: int, user_name: str, service_key: str, staff_key: str, booking_date: str, slot: str) -> int:
return db_run(
"INSERT INTO bookings (user_id,user_name,service_key,staff_key,booking_date,slot) VALUES (?,?,?,?,?,?)",
(user_id, user_name, service_key, staff_key, booking_date, slot)
)
def get_booked_slots(staff_key: str, booking_date: str) -> list[str]:
return [r[0] for r in db_query(
"SELECT slot FROM bookings WHERE staff_key=? AND booking_date=? AND cancelled=0",
(staff_key, booking_date)
)]
# ... ادامه کد (تا ۱۳۵ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir
"""
بات جستجو املاک — نسخه رایگان
Real-Estate Search Bot (Bale)
بازوساز | hi@botban.ir
"""
import os, json, time, sqlite3, logging
from typing import Any
import requests
from dotenv import load_dotenv
load_dotenv()
log = logging.getLogger(__name__)
TOKEN: str = os.getenv("BALE_BOT_TOKEN", "")
BASE_URL: str = f"https://tapi.bale.ai/bot{TOKEN}"
DB_PATH: str = os.path.join(os.path.dirname(__file__), "realestate.db")
# بارگذاری آگهیها (حداکثر ۲۰ — محدودیت نسخه رایگان)
with open(os.path.join(os.path.dirname(__file__), "listings.json"), encoding="utf-8") as f:
ALL_LISTINGS: list[dict] = json.load(f)[:20]
sessions: dict[int, dict] = {}
STEPS = ["type", "city", "min_price", "max_price", "bedrooms"]
def format_price(price: int, listing_type: str) -> str:
if listing_type == "rent":
return f"{price:,} تومان/ماه"
b = price / 1_000_000_000
return f"{b:.1f} میلیارد تومان" if b >= 1 else f"{price/1_000_000:.0f} میلیون تومان"
def city_keyboard() -> dict:
cities = sorted({lst["city"] for lst in ALL_LISTINGS})
buttons = [[{"text": f"🏙️ {c}", "callback_data": f"city:{c}"}] for c in cities]
buttons.append([{"text": "📍 سایر شهرها (نسخه حرفهای)", "callback_data": "pro_city"}])
return {"inline_keyboard": buttons}
def search_listings(f: dict) -> list[dict]:
"""فیلتر مرحلهبهمرحله آگهیها"""
results = []
for lst in ALL_LISTINGS:
if lst["type"] != f.get("type"):
continue
if f.get("city") and lst["city"] != f["city"]:
continue
min_p = f.get("min_price", 0)
max_p = f.get("max_price", 10**15)
if not (min_p <= lst["price"] <= max_p):
continue
beds = f.get("bedrooms", 0)
if beds and beds != 4 and lst["bedrooms"] != beds:
continue
results.append(lst)
return results
def listing_card_text(lst: dict) -> str:
feats = "، ".join(lst.get("features", []))
return (
f"🏠 {lst['neighborhood']}، {lst['city']}\n"
f"📐 {lst['area']} متر | 🛏️ {lst['bedrooms']} خواب | طبقه {lst['floor']}\n"
f"💰 {format_price(lst['price'], lst['type'])}\n"
f"✅ {feats}"
)
def send_results(chat_id: int, results: list[dict]) -> None:
if not results:
send_message(chat_id, "😔 ملکی با این مشخصات پیدا نشد.")
return
for lst in results[:5]: # حداکثر ۵ نتیجه در نسخه رایگان
send_message(chat_id, listing_card_text(lst))
# ... ادامه کد (تا ۱۶۷ خط دیگر)
# نسخه کامل + مستندات + دیتابیس → hi@botban.ir