cheque-bot / app.py
Figmapng's picture
Create app.py
24b43e8 verified
Raw History Blame Contribute Delete
6.89 kB
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())