from telegram import Update, InlineKeyboardButton,...
Criado em: 8 de fevereiro de 2025
Criado em: 8 de fevereiro de 2025
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid
BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176
user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}
TEXTS = {
"en": {
"welcome": (
"<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n"
"<b>Buy and sell anything – safely!</b>\n\n"
"From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n"
"🔹 Convenient wallet management\n"
"🔹 Referral system\n\n"
"<b>Please select a section below:</b>"
),
"btn_add_wallet": "🪙 Add Wallet",
"btn_create_deal": "🤝 Create a Deal",
"btn_profile": "👤 Profile",
"btn_change_language": "🌐 Change Language",
"btn_support": "📞 Support",
"add_wallet_placeholder": (
"🪙 This is a placeholder for the 'Add Wallet' section.\n"
"Here you would guide users to link or manage their wallets."
),
"ask_second_username": (
"<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:"
),
"profile_view": (
"👤 <b>Your Profile</b>\n\n"
"• Name: {first_name} {last_name}\n"
"• Username: @{username}\n"
"• Balance: {balance} USDT\n"
"• Preferred Language: {lang}\n"
),
"language_changed": (
"Language changed to: <b>{lang}</b>\n"
"(In a real bot, you’d reload text in that language.)"
),
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
"deal_confirm_msg": (
"<b>You are about to create a deal with @{second_user}.</b>\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"<b>Confirm creation?</b>"
),
"deal_insufficient_balance": (
"<b> You do not have enough balance to create this deal. Cancelled.</b>"
),
"deal_created": (
"✅ Deal created! Deal ID: {deal_id}\n\n"
"Waiting for @{second_user} to accept."
),
"deal_canceled": "Deal creation canceled.",
"deal_notify_second_user": (
"👋 You have a new deal request from @{creator_username}!\n\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"Deal ID: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ We do not have a record of @{username}'s user ID. "
"They need to start the bot first so we can notify them."
),
"deal_accepted": (
"✅ You have accepted the deal {deal_id}.\n\n"
"Funds are now in escrow. Please proceed with the exchange of the item."
),
"deal_insufficient_after_accept": (
"Creator does not have sufficient funds. Deal canceled."
),
"deal_creator_notified_accepted": (
"Your deal {deal_id} was accepted by @{second_username}. "
"{amount} USDT is now frozen in escrow."
),
"deal_declined": "❌ You have declined the deal {deal_id}.",
"deal_creator_notified_declined": (
"Your deal {deal_id} was declined by @{second_username}."
),
"deal_prompt_received": (
"Once you receive the item, press the button below to release escrow to the seller.\n"
"If there's a problem, please contact support."
),
"deal_received_confirmed": (
"✅ You have confirmed receipt. Deal {deal_id} is completed!\n"
"You received {amount} USDT from escrow."
),
"deal_creator_notified_completed": (
"The buyer confirmed receipt. Deal {deal_id} is completed!\n"
"Your {amount} USDT has been released to them."
),
"not_authorized": "You are not authorized to perform this action.",
"add_money_success": "Added {amount} USDT to user {target_id}'s balance.",
"balance_increased_notification": (
"Good news! You've received {amount} USDT. "
"Your new balance is {new_balance} USDT."
),
"deal_not_found": "This deal no longer exists or was not found.",
"deal_not_waiting": "This deal is not awaiting acceptance.",
"deal_not_accepted_state": "This deal is not in an active (accepted) state.",
"not_second_user": "You are not the second participant of this deal.",
"not_in_deal_flow": "Use the main menu or /start to begin creating a deal.",
"invalid_amount": "Invalid amount. Please enter a number.",
},
"ru": {
"welcome": (
"<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n"
"<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n"
"От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n"
"🔹 Удобное управление кошельками\n"
"🔹 Реферальная система\n\n"
"<b>Пожалуйста, выберите раздел ниже:</b>"
),
"btn_add_wallet": "🪙 Добавить кошелек",
"btn_create_deal": "🤝 Создать сделку",
"btn_profile": "👤 Профиль",
"btn_change_language": "🌐 Сменить язык",
"btn_support": "📞 Поддержка",
"add_wallet_placeholder": (
"🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n"
"Здесь вы можете связать или управлять своими кошельками."
),
"ask_second_username": (
"Пожалуйста, введите <b>@username</b> второго участника сделки "
"(можете не писать '@'):"
),
"profile_view": (
"👤 <b>Ваш профиль</b> \n\n"
"• Имя: {first_name} {last_name}\n"
"• Логин: @{username}\n"
"• Баланс: {balance} USDT\n"
"• Предпочитаемый язык: {lang}\n"
),
"language_changed": (
"Язык изменен на: <b>{lang}</b>\n"
),
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
"deal_confirm_msg": (
"Вы собираетесь создать сделку с @{second_user}.\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"Подтвердить создание?"
),
"deal_insufficient_balance": (
"У вас недостаточно средств для создания сделки. Отменено."
),
"deal_created": (
"✅ Сделка создана! ID сделки: {deal_id}\n\n"
"Ожидаем подтверждения от @{second_user}."
),
"deal_canceled": "Создание сделки отменено.",
"deal_notify_second_user": (
"👋 У вас новый запрос на сделку от @{creator_username}!\n\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"ID сделки: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ У нас нет данных о пользователе @{username}. "
"Он должен сначала запустить бота, чтобы мы могли уведомить его."
),
"deal_accepted": (
"✅ Вы приняли сделку {deal_id}.\n\n"
"Средства заморожены. Пожалуйста, проведите обмен товаром."
),
"deal_insufficient_after_accept": (
"У создателя больше недостаточно средств. Сделка отменена."
),
"deal_creator_notified_accepted": (
"Ваша сделка {deal_id} была принята пользователем @{second_username}. "
"{amount} USDT заморожено в эскроу."
),
"deal_declined": "❌ Вы отклонили сделку {deal_id}.",
"deal_creator_notified_declined": (
"Ваша сделка {deal_id} была отклонена пользователем @{second_username}."
),
"deal_prompt_received": (
"Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n"
"Если что-то не так, свяжитесь со службой поддержки."
),
"deal_received_confirmed": (
"✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n"
"Вы получили {amount} USDT из эскроу."
),
"deal_creator_notified_completed": (
"Покупатель подтвердил получение. Сделка {deal_id} завершена!\n"
"Ваши {amount} USDT были переведены ему."
),
"not_authorized": "У вас нет прав для этого действия.",
"add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.",
"balance_increased_notification": (
"Отличные новости! Вы получили {amount} USDT.\n"
"Ваш новый баланс: {new_balance} USDT."
),
"deal_not_found": "Сделка не найдена или уже не существует.",
"deal_not_waiting": "Сделка не ожидает подтверждения.",
"deal_not_accepted_state": "Сделка находится не в статусе 'принята'.",
"not_second_user": "Вы не являетесь вторым участником данной сделки.",
"not_in_deal_flow": "Используйте главное меню или /start для создания сделки.",
"invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.",
}
}
def t(user_id: int, key: str) -> str:
lang = user_language.get(user_id, "en")
return TEXTS[lang].get(key, f"Missing translation for {key}")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id
if user.id not in user_language:
user_language[user.id] = "en"
lang = user_language[user.id]
welcome_text = t(user.id, "welcome")
buttons = [
[InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')],
[InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')],
[InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')],
[InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')],
[InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')]
]
reply_markup = InlineKeyboardMarkup(buttons)
photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png"
await update.message.reply_photo(
photo=photo_url,
caption=welcome_text,
reply_markup=reply_markup,
parse_mode="HTML"
)
async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
if user.username:
username_to_id[user.username.lower()] = user_id
lang = user_language.get(user_id, "en")
if query.data == 'add_wallet':
await query.edit_message_caption(
caption=t(user_id, "add_wallet_placeholder"),
parse_mode="HTML"
)
elif query.data == 'create_deal':
user_deal_steps[user_id] = 'waiting_for_second_username'
await query.edit_message_caption(
caption=t(user_id, "ask_second_username"),
parse_mode="HTML"
)
elif query.data == 'profile':
balance = user_balances.get(user_id, 0.0)
profile_text = t(user_id, "profile_view").format(
first_name=user.first_name if user.first_name else "",
last_name=user.last_name if user.last_name else "",
username=(user.username if user.username else "N/A"),
balance=balance,
lang=lang
)
await query.edit_message_caption(caption=profile_text, parse_mode="HTML")
elif query.data == 'change_language':
new_lang = "ru" if lang == "en" else "en"
user_language[user_id] = new_lang
await query.edit_message_caption(
caption=t(user_id, "language_changed").format(lang=new_lang.upper()),
parse_mode="HTML"
)
async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return
try:
target_user_id = int(context.args[0])
amount = float(context.args[1])
except (IndexError, ValueError):
await update.message.reply_text("Usage: /add_money <user_id> <amount>")
return
if target_user_id not in user_balances:
user_balances[target_user_id] = 0.0
user_balances[target_user_id] += amount
await update.message.reply_text(
t(user_id, "add_money_success").format(
amount=amount,
target_id=target_user_id
)
)
try:
target_lang = user_language.get(target_user_id, "en")
await context.bot.send_message(
chat_id=target_user_id,
text=TEXTS[target_lang]["balance_increased_notification"].format(
amount=amount,
new_balance=user_balances[target_user_id]
)
)
except Exception:
pass
async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
user_id = user.id
text = update.message.text.strip()
if user.username:
username_to_id[user.username.lower()] = user_id
if user_id in user_deal_steps:
step = user_deal_steps[user_id]
if step == 'waiting_for_second_username':
context.user_data['deal_second_username'] = text.lstrip('@').lower()
user_deal_steps[user_id] = 'waiting_for_topic'
await update.message.reply_text(t(user_id, "deal_step_topic"))
return
elif step == 'waiting_for_topic':
context.user_data['deal_topic'] = text
user_deal_steps[user_id] = 'waiting_for_amount'
await update.message.reply_text(t(user_id, "deal_step_amount"))
return
elif step == 'waiting_for_amount':
try:
amount = float(text)
except ValueError:
await update.message.reply_text(t(user_id, "invalid_amount"))
return
context.user_data['deal_amount'] = amount
second_user_username = context.user_data.get('deal_second_username')
topic = context.user_data.get('deal_topic')
msg = t(user_id, "deal_confirm_msg").format(
second_user=second_user_username,
topic=topic,
amount=amount
)
reply_markup = InlineKeyboardMarkup([
[
InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"),
InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation")
]
])
await update.message.reply_text(msg, reply_markup=reply_markup)
user_deal_steps[user_id] = 'waiting_for_creation_confirmation'
return
else:
await update.message.reply_text(t(user_id, "not_in_deal_flow"))
async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
if user.username:
username_to_id[user.username.lower()] = user_id
lang = user_language.get(user_id, "en")
if query.data == 'confirm_deal_creation':
if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation':
await query.edit_message_text("No active deal creation to confirm.")
return
second_user_username = context.user_data['deal_second_username']
topic = context.user_data['deal_topic']
amount = context.user_data['deal_amount']
creator_balance = user_balances.get(user_id, 0.0)
if creator_balance < amount:
await query.edit_message_text(t(user_id, "deal_insufficient_balance"))
user_deal_steps.pop(user_id, None)
return
deal_id = uuid.uuid4().hex
second_user_id = username_to_id.get(second_user_username)
active_deals[deal_id] = {
'creator': user_id,
'second_user': second_user_id,
'topic': topic,
'amount': amount,
'status': 'waiting_for_accept'
}
user_deal_steps.pop(user_id, None)
await query.edit_message_text(
t(user_id, "deal_created").format(
deal_id=deal_id,
second_user=second_user_username
)
)
if second_user_id:
second_user_lang = user_language.get(second_user_id, "en")
deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format(
creator_username=user.username,
topic=topic,
amount=amount,
deal_id=deal_id
)
btns = [
[
InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"),
InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}")
]
]
try:
await context.bot.send_message(
chat_id=second_user_id,
text=deal_info,
reply_markup=InlineKeyboardMarkup(btns)
)
except Exception:
await context.bot.send_message(
chat_id=user_id,
text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username)
)
else:
await context.bot.send_message(
chat_id=user_id,
text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username)
)
elif query.data == 'cancel_deal_creation':
user_deal_steps.pop(user_id, None)
await query.edit_message_text(t(user_id, "deal_canceled"))
elif query.data.startswith('accept_') or query.data.startswith('decline_'):
deal_id = query.data.split('', 1)[1]
if deal_id not in active_deals:
await query.edit_message_text(t(user_id, "deal_not_found"))
return
deal = active_deals[deal_id]
if user_id != deal['second_user']:
await query.edit_message_text(t(user_id, "not_second_user"))
return
if deal['status'] != 'waiting_for_accept':
await query.edit_message_text(t(user_id, "deal_not_waiting"))
return
if query.data.startswith('accept'):
deal['status'] = 'accepted'
creator_id = deal['creator']
amount = deal['amount']
if user_balances.get(creator_id, 0.0) < amount:
deal['status'] = 'canceled'
await query.edit_message_text(t(user_id, "deal_insufficient_after_accept"))
return
user_balances[creator_id] -= amount
deal['frozen_amount'] = amount
await query.edit_message_text(
t(user_id, "deal_accepted").format(deal_id=deal_id)
)
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format(
deal_id=deal_id,
second_username=user.username,
amount=amount
)
)
except Exception:
pass
final_btns = [
[
InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}")
]
]
prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"]
await context.bot.send_message(
chat_id=user_id,
text=prompt_text,
reply_markup=InlineKeyboardMarkup(final_btns)
)
else:
deal['status'] = 'declined'
await query.edit_message_text(
t(user_id, "deal_declined").format(deal_id=deal_id)
)
creator_id = deal['creator']
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_declined"].format(
deal_id=deal_id,
second_username=user.username
)
)
except Exception:
pass
elif query.data.startswith('received_'):
deal_id = query.data.split('_', 1)[1]
if deal_id not in active_deals:
await query.edit_message_text(t(user_id, "deal_not_found"))
return
deal = active_deals[deal_id]
if deal['status'] != 'accepted':
await query.edit_message_text(t(user_id, "deal_not_accepted_state"))
return
if user_id != deal['second_user']:
await query.edit_message_text(t(user_id, "not_second_user"))
return
amount = deal.get('frozen_amount', 0.0)
creator_id = deal['creator']
second_user_id = deal['second_user']
if amount > 0:
user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount
deal['status'] = 'completed'
deal['frozen_amount'] = 0.0
await query.edit_message_text(
t(user_id, "deal_received_confirmed").format(
deal_id=deal_id,
amount=amount
)
)
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_completed"].format(
deal_id=deal_id,
amount=amount
)
)
except Exception:
pass
def main():
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("add_money", add_money))
application.add_handler(
CallbackQueryHandler(
handle_main_menu_callback,
pattern='^(add_wallet|create_deal|profile|change_language)$'
)
)
application.add_handler(
CallbackQueryHandler(
handle_deal_callback,
pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)'
)
)
application.add_handler(
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text)
)
application.run_polling()
if name == 'main':
main()
can u make Назад button under Язык изменен на: text
Below is an example of how you can add a "Назад" (Back) button after changing the language. The idea is:
'main_menu'
to the callback patternIn the CallbackQueryHandler
for the main menu callbacks, we should include main_menu
in the pattern:
pythonapplication.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) )
handle_main_menu_callback
to handle the "Назад" caseWe add an elif query.data == 'main_menu':
block that effectively re-displays the main menu:
pythonasync def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Switch language new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Show the "Language changed" text with a "Назад" button back_button = InlineKeyboardMarkup([ [InlineKeyboardButton("Назад", callback_data="main_menu")] ]) await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # If the original message is a photo with a caption, # you can edit the caption instead of text: await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )
With these changes:
data='main_menu'
, which simply re-displays the main menu.integrate it into my text please
Below is the updated code with the "Назад" (Back) button integrated right after changing the language. The main changes are:
|main_menu
to the callback query pattern.elif query.data == 'main_menu'
block that restores the main menu.pythonfrom telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" "(In a real bot, you’d reload text in that language.)" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" "• Имя: {first_name} {last_name}\n" "• Логин: @{username}\n" "• Баланс: {balance} USDT\n" "• Предпочитаемый язык: {lang}\n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path in your code). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Show the "Language changed" text with a "Назад" button back_button = InlineKeyboardMarkup([ [InlineKeyboardButton("Назад", callback_data="main_menu")] ]) await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()
pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$'
We expanded the pattern to include "main_menu"
, so when the user taps the “Назад” button, the callback data equals "main_menu"
, which our bot can handle.
Inside elif query.data == 'change_language':
"Назад"
, which points to "main_menu"
.Inside elif query.data == 'main_menu':
We rebuild the main menu buttons (in the user’s current language) and use edit_message_caption
to restore the original welcome text and menu inline keyboard.
With this, after the user changes the language, they see the text indicating it has changed plus a Назад button. Pressing that button takes them back to the main menu.
Can you make it so if its Language changed to: EN
(In a real bot, you’d reload text in that language.) button is gonna be Back and if its on russian its gonna be назад
Below is a modified version of the code where the Back button text depends on the newly selected language:
All other logic remains the same.
pythonfrom telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" "(In a real bot, you’d reload text in that language.)" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" "• Имя: {first_name} {last_name}\n" "• Логин: @{username}\n" "• Баланс: {balance} USDT\n" "• Предпочитаемый язык: {lang}\n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()
elif query.data == 'change_language':
block, after we switch the user’s language, we now set:
This ensures the button label is "Назад" for Russian and "Back" for English.pythonback_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ])
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid
BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176
user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}
TEXTS = {
"ru": {
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
# дальше код без изменений
},
"en": {
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
# дальше код без изменений
}
}
def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
return TEXTS.get(lang, {}).get(key, f"Missing translation for {key}")
async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()
textif user.username: username_to_id[user.username.lower()] = user_id if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' print(f"LANG: {user_language.get(user_id)}, TEXT: {t(user_id, 'deal_step_topic')}") await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return else: await update.message.reply_text(t(user_id, "not_in_deal_flow")) "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": " <b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b> :", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", }
def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
return TEXTS[lang].get(key, f"Missing translation for {key}")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Start command, shows the main menu with a welcome message and buttons."""
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id
text# Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" )
async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.)."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
textif user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )
async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin-only command to add money to a user's balance."""
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return
texttry: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass
async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()
textif user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow"))
async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles deal-related callbacks: confirming creation, accepting, declining, etc."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
textif user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass
def main():
application = Application.builder().token(BOT_TOKEN).build()
text# Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling()
if name == 'main':
main()
C:\Users\1234\AppData\Local\Programs\Python\Python313\python.exe "C:\Users\1234\Downloads\12 29\New folder\yabloko (2).py"
File "C:\Users\1234\Downloads\12 29\New folder\yabloko (2).py", line 62
"en": {
^^^^
SyntaxError: illegal target for annotation
Process finished with exit code 1
fix pls
Below is a fixed version of your code. The main issue was that there was a second "en": { ... }
dictionary declaration inside the code, causing Python to throw SyntaxError: illegal target for annotation
.
You only need one TEXTS
dictionary that includes both "ru"
and "en"
translations. Also, you only need one definition of the def t(user_id: int, key: str) -> str:
function.
Here’s a merged/fixed code snippet:
pythonfrom telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} # Single unified TEXTS dictionary TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") # Return the requested key from the correct language dictionary return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm receipt final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (including "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()
"en": { ... }
definition that was floating in the middle of the file.TEXTS
dictionary.def t(user_id: int, key: str):
function.With this structure, Python will no longer see the syntax error, and your bot code should run without the illegal target for annotation
issue.
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid
BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176
user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}
TEXTS = {
"en": {
"welcome": (
"<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n"
"<b>Buy and sell anything – safely!</b>\n\n"
"From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n"
"🔹 Convenient wallet management\n"
"🔹 Referral system\n\n"
"<b>Please select a section below:</b>"
),
"btn_add_wallet": "🪙 Add Wallet",
"btn_create_deal": "🤝 Create a Deal",
"btn_profile": "👤 Profile",
"btn_change_language": "🌐 Change Language",
"btn_support": "📞 Support",
"add_wallet_placeholder": (
"🪙 This is a placeholder for the 'Add Wallet' section.\n"
"Here you would guide users to link or manage their wallets."
),
"ask_second_username": (
"<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:"
),
"profile_view": (
"👤 <b>Your Profile</b>\n\n"
"• Name: {first_name} {last_name}\n"
"• Username: @{username}\n"
"• Balance: {balance} USDT\n"
"• Preferred Language: {lang}\n"
),
"language_changed": (
"Language changed to: <b>{lang}</b>\n"
),
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
"deal_confirm_msg": (
"<b>You are about to create a deal with @{second_user}.</b>\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"<b>Confirm creation?</b>"
),
"deal_insufficient_balance": (
"<b> You do not have enough balance to create this deal. Cancelled.</b>"
),
"deal_created": (
"✅ Deal created! Deal ID: {deal_id}\n\n"
"Waiting for @{second_user} to accept."
),
"deal_canceled": "Deal creation canceled.",
"deal_notify_second_user": (
"👋 You have a new deal request from @{creator_username}!\n\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"Deal ID: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ We do not have a record of @{username}'s user ID. "
"They need to start the bot first so we can notify them."
),
"deal_accepted": (
"✅ You have accepted the deal {deal_id}.\n\n"
"Funds are now in escrow. Please proceed with the exchange of the item."
),
"deal_insufficient_after_accept": (
"Creator does not have sufficient funds. Deal canceled."
),
"deal_creator_notified_accepted": (
"Your deal {deal_id} was accepted by @{second_username}. "
"{amount} USDT is now frozen in escrow."
),
"deal_declined": "❌ You have declined the deal {deal_id}.",
"deal_creator_notified_declined": (
"Your deal {deal_id} was declined by @{second_username}."
),
"deal_prompt_received": (
"Once you receive the item, press the button below to release escrow to the seller.\n"
"If there's a problem, please contact support."
),
"deal_received_confirmed": (
"✅ You have confirmed receipt. Deal {deal_id} is completed!\n"
"You received {amount} USDT from escrow."
),
"deal_creator_notified_completed": (
"The buyer confirmed receipt. Deal {deal_id} is completed!\n"
"Your {amount} USDT has been released to them."
),
"not_authorized": "You are not authorized to perform this action.",
"add_money_success": "Added {amount} USDT to user {target_id}'s balance.",
"balance_increased_notification": (
"Good news! You've received {amount} USDT. "
"Your new balance is {new_balance} USDT."
),
"deal_not_found": "This deal no longer exists or was not found.",
"deal_not_waiting": "This deal is not awaiting acceptance.",
"deal_not_accepted_state": "This deal is not in an active (accepted) state.",
"not_second_user": "You are not the second participant of this deal.",
"not_in_deal_flow": "Use the main menu or /start to begin creating a deal.",
"invalid_amount": "Invalid amount. Please enter a number.",
},
"ru": {
"welcome": (
"<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n"
"<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n"
"От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n"
"🔹 Удобное управление кошельками\n"
"🔹 Реферальная система\n\n"
"<b>Пожалуйста, выберите раздел ниже:</b>"
),
"btn_add_wallet": "🪙 Добавить кошелек",
"btn_create_deal": "🤝 Создать сделку",
"btn_profile": "👤 Профиль",
"btn_change_language": "🌐 Сменить язык",
"btn_support": "📞 Поддержка",
"add_wallet_placeholder": (
"🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n"
"Здесь вы можете связать или управлять своими кошельками."
),
"ask_second_username": (
"Пожалуйста, введите <b>@username</b> второго участника сделки "
"(можете не писать '@'):"
),
"profile_view": (
"👤 <b>Ваш профиль</b> \n\n"
" <b>• Имя: {first_name} {last_name}</b> \n"
"• <b>Логин: @{username}</b> \n"
"• <b>Баланс: {balance} USDT</b> \n"
"• <b>Предпочитаемый язык: {lang}</b> \n"
),
"language_changed": (
"Язык изменен на: <b>{lang}</b>\n"
),
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
"deal_confirm_msg": (
"Вы собираетесь создать сделку с @{second_user}.\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"Подтвердить создание?"
),
text"deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", }
}
def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
# Return the requested key from the correct language dictionary
return TEXTS[lang].get(key, f"Missing translation for {key}")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Start command, shows the main menu with a welcome message and buttons."""
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id
text# Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" )
async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.)."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
textif user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )
async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin-only command to add money to a user's balance."""
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return
texttry: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass
async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()
textif user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow"))
async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles deal-related callbacks: confirming creation, accepting, declining, etc."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
textif user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm receipt final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass
def main():
application = Application.builder().token(BOT_TOKEN).build()
text# Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (including "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling()
if name == 'main':
main()
Убери кнопку смены языка
Below is your updated code without the language-change button. All the logic for multi-language support remains (in case you still want to handle users in different languages), but there is no button for the user to toggle language.
btn_change_language
line from the buttons
in start()
.elif query.data == 'change_language':
block in handle_main_menu_callback
."change_language"
from the callback query handler pattern.pythonfrom telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} # Single unified TEXTS dictionary TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_support": "📞 Support", # Removed "btn_change_language" "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b>You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_support": "📞 Поддержка", # Removed "btn_change_language" "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def