pygrammy 2.0.0
Modern Telegram Bot Framework for Python - Inspired by GrammyJS
Requires Python: >=3.8

# 🐍 PyGrammY 2.0

**PyGrammY 2.0** — Python uchun **to'liq asinxron**, **Grammy.js'dan ilhomlangan**, zamonaviy **Telegram Bot Framework**.  
Barcha Telegram media turlari, inline query, poll, va boshqa imkoniyatlarni qo'llab-quvvatlaydi.

[![Version](https://img.shields.io/badge/version-2.0.0-blue.svg)](https://github.com/yourusername/pygrammy)
[![Python](https://img.shields.io/badge/python-3.8+-brightgreen.svg)](https://python.org)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)

---

## 🚀 Xususiyatlar

### ✨ Core Features
- ⚡ **To'liq asinxron** (`async/await`)
- 🌐 **httpx** asosida Telegram Bot API
- 🧠 **Context (ctx)** — barcha ma'lumotlar bitta joyda
- 🔌 **Middleware chain** (GrammyJS uslubida)
- 💾 **Session** (memory & file storage)
- 🧩 **Composer** — modular bot arxitekturasi
- 🎯 **Kuchli filters** (regex, file extension, user/chat ID)
- 🪝 **Polling** va **Webhook** qo'llab-quvvatlanadi
- 🛡️ **Global error handling**

### 📦 Media Support
- 📸 **Photo** (rasm)
- 🎥 **Video** 
- 🎵 **Audio**
- 🎤 **Voice** (ovozli xabar)
- 📹 **Video Note** (dumaloq video)
- 🎞️ **Animation** (GIF)
- 🏷️ **Sticker**
- 📄 **Document** (har qanday fayl)
- 📍 **Location** (joylashuv)
- 🏢 **Venue** (joy)
- 📞 **Contact** (kontakt)
- 📊 **Poll** (so'rov)
- 🎲 **Dice** (zar, nishon, va boshqalar)
- 📦 **Media Groups** (bir nechta media birga)

### ⌨️ Keyboards
- 🖱️ **InlineKeyboard** — inline tugmalar
- ⌨️ **Keyboard** — reply klaviatura
- 🗑️ **RemoveKeyboard** — klaviaturani olib tashlash
- 💬 **ForceReply** — javob berishga majburlash

### 🔍 Advanced Features
- 🔎 **Inline Query** qo'llab-quvvatlanadi
- 📨 **Message forwarding & copying**
- 📌 **Pin/Unpin messages**
- ✏️ **Edit messages** (matn, media, keyboard)
- 🗑️ **Delete messages**
- 📥 **File download**
- 👥 **Chat management** (ban, restrict, promote)
- 💬 **Chat actions** (typing, upload_photo, va boshqalar)

---

## 📦 O'rnatish

### PyPI orqali (kelajakda)
```bash
pip install pygrammy
```

### Lokal o'rnatish

```bash
# Dependencies o'rnatish
pip install httpx aiohttp

# Loyihani clone qilish
git clone https://github.com/yourusername/pygrammy
cd pygrammy

# O'rnatish
pip install -e .
```

---

## 🧑‍💻 Minimal misol

```python
import asyncio
from pygrammy import Bot

bot = Bot("YOUR_BOT_TOKEN")

@bot.command("start")
async def start(ctx):
    await ctx.reply("👋 Salom! PyGrammY 2.0 ishlayapti!")

async def main():
    async with bot:
        await bot.start()

asyncio.run(main())
```

---

## 📚 O'rganish

### Media yuborish

```python
from pygrammy import Bot, InputFile

bot = Bot("TOKEN")

@bot.command("photo")
async def send_photo(ctx):
    # URL orqali
    await ctx.replyWithPhoto("https://example.com/photo.jpg", 
                             caption="Rasm!")
    
    # Lokal fayl
    await ctx.sendPhoto(InputFile("photo.jpg"), caption="Lokal rasm")
    
    # File ID
    await ctx.sendPhoto("AgACAgIAAxkBAAI...", caption="File ID")

@bot.command("video")
async def send_video(ctx):
    await ctx.replyWithVideo(
        InputFile("video.mp4"),
        caption="🎥 Video",
        supports_streaming=True
    )

@bot.command("audio")
async def send_audio(ctx):
    await ctx.sendAudio(
        InputFile("song.mp3"),
        title="Qo'shiq nomi",
        performer="Ijrochi"
    )
```

### Media Group

```python
from pygrammy import InputMediaPhoto, InputMediaVideo, InputFile

@bot.command("album")
async def send_album(ctx):
    media = [
        InputMediaPhoto("https://example.com/1.jpg", caption="Birinchi"),
        InputMediaPhoto("https://example.com/2.jpg", caption="Ikkinchi"),
        InputMediaVideo(InputFile("video.mp4"), caption="Video")
    ]
    await ctx.sendMediaGroup(media)
```

### Inline Keyboard

```python
from pygrammy import InlineKeyboard

@bot.command("menu")
async def menu(ctx):
    kb = InlineKeyboard()
    kb.text("👍 Like", "like").text("👎 Dislike", "dislike")
    kb.row()
    kb.url("🌐 Website", "https://example.com")
    kb.switch_inline_query("🔍 Search", "query")
    
    await ctx.reply("Tanlang:", reply_markup=kb)

@bot.callback_query("like")
async def like_handler(ctx):
    await ctx.answerCallbackQuery("Rahmat! 👍")
    await ctx.editMessageText("Sizga yoqdi! ❤️")
```

### Reply Keyboard

```python
from pygrammy import Keyboard

@bot.command("keyboard")
async def keyboard(ctx):
    kb = Keyboard()
    kb.text("🏠 Bosh sahifa").text("👤 Profil")
    kb.row()
    kb.request_contact("📞 Kontakt")
    kb.request_location("📍 Joylashuv")
    kb.resized().one_time()
    
    await ctx.reply("Tanlang:", reply_markup=kb)
```

### ForceReply

```python
from pygrammy import ForceReply

@bot.command("ask")
async def ask(ctx):
    await ctx.reply(
        "Ismingiz nima?",
        reply_markup=ForceReply(
            input_field_placeholder="Ismingizni kiriting..."
        )
    )
```

### Session

```python
from pygrammy import session

bot.use(session(initial=lambda: {"count": 0}))

@bot.on("message:text")
async def counter(ctx):
    ctx.session["count"] += 1
    await ctx.reply(f"Xabarlar soni: {ctx.session['count']}")
```

### Filters

```python
from pygrammy import Filters

# Media filtrlari
@bot.filter(Filters.photo)
async def photo_handler(ctx):
    await ctx.reply("📸 Rasm qabul qilindi!")

@bot.filter(Filters.video)
async def video_handler(ctx):
    await ctx.reply("🎥 Video qabul qilindi!")

# Regex filter
@bot.filter(Filters.regex(r"(?i)salom|hello"))
async def greeting(ctx):
    await ctx.reply("👋 Salom!")

# User ID filter
@bot.filter(Filters.user_id(123456, 789012))
async def admin_only(ctx):
    await ctx.reply("👑 Admin panel")

# File extension filter
@bot.filter(Filters.file_extension("pdf", "docx"))
async def document_handler(ctx):
    await ctx.reply("📄 PDF yoki DOCX fayl!")

# Kombinatsiya
admin_filter = Filters.user_id(123456) & Filters.private_chat
@bot.filter(admin_filter)
async def admin_private(ctx):
    await ctx.reply("Admin + Private chat")
```

### Message Operations

```python
# Forward
@bot.command("forward")
async def forward(ctx):
    if ctx.message.reply_to_message:
        await ctx.forwardMessage(
            from_chat_id=ctx.chat_id,
            message_id=ctx.message.reply_to_message.message_id
        )

# Copy (forward signature'siz)
@bot.command("copy")
async def copy(ctx):
    if ctx.message.reply_to_message:
        await ctx.copyMessage(
            from_chat_id=ctx.chat_id,
            message_id=ctx.message.reply_to_message.message_id
        )

# Pin
@bot.command("pin")
async def pin(ctx):
    if ctx.message.reply_to_message:
        await ctx.pinChatMessage(
            message_id=ctx.message.reply_to_message.message_id
        )

# Delete
@bot.command("delete")
async def delete(ctx):
    await ctx.deleteMessage()
```

### Chat Actions

```python
@bot.command("typing")
async def typing_demo(ctx):
    await ctx.sendChatAction("typing")
    await asyncio.sleep(3)
    await ctx.reply("Yozdim!")

# Actions: typing, upload_photo, record_video, upload_video,
#          record_voice, upload_voice, upload_document,
#          choose_sticker, find_location, record_video_note
```

### Poll

```python
@bot.command("poll")
async def create_poll(ctx):
    await ctx.sendPoll(
        question="PyGrammY 2.0 qanday?",
        options=["😍 Zo'r", "👍 Yaxshi", "😐 O'rtacha"],
        is_anonymous=False,
        allows_multiple_answers=False
    )

# Poll to'xtatish
@bot.command("stop_poll")
async def stop_poll(ctx):
    if ctx.message.reply_to_message:
        await ctx.stopPoll(
            message_id=ctx.message.reply_to_message.message_id
        )
```

### Inline Query

```python
@bot.on("inline_query")
async def inline_handler(ctx):
    query = ctx.inline_query.query
    
    results = [
        {
            "type": "article",
            "id": "1",
            "title": "Salom",
            "description": "Salomlashish",
            "input_message_content": {
                "message_text": f"👋 Salom! Query: {query}"
            }
        },
        {
            "type": "photo",
            "id": "2",
            "photo_url": "https://example.com/photo.jpg",
            "thumb_url": "https://example.com/thumb.jpg",
            "caption": "Rasm natijasi"
        }
    ]
    
    await ctx.answerInlineQuery(results, cache_time=300)
```

### File Download

```python
@bot.on("message:document")
async def download_file(ctx):
    doc = ctx.message.document
    
    # File info olish
    file_info = await ctx.getFile(doc.file_id)
    
    # Download qilish
    file_bytes = await ctx.downloadFile(doc.file_id)
    
    # Yoki faylga saqlash
    await ctx.downloadFile(doc.file_id, f"downloads/{doc.file_name}")
    
    await ctx.reply(f"✅ Fayl yuklandi: {doc.file_name}")
```

### Middleware

```python
@bot.use
async def logger(ctx, next):
    print(f"Update: {ctx.update.update_id}")
    print(f"User: {ctx.from_user.first_name if ctx.from_user else 'N/A'}")
    await next()

@bot.use
async def auth_middleware(ctx, next):
    allowed_users = [123456, 789012]
    if ctx.from_user and ctx.from_user.id in allowed_users:
        await next()
    else:
        await ctx.reply("⛔️ Kirish taqiqlangan!")
```

### Error Handling

```python
@bot.catch
async def error_handler(error, ctx):
    print(f"❌ Error: {error}")
    if ctx and ctx.chat_id:
        await ctx.reply("Xatolik yuz berdi. Qayta urinib ko'ring.")
```

### Webhook

```python
await bot.start(webhook={
    "domain": "https://example.com",
    "path": "/webhook",
    "port": 8443
})
```

---

## 🧩 Composer (Modular Architecture)

```python
# handlers/start.py
from pygrammy import Composer

start_router = Composer()

@start_router.command("start")
async def start(ctx):
    await ctx.reply("Salom!")

# main.py
from handlers.start import start_router

bot.use(start_router)
```

---

## 📖 To'liq misol

`example_bot.py` faylida barcha xususiyatlarni o'z ichiga olgan to'liq misol bor:

```bash
# Bot tokenini kiriting
python example_bot.py
```

Misol botda:
- ✅ Barcha media turlari
- ✅ Inline va Reply keyboards
- ✅ Session
- ✅ Filters
- ✅ Inline query
- ✅ Polls
- ✅ Message forwarding
- ✅ File download
- ✅ Error handling

---

## 🆚 GrammyJS bilan taqqoslash

| Xususiyat           | GrammyJS        | PyGrammY 2.0    |
| ------------------- | --------------- | --------------- |
| Til                 | JavaScript/TS   | Python          |
| Async               | Promise         | async/await     |
| HTTP                | fetch           | httpx           |
| Typing              | TypeScript      | Type hints      |
| Middleware          | ✅              | ✅              |
| Session             | ✅              | ✅              |
| Filters             | ✅              | ✅              |
| Inline Query        | ✅              | ✅              |
| Media Groups        | ✅              | ✅              |
| File Download       | ✅              | ✅              |

---

## 🔄 1.0 → 2.0 O'zgarishlar

### Yangi xususiyatlar
- ✅ Barcha media turlari (Audio, Video, Animation, Voice, VideoNote, Sticker)
- ✅ InputFile va InputMedia class'lari
- ✅ ForceReply keyboard
- ✅ Inline query qo'llab-quvvatlanadi
- ✅ Poll yaratish va boshqarish
- ✅ Message forward/copy/pin operatsiyalari
- ✅ File download funksiyasi
- ✅ Chat management metodlari
- ✅ Chat actions (typing, upload_photo, va h.k.)
- ✅ Kengaytirilgan filtrlar (regex, file extension, user/chat ID)
- ✅ Grammy.js uslubida metodlar (`replyWithPhoto`, `sendChatAction`)

### Backward Compatibility
Version 1.0 API'lari hamma ham ishlaydi! Yangi features qo'shimcha imkoniyatlar.

---

## 📝 Litsenziya

MIT License - batafsil ma'lumot uchun [LICENSE](LICENSE) faylini ko'ring.

---

## 🤝 Hissa qo'shish

Pull request'lar va issue'lar qabul qilinadi!

1. Fork qiling
2. Feature branch yarating (`git checkout -b feature/amazing`)
3. Commit qiling (`git commit -m 'Add amazing feature'`)
4. Push qiling (`git push origin feature/amazing`)
5. Pull Request oching

---

## 📞 Aloqa

- GitHub Issues: [pygrammy/issues](https://github.com/yourusername/pygrammy/issues)
- Telegram: [@yourusername](https://t.me/yourusername)

---

## ⭐️ Rahmat!

Agar PyGrammY yoqsa, ⭐️ bosishni unutmang!

**Happy Coding! 🚀**