Some fix
This commit is contained in:
@@ -5,18 +5,18 @@ import sys
|
||||
import logging
|
||||
import base64
|
||||
from datetime import datetime
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram import Update
|
||||
from telegram.ext import (
|
||||
Application,
|
||||
CommandHandler,
|
||||
MessageHandler,
|
||||
CallbackQueryHandler,
|
||||
ConversationHandler,
|
||||
filters,
|
||||
ContextTypes
|
||||
)
|
||||
from telegram.request import HTTPXRequest
|
||||
import httpx
|
||||
from httpx_socks import AsyncProxyTransport
|
||||
|
||||
from config import TELEGRAM_BOT_TOKEN, PIApi_API_KEY, PIApi_BASE_URL, PROXY_URL, PROXY_TYPE
|
||||
from database import init_db, save_user, save_image_record, update_image_record, get_user_images
|
||||
@@ -24,75 +24,116 @@ import aiosqlite
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Состояния для ConversationHandler
|
||||
# Состояния
|
||||
AWAITING_PROMPT = 1
|
||||
|
||||
# Создаем директории
|
||||
# Директории
|
||||
UPLOAD_DIR = "uploads"
|
||||
PROCESSED_DIR = "processed"
|
||||
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
||||
os.makedirs(PROCESSED_DIR, exist_ok=True)
|
||||
|
||||
# Глобальная сессия
|
||||
session = None
|
||||
|
||||
|
||||
async def get_session():
|
||||
"""Создание aiohttp сессии"""
|
||||
global session
|
||||
if session is None:
|
||||
connector = None
|
||||
if PROXY_URL:
|
||||
# Создаем коннектор с прокси для aiohttp
|
||||
from aiohttp_socks import ProxyConnector
|
||||
try:
|
||||
connector = ProxyConnector.from_url(PROXY_URL)
|
||||
logger.info(f"🔌 Создан SOCKS коннектор для aiohttp")
|
||||
except:
|
||||
connector = aiohttp.TCPConnector()
|
||||
else:
|
||||
connector = aiohttp.TCPConnector()
|
||||
|
||||
session = aiohttp.ClientSession(connector=connector)
|
||||
return session
|
||||
|
||||
|
||||
async def close_session():
|
||||
"""Закрытие aiohttp сессии"""
|
||||
global session
|
||||
if session:
|
||||
await session.close()
|
||||
session = None
|
||||
|
||||
|
||||
def get_telegram_request():
|
||||
"""Правильная настройка прокси для Telegram"""
|
||||
if PROXY_URL:
|
||||
logger.info(f"🔌 Настройка прокси для Telegram: {PROXY_URL}")
|
||||
try:
|
||||
# Используем монтированный транспорт
|
||||
transport = httpx.AsyncHTTPTransport(proxy=PROXY_URL)
|
||||
"""Настройка SOCKS5 прокси для Telegram с использованием httpx_socks"""
|
||||
if not PROXY_URL:
|
||||
return None
|
||||
|
||||
logger.info(f"🔌 Настройка SOCKS5 прокси для Telegram")
|
||||
|
||||
try:
|
||||
# Парсим прокси URL
|
||||
import re
|
||||
match = re.search(r'socks5://([^:]+):([^@]+)@([^:]+):(\d+)', PROXY_URL)
|
||||
|
||||
if match:
|
||||
username = match.group(1)
|
||||
password = match.group(2)
|
||||
host = match.group(3)
|
||||
port = int(match.group(4))
|
||||
|
||||
logger.info(f"🔌 Прокси: {host}:{port}")
|
||||
|
||||
# Создаем транспорт с SOCKS5 прокси
|
||||
transport = AsyncProxyTransport.from_url(
|
||||
f"socks5://{username}:{password}@{host}:{port}"
|
||||
)
|
||||
request = HTTPXRequest(transport=transport)
|
||||
logger.info("✅ Прокси настроен успешно")
|
||||
logger.info("✅ SOCKS5 прокси настроен успешно")
|
||||
return request
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка настройки прокси: {e}")
|
||||
# Возвращаем обычный запрос без прокси
|
||||
return HTTPXRequest()
|
||||
else:
|
||||
logger.info("🔌 Прокси не используется")
|
||||
return HTTPXRequest()
|
||||
else:
|
||||
# Пробуем без авторизации
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(PROXY_URL)
|
||||
host = parsed.hostname
|
||||
port = parsed.port
|
||||
|
||||
transport = AsyncProxyTransport.from_url(f"socks5://{host}:{port}")
|
||||
request = HTTPXRequest(transport=transport)
|
||||
logger.info("✅ SOCKS5 прокси настроен (без авторизации)")
|
||||
return request
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка настройки: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def test_telegram_connection():
|
||||
"""Тест подключения к Telegram через прокси"""
|
||||
if not PROXY_URL:
|
||||
logger.error("Прокси не настроен")
|
||||
return False
|
||||
|
||||
logger.info("Тестируем подключение к Telegram через SOCKS5 прокси...")
|
||||
|
||||
try:
|
||||
# Используем aiohttp с socks прокси
|
||||
from aiohttp_socks import ProxyConnector
|
||||
|
||||
# Парсим прокси
|
||||
import re
|
||||
match = re.search(r'socks5://([^:]+):([^@]+)@([^:]+):(\d+)', PROXY_URL)
|
||||
|
||||
if match:
|
||||
username = match.group(1)
|
||||
password = match.group(2)
|
||||
host = match.group(3)
|
||||
port = int(match.group(4))
|
||||
|
||||
connector = ProxyConnector.from_url(f"socks5://{username}:{password}@{host}:{port}")
|
||||
else:
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(PROXY_URL)
|
||||
connector = ProxyConnector.from_url(f"socks5://{parsed.hostname}:{parsed.port}")
|
||||
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getMe"
|
||||
async with session.get(url, timeout=15) as response:
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
if data.get('ok'):
|
||||
logger.info(f"✅ Подключение работает! Бот: @{data['result']['username']}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Ошибка API: {data}")
|
||||
return False
|
||||
else:
|
||||
logger.error(f"HTTP {response.status}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработчик команды /start"""
|
||||
logger.info(f"✅ Получена команда /start от {update.effective_user.id}")
|
||||
"""Обработчик /start"""
|
||||
user = update.effective_user
|
||||
logger.info(f"Start от {user.id}")
|
||||
|
||||
await save_user(
|
||||
user_id=user.id,
|
||||
@@ -101,169 +142,179 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
last_name=user.last_name
|
||||
)
|
||||
|
||||
welcome_text = (
|
||||
await update.message.reply_text(
|
||||
f"👋 Привет, {user.first_name}!\n\n"
|
||||
f"Я бот для обработки фотографий через нейросеть.\n\n"
|
||||
f"📸 Просто отправь мне фото и напиши, как его изменить!\n\n"
|
||||
f"🔧 Команды:\n"
|
||||
f"📸 Отправь мне фото и напиши, как его изменить!\n\n"
|
||||
f"Команды:\n"
|
||||
f"/start - Приветствие\n"
|
||||
f"/test - Проверка работы\n"
|
||||
f"/help - Помощь\n"
|
||||
f"/history - История обработок"
|
||||
)
|
||||
await update.message.reply_text(welcome_text)
|
||||
|
||||
|
||||
async def test_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Тестовая команда"""
|
||||
logger.info(f"✅ Получена команда /test от {update.effective_user.id}")
|
||||
await update.message.reply_text("✅ Бот работает! Команды обрабатываются нормально.")
|
||||
logger.info(f"Test от {update.effective_user.id}")
|
||||
await update.message.reply_text("✅ Бот работает через SOCKS5 прокси!")
|
||||
|
||||
|
||||
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработчик команды /help"""
|
||||
logger.info(f"✅ Получена команда /help от {update.effective_user.id}")
|
||||
help_text = (
|
||||
"📖 **Инструкция:**\n\n"
|
||||
"1️⃣ Отправь фото\n"
|
||||
"2️⃣ Напиши текстовое описание изменений\n"
|
||||
"3️⃣ Получи результат!\n\n"
|
||||
"**Примеры промптов:**\n"
|
||||
"- 'сделай фон пляжем'\n"
|
||||
"- 'добавь солнечные очки'\n"
|
||||
"- 'преврати в рисунок акварелью'\n\n"
|
||||
"📊 /history - История\n"
|
||||
"🔧 /test - Проверка"
|
||||
"""Помощь"""
|
||||
await update.message.reply_text(
|
||||
"📖 Инструкция:\n\n"
|
||||
"1. Отправь фото\n"
|
||||
"2. Напиши промпт (например: 'сделай фон пляжем')\n"
|
||||
"3. Получи результат!\n\n"
|
||||
"Команды: /start, /test, /history"
|
||||
)
|
||||
await update.message.reply_text(help_text, parse_mode='Markdown')
|
||||
|
||||
|
||||
async def handle_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработчик получения фото"""
|
||||
logger.info(f"✅ Получено фото от {update.effective_user.id}")
|
||||
"""Обработка фото"""
|
||||
user = update.effective_user
|
||||
logger.info(f"Фото от {user.id}")
|
||||
|
||||
photo_file = await update.message.photo[-1].get_file()
|
||||
file_id = photo_file.file_id
|
||||
|
||||
# Сохраняем фото
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
local_filename = f"user_{user.id}_{timestamp}.jpg"
|
||||
local_path = os.path.join(UPLOAD_DIR, local_filename)
|
||||
|
||||
local_path = os.path.join(UPLOAD_DIR, f"user_{user.id}_{timestamp}.jpg")
|
||||
await photo_file.download_to_drive(local_path)
|
||||
|
||||
# Запись в БД
|
||||
image_id = await save_image_record(
|
||||
user_id=user.id,
|
||||
original_file_id=file_id,
|
||||
original_url=local_path
|
||||
)
|
||||
|
||||
context.user_data['current_image_id'] = image_id
|
||||
context.user_data['current_file_path'] = local_path
|
||||
context.user_data['image_id'] = image_id
|
||||
context.user_data['image_path'] = local_path
|
||||
|
||||
await update.message.reply_text(
|
||||
"📸 Фото получено!\n\n"
|
||||
"Теперь напиши, как изменить это фото.\n"
|
||||
"❌ Для отмены отправь /cancel"
|
||||
"Напиши, как изменить это фото.\n"
|
||||
"Например: 'сделай фон пляжем' или 'преврати в рисунок'\n\n"
|
||||
"/cancel - отмена"
|
||||
)
|
||||
|
||||
return AWAITING_PROMPT
|
||||
|
||||
|
||||
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Отмена операции"""
|
||||
logger.info(f"Отмена операции от {update.effective_user.id}")
|
||||
if 'current_file_path' in context.user_data:
|
||||
file_path = context.user_data['current_file_path']
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
"""Отмена"""
|
||||
if 'image_path' in context.user_data:
|
||||
path = context.user_data['image_path']
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
await update.message.reply_text("Операция отменена.")
|
||||
context.user_data.clear()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
async def process_image_with_prompt(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработка изображения через PiAPI"""
|
||||
async def process_image(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработка через PiAPI"""
|
||||
prompt = update.message.text
|
||||
user = update.effective_user
|
||||
logger.info(f"Получен промпт от {user.id}: {prompt}")
|
||||
logger.info(f"Промпт от {user.id}: {prompt[:50]}")
|
||||
|
||||
image_id = context.user_data.get('current_image_id')
|
||||
file_path = context.user_data.get('current_file_path')
|
||||
image_id = context.user_data.get('image_id')
|
||||
image_path = context.user_data.get('image_path')
|
||||
|
||||
if not image_id or not file_path:
|
||||
await update.message.reply_text("❌ Ошибка: изображение не найдено")
|
||||
if not image_id or not image_path:
|
||||
await update.message.reply_text("❌ Ошибка: фото не найдено")
|
||||
return ConversationHandler.END
|
||||
|
||||
status_msg = await update.message.reply_text(
|
||||
f"🎨 Обрабатываю...\n\nПромпт: {prompt}\n\n⏳ Обычно это занимает 10-30 секунд")
|
||||
f"🎨 Обрабатываю...\n\n"
|
||||
f"📝 Промпт: {prompt}\n\n"
|
||||
f"⏳ Это займет 10-30 секунд"
|
||||
)
|
||||
|
||||
try:
|
||||
async with aiosqlite.connect("bot_database.db") as db:
|
||||
await db.execute("UPDATE images SET prompt = ? WHERE id = ?", (prompt, image_id))
|
||||
await db.commit()
|
||||
|
||||
result_url = await call_piapi_image_edit(file_path, prompt)
|
||||
result_url = await call_piapi_with_proxy(image_path, prompt)
|
||||
|
||||
if result_url:
|
||||
result_filename = f"user_{user.id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_result.jpg"
|
||||
result_path = os.path.join(PROCESSED_DIR, result_filename)
|
||||
result_path = os.path.join(
|
||||
PROCESSED_DIR,
|
||||
f"user_{user.id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_result.jpg"
|
||||
)
|
||||
|
||||
current_session = await get_session()
|
||||
async with current_session.get(result_url) as resp:
|
||||
if resp.status == 200:
|
||||
with open(result_path, "wb") as f:
|
||||
f.write(await resp.read())
|
||||
# Скачиваем результат через SOCKS5
|
||||
from aiohttp_socks import ProxyConnector
|
||||
import re
|
||||
|
||||
# Удаляем сообщение о статусе
|
||||
await status_msg.delete()
|
||||
match = re.search(r'socks5://([^:]+):([^@]+)@([^:]+):(\d+)', PROXY_URL)
|
||||
if match:
|
||||
username = match.group(1)
|
||||
password = match.group(2)
|
||||
host = match.group(3)
|
||||
port = int(match.group(4))
|
||||
connector = ProxyConnector.from_url(f"socks5://{username}:{password}@{host}:{port}")
|
||||
else:
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(PROXY_URL)
|
||||
connector = ProxyConnector.from_url(f"socks5://{parsed.hostname}:{parsed.port}")
|
||||
|
||||
# Отправляем результат
|
||||
with open(result_path, "rb") as photo:
|
||||
await update.message.reply_photo(
|
||||
photo=photo,
|
||||
caption=f"✅ Готово!\n\n✨ Промпт: {prompt}"
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
async with session.get(result_url) as resp:
|
||||
if resp.status == 200:
|
||||
with open(result_path, "wb") as f:
|
||||
f.write(await resp.read())
|
||||
|
||||
await status_msg.delete()
|
||||
with open(result_path, "rb") as photo:
|
||||
await update.message.reply_photo(
|
||||
photo=photo,
|
||||
caption=f"✅ Готово!\n\n✨ {prompt}"
|
||||
)
|
||||
|
||||
msg = await update.message.reply_photo(photo=open(result_path, "rb"))
|
||||
await update_image_record(
|
||||
image_id=image_id,
|
||||
processed_file_id=msg.photo[-1].file_id,
|
||||
processed_url=result_path,
|
||||
status='completed'
|
||||
)
|
||||
|
||||
# Сохраняем file_id
|
||||
msg = await update.message.reply_photo(photo=open(result_path, "rb"))
|
||||
processed_file_id = msg.photo[-1].file_id
|
||||
|
||||
await update_image_record(
|
||||
image_id=image_id,
|
||||
processed_file_id=processed_file_id,
|
||||
processed_url=result_path,
|
||||
status='completed'
|
||||
)
|
||||
else:
|
||||
raise Exception("Ошибка загрузки результата")
|
||||
logger.info(f"Обработка успешна для {user.id}")
|
||||
else:
|
||||
raise Exception(f"HTTP {resp.status}")
|
||||
else:
|
||||
raise Exception("Не получен URL результата")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
logger.error(f"Ошибка: {error_msg}")
|
||||
await status_msg.edit_text(f"❌ Ошибка: {error_msg}\n\nПопробуйте еще раз или отправьте другое фото.")
|
||||
logger.error(f"Ошибка: {e}")
|
||||
await status_msg.edit_text(f"❌ Ошибка: {str(e)}\n\nПопробуйте еще раз.")
|
||||
await update_image_record(image_id=image_id, status='failed')
|
||||
|
||||
if os.path.exists(image_path):
|
||||
os.remove(image_path)
|
||||
|
||||
context.user_data.clear()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
async def call_piapi_image_edit(image_path: str, prompt: str) -> str:
|
||||
"""Вызов PiAPI"""
|
||||
async def call_piapi_with_proxy(image_path: str, prompt: str) -> str:
|
||||
"""Вызов PiAPI через SOCKS5 прокси"""
|
||||
if not PIApi_API_KEY:
|
||||
raise Exception("PIApi_API_KEY не настроен")
|
||||
|
||||
with open(image_path, "rb") as f:
|
||||
image_base64 = base64.b64encode(f.read()).decode('utf-8')
|
||||
|
||||
headers = {
|
||||
"x-api-key": PIApi_API_KEY,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
with open(image_path, "rb") as image_file:
|
||||
image_base64 = base64.b64encode(image_file.read()).decode('utf-8')
|
||||
|
||||
payload = {
|
||||
"model": "black-forest-labs/FLUX.1-dev",
|
||||
"task_type": "image-to-image",
|
||||
@@ -276,50 +327,87 @@ async def call_piapi_image_edit(image_path: str, prompt: str) -> str:
|
||||
}
|
||||
}
|
||||
|
||||
current_session = await get_session()
|
||||
# Создаем SOCKS5 коннектор
|
||||
from aiohttp_socks import ProxyConnector
|
||||
import re
|
||||
|
||||
async with current_session.post(PIApi_BASE_URL, headers=headers, json=payload, timeout=30) as response:
|
||||
if response.status != 200:
|
||||
raise Exception(f"HTTP {response.status}")
|
||||
match = re.search(r'socks5://([^:]+):([^@]+)@([^:]+):(\d+)', PROXY_URL)
|
||||
if match:
|
||||
username = match.group(1)
|
||||
password = match.group(2)
|
||||
host = match.group(3)
|
||||
port = int(match.group(4))
|
||||
connector = ProxyConnector.from_url(f"socks5://{username}:{password}@{host}:{port}")
|
||||
else:
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(PROXY_URL)
|
||||
connector = ProxyConnector.from_url(f"socks5://{parsed.hostname}:{parsed.port}")
|
||||
|
||||
data = await response.json()
|
||||
if data.get('code') != 200:
|
||||
raise Exception(f"API Error: {data.get('message')}")
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
async with session.post(
|
||||
PIApi_BASE_URL,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=30
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
text = await response.text()
|
||||
raise Exception(f"HTTP {response.status}: {text[:100]}")
|
||||
|
||||
task_id = data['data']['task_id']
|
||||
data = await response.json()
|
||||
if data.get('code') != 200:
|
||||
raise Exception(f"API Error: {data.get('message')}")
|
||||
|
||||
result_url = await poll_task_status(task_id, headers)
|
||||
return result_url
|
||||
task_id = data['data']['task_id']
|
||||
logger.info(f"Создана задача: {task_id}")
|
||||
|
||||
return await poll_task_with_proxy(task_id)
|
||||
|
||||
|
||||
async def poll_task_status(task_id: str, headers: dict, max_attempts: int = 60) -> str:
|
||||
"""Ожидание завершения"""
|
||||
async def poll_task_with_proxy(task_id: str, max_attempts: int = 60) -> str:
|
||||
"""Ожидание завершения задачи через SOCKS5 прокси"""
|
||||
get_url = f"https://api.piapi.ai/api/v1/task/{task_id}"
|
||||
current_session = await get_session()
|
||||
headers = {"x-api-key": PIApi_API_KEY}
|
||||
|
||||
from aiohttp_socks import ProxyConnector
|
||||
import re
|
||||
|
||||
match = re.search(r'socks5://([^:]+):([^@]+)@([^:]+):(\d+)', PROXY_URL)
|
||||
if match:
|
||||
username = match.group(1)
|
||||
password = match.group(2)
|
||||
host = match.group(3)
|
||||
port = int(match.group(4))
|
||||
connector = ProxyConnector.from_url(f"socks5://{username}:{password}@{host}:{port}")
|
||||
else:
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(PROXY_URL)
|
||||
connector = ProxyConnector.from_url(f"socks5://{parsed.hostname}:{parsed.port}")
|
||||
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
for attempt in range(max_attempts):
|
||||
try:
|
||||
async with session.get(get_url, headers=headers) as response:
|
||||
if response.status != 200:
|
||||
await asyncio.sleep(2)
|
||||
continue
|
||||
|
||||
data = await response.json()
|
||||
status = data.get('data', {}).get('status')
|
||||
|
||||
if status == 'completed':
|
||||
output = data.get('data', {}).get('output', {})
|
||||
result_url = output.get('url') or output.get('image')
|
||||
if result_url:
|
||||
logger.info(f"Задача {task_id} выполнена")
|
||||
return result_url
|
||||
elif status == 'failed':
|
||||
raise Exception("Задача не выполнена")
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
try:
|
||||
async with current_session.get(get_url, headers=headers) as response:
|
||||
if response.status != 200:
|
||||
await asyncio.sleep(2)
|
||||
continue
|
||||
|
||||
data = await response.json()
|
||||
status = data.get('data', {}).get('status')
|
||||
logger.info(f"Статус задачи {task_id}: {status} (попытка {attempt + 1})")
|
||||
|
||||
if status == 'completed':
|
||||
output = data.get('data', {}).get('output', {})
|
||||
result_url = output.get('url') or output.get('image')
|
||||
if result_url:
|
||||
return result_url
|
||||
elif status == 'failed':
|
||||
raise Exception("Задача не выполнена")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка опроса: {e}")
|
||||
await asyncio.sleep(2)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка: {e}")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
raise Exception("Превышено время ожидания")
|
||||
|
||||
@@ -330,19 +418,17 @@ async def history_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
images = await get_user_images(user.id, limit=5)
|
||||
|
||||
if not images:
|
||||
await update.message.reply_text(
|
||||
"📭 У вас пока нет обработанных изображений.\n\nОтправьте фото для начала работы!")
|
||||
await update.message.reply_text("📭 Нет обработанных изображений\n\nОтправьте фото для начала работы!")
|
||||
return
|
||||
|
||||
text = "🖼 **Ваши последние обработки:**\n\n"
|
||||
text = "🖼 **История обработок:**\n\n"
|
||||
for i, img in enumerate(images, 1):
|
||||
status_emoji = "✅" if img['status'] == 'completed' else "❌" if img['status'] == 'failed' else "⏳"
|
||||
status = "✅" if img['status'] == 'completed' else "❌"
|
||||
date = img['created_at'][:16].replace('T', ' ')
|
||||
prompt_preview = img['prompt'][:40] + "..." if img['prompt'] and len(img['prompt']) > 40 else img[
|
||||
'prompt'] or "без промпта"
|
||||
text += f"{status_emoji} **{i}.** {date}\n 📝 {prompt_preview}\n\n"
|
||||
prompt = img['prompt'][:35] + "..." if img['prompt'] and len(img['prompt']) > 35 else img[
|
||||
'prompt'] or "без промпта"
|
||||
text += f"{status} **{i}.** {date}\n 📝 {prompt}\n\n"
|
||||
|
||||
text += "💡 Отправьте новое фото для обработки!"
|
||||
await update.message.reply_text(text, parse_mode='Markdown')
|
||||
|
||||
|
||||
@@ -356,37 +442,48 @@ async def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
async def main():
|
||||
"""Запуск бота"""
|
||||
print("\n" + "=" * 50)
|
||||
print("🤖 ЗАПУСК TELEGRAM БОТА")
|
||||
print("🤖 ЗАПУСК TELEGRAM БОТА ЧЕРЕЗ SOCKS5 ПРОКСИ")
|
||||
print("=" * 50)
|
||||
|
||||
if PROXY_URL:
|
||||
print(f"🔌 Прокси: {PROXY_URL.split('@')[-1] if '@' in PROXY_URL else PROXY_URL}")
|
||||
else:
|
||||
print("🔌 Прокси: Не используется")
|
||||
if not PROXY_URL:
|
||||
print("❌ Прокси не настроен в .env файле!")
|
||||
return
|
||||
|
||||
print(f"🔌 Тип: {PROXY_TYPE.upper()}")
|
||||
print("=" * 50)
|
||||
|
||||
# Проверяем подключение
|
||||
if not await test_telegram_connection():
|
||||
print("\n❌ НЕТ ПОДКЛЮЧЕНИЯ К TELEGRAM ЧЕРЕЗ ПРОКСИ!")
|
||||
print("Проверьте настройки прокси в файле .env")
|
||||
return
|
||||
|
||||
# Инициализация
|
||||
await init_db()
|
||||
|
||||
# Создаем приложение
|
||||
request = get_telegram_request()
|
||||
if request is None:
|
||||
print("\n❌ Не удалось настроить прокси для Telegram!")
|
||||
return
|
||||
|
||||
application = Application.builder().token(TELEGRAM_BOT_TOKEN).request(request).build()
|
||||
|
||||
# Регистрируем обработчики
|
||||
application.add_handler(CommandHandler("start", start))
|
||||
application.add_handler(CommandHandler("test", test_command))
|
||||
application.add_handler(CommandHandler("help", help_command))
|
||||
application.add_handler(CommandHandler("history", history_command))
|
||||
application.add_handler(CommandHandler("test", test_command))
|
||||
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[MessageHandler(filters.PHOTO, handle_photo)],
|
||||
states={AWAITING_PROMPT: [MessageHandler(filters.TEXT & ~filters.COMMAND, process_image_with_prompt)]},
|
||||
states={AWAITING_PROMPT: [MessageHandler(filters.TEXT & ~filters.COMMAND, process_image)]},
|
||||
fallbacks=[CommandHandler("cancel", cancel)],
|
||||
)
|
||||
application.add_handler(conv_handler)
|
||||
application.add_error_handler(error_handler)
|
||||
|
||||
print("\n✅ Бот запускается...")
|
||||
print("\n✅ Бот запускается через SOCKS5 прокси...")
|
||||
|
||||
try:
|
||||
await application.initialize()
|
||||
@@ -394,11 +491,10 @@ async def main():
|
||||
await application.updater.start_polling()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("🤖 БОТ УСПЕШНО ЗАПУЩЕН!")
|
||||
print("🤖 БОТ УСПЕШНО ЗАПУЩЕН ЧЕРЕЗ SOCKS5 ПРОКСИ!")
|
||||
print("=" * 50)
|
||||
print("\n📱 Отправь команду /test в Telegram для проверки\n")
|
||||
print("\n📱 Отправь команду /test в Telegram\n")
|
||||
|
||||
# Бесконечное ожидание
|
||||
await asyncio.Event().wait()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
@@ -407,7 +503,6 @@ async def main():
|
||||
logger.error(f"Ошибка: {e}")
|
||||
print(f"\n❌ Ошибка: {e}")
|
||||
finally:
|
||||
await close_session()
|
||||
await application.updater.stop()
|
||||
await application.stop()
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@ TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
||||
PIApi_API_KEY = os.getenv("PIApi_API_KEY")
|
||||
PIApi_BASE_URL = "https://api.piapi.ai/api/v1/task"
|
||||
|
||||
# Настройки прокси
|
||||
# Прокси для всего
|
||||
PROXY_URL = os.getenv("PROXY_URL")
|
||||
PROXY_TYPE = os.getenv("PROXY_TYPE", "http")
|
||||
|
||||
# Проверка наличия прокси
|
||||
if PROXY_URL:
|
||||
print(f"🔧 Обнаружен прокси: {PROXY_URL.split('@')[-1] if '@' in PROXY_URL else PROXY_URL}")
|
||||
print(f"🔧 Прокси: {PROXY_URL.split('@')[-1] if '@' in PROXY_URL else PROXY_URL}")
|
||||
else:
|
||||
print("ℹ️ Прокси не настроен")
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
python-telegram-bot==20.7
|
||||
python-telegram-bot[socks]==20.7
|
||||
aiohttp==3.9.1
|
||||
aiosqlite==0.19.0
|
||||
python-dotenv==1.0.0
|
||||
Pillow==10.1.0
|
||||
httpx==0.25.2
|
||||
aiohttp-socks==0.8.4
|
||||
httpx-socks==0.8.0
|
||||
Reference in New Issue
Block a user