import os import json import logging import asyncio from datetime import datetime from aiogram import Bot, Dispatcher, types from aiogram.enums import ContentType from aiogram.filters import CommandStart from google import genai from google.oauth2.service_account import Credentials from googleapiclient.discovery import build from aiohttp import web # Настройка логирования logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # Токендер мен Кілттер TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN") GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") GOOGLE_SHEETS_ID = os.getenv("GOOGLE_SHEETS_ID") # Инициализация bot = Bot(token=TELEGRAM_TOKEN) dp = Dispatcher() ai_client = genai.Client(api_key=GEMINI_API_KEY) # Google Sheets API байланысы def append_to_sheets(rows): service_account_info = json.loads(os.getenv("GOOGLE_CREDENTIALS_JSON")) creds = Credentials.from_service_account_info( service_account_info, scopes=['https://www.googleapis.com/auth/spreadsheets'] ) service = build('sheets', 'v4', credentials=creds) sheet = service.spreadsheets() body = {'values': rows} result = sheet.values().append( spreadsheetId=GOOGLE_SHEETS_ID, range="Накладные!A2", valueInputOption="USER_ENTERED", insertDataOption="INSERT_ROWS", body=body ).execute() return result @dp.message(CommandStart()) async def cmd_start(message: types.Message): await message.answer( "👋 Сәлеметсіз бе! Мен накладнойларды есепке алу ботымын.\n\n" "Маған накладнойдың немесе чектің анық түсірілген суретін жіберіңіз. " "Мен оны автоматты түрде оқып, Google Sheets кестесіне енгіземін! 📊" ) @dp.message(lambda message: message.content_type == ContentType.PHOTO) async def handle_photo(message: types.Message): status_message = await message.answer("⏳ Сурет қабылданды. Өңделуде, күте тұрыңыз...") try: # 1. Суретті Телеграмнан жүктеп алу photo = message.photo[-1] file_info = await bot.get_file(photo.file_id) photo_bytes = await bot.download_file(file_info.file_path) # 2. Суретті жаңа Gemini API-мен оқу prompt = ( "Сен накладнойларды танитын көмекшісің. Мына суреттегі накладнойды/чекті мұқият талда. " "Бұл суреттен келесі мәліметтерді тауып, тек қана валидті JSON форматында қайтар. " "Ешқандай markdown белгілерін (мысалы ```json) қоспа, тек таза JSON текст болсын. " "Егер мәлімет жоқ болса, бостой қалдыр (null немесе пустой строка). " "Формат мынадай болуы керек:\n" "{\n" " \"date\": \"Күні (КҮН.АЙ.ЖЫЛ форматында, мысалы: 23.06.2026)\",\n" " \"supplier\": \"Жіберуші/Дүкен атауы (мысалы: Строй Сити)\",\n" " \"items\": [\n" " {\n" " \"name\": \"Тауар атауы\",\n" " \"quantity\": \"Саны (өлшем бірлігімен бірге, мысалы: 10.08 м2 немесе 3 уп)\",\n" " \"price\": \"Бір бірлігінің бағасы (тек сан)\",\n" " \"total\": \"Жалпы сомасы (тек сан)\"\n" " }\n" " ]\n" "}" ) # Жаңа SDK форматында суретті жіберу response = ai_client.models.generate_content( model='gemini-1.5-flash', contents=[ genai.types.Part.from_bytes(data=photo_bytes.getvalue(), mime_type='image/jpeg'), prompt ] ) raw_text = response.text.strip() if raw_text.startswith("```json"): raw_text = raw_text[7:] if raw_text.endswith("```"): raw_text = raw_text[:-3] raw_text = raw_text.strip() data = json.loads(raw_text) date_str = data.get("date") or datetime.now().strftime("%d.%m.%Y") supplier = data.get("supplier") or "Белгісіз" items = data.get("items", []) if not items: await status_message.edit_text("❌ Суреттен тауарлар тізімі табылмады. Қайтадан анық етіп түсіріп көріңіз.") return # 3. Google Sheets жолдарын дайындау rows_to_append = [] for item in items: rows_to_append.append([ date_str, supplier, item.get("name"), item.get("quantity"), item.get("price"), item.get("total") ]) append_to_sheets(rows_to_append) report = f"✅ Накладной сәтті өңделді және Google Sheets-ке қосылды!\n\n" report += f"📅 Күні: {date_str}\n" report += f"🏪 Жіберуші: {supplier}\n" report += f"📦 Тауар саны: {len(items)} дана\n\n" report += "Таблицаңызды тексерсеңіз болады! 📈" await status_message.edit_text(report) except Exception as e: logging.error(f"Қате орын алды: {str(e)}") await status_message.edit_text("❌ Қате орын алды: Жүйе суретті тани алмады немесе Google Sheets-ке қосыла алмады.") # Render-де Port сканерлеуден өткізу үшін шағын веб-сервер async def handle_web(request): return web.Response(text="Bot is running!") async def start_web_server(): app = web.Application() app.router.add_get('/', handle_web) runner = web.AppRunner(app) await runner.setup() port = int(os.getenv("PORT", 8000)) site = web.TCPSite(runner, '0.0.0.0', port) await site.start() logging.info(f"Веб-сервер {port} портында іске қосылды.") async def main(): # Веб-сервер мен Телеграм ботты бір уақытта іске қосу await start_web_server() await dp.start_polling(bot) if __name__ == '__main__': asyncio.run(main())