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