diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2dd440d --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +BOT_TOKEN=your_token_here +ADMIN_ID=your_chat_id_here diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..68491ee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# 使用轻量级的 Python 镜像 +FROM python:3.10-slim + +# 设置工作目录 +WORKDIR /app + +# 先复制依赖文件并安装(利用缓存机制) +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# 复制脚本代码 +COPY bot.py . + +# 创建一个数据卷目录,防止数据库在容器删除时丢失 +VOLUME /app/data + +# 修改脚本中的数据库路径(建议在脚本里将 DB_FILE 改为 /app/data/messages.db) +ENV DB_PATH=/app/data/messages.db + +# 启动命令 +CMD ["python", "bot.py"] + diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..5ea81f5 --- /dev/null +++ b/bot.py @@ -0,0 +1,100 @@ +import os +import logging +import aiosqlite +from telegram import Update +from telegram.ext import Application, MessageHandler, CommandHandler, filters, ContextTypes + +# --- 从环境变量读取配置 --- +BOT_TOKEN = os.getenv('BOT_TOKEN') +ADMIN_ID = int(os.getenv('ADMIN_ID', '0')) +DB_FILE = os.getenv('DB_PATH', '/app/data/messages.db') + +# 启用日志 +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + level=logging.INFO +) +logger = logging.getLogger(__name__) + +# 初始化数据库 +async def init_db(): + async with aiosqlite.connect(DB_FILE) as db: + await db.execute('''CREATE TABLE IF NOT EXISTS msg_map + (admin_msg_id INTEGER PRIMARY KEY, user_id INTEGER)''') + await db.commit() + +# 处理 /start 命令 +async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): + user_id = update.effective_chat.id + if user_id != ADMIN_ID: + await update.message.reply_text("Hello!\n\nYou can contact us using this bot.") + else: + await update.message.reply_text("你好,管理员!有人给机器人发消息时,我会转发给你。你直接【回复】该消息即可回信。") + +# 处理所有普通消息(文字、图片、语音、文件等) +async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE): + if not update.message: + return + + user_id = update.effective_chat.id + message = update.message + + # 1. 用户发给机器人 -> 转发给管理员 + if user_id != ADMIN_ID: + try: + forwarded_msg = await context.bot.forward_message( + chat_id=ADMIN_ID, + from_chat_id=user_id, + message_id=message.message_id + ) + + # 记录对应关系到数据库 + async with aiosqlite.connect(DB_FILE) as db: + await db.execute("INSERT INTO msg_map VALUES (?, ?)", + (forwarded_msg.message_id, user_id)) + await db.commit() + except Exception as e: + logger.error(f"转发失败: {e}") + + # 2. 管理员回复转发的消息 -> 回传给用户 + else: + if message.reply_to_message: + reply_id = message.reply_to_message.message_id + + async with aiosqlite.connect(DB_FILE) as db: + async with db.execute("SELECT user_id FROM msg_map WHERE admin_msg_id = ?", (reply_id,)) as cursor: + row = await cursor.fetchone() + + if row: + target_user_id = row[0] + try: + # 使用 copy_message 原样复制回复的内容 + await context.bot.copy_message( + chat_id=target_user_id, + from_chat_id=ADMIN_ID, + message_id=message.message_id + ) + except Exception as e: + await message.reply_text(f"回复发送失败,可能用户已停用机器人: {e}") + else: + await message.reply_text("找不到该消息的来源记录,无法回复。") + # 如果管理员没用回复功能,而是直接发消息,不执行任何操作 + +async def post_init(application: Application): + await init_db() + +if __name__ == '__main__': + # 检查配置 + if not BOT_TOKEN or ADMIN_ID == 0: + print("错误: 请确保环境变量 BOT_TOKEN 和 ADMIN_ID 已正确设置!") + exit(1) + + # 构建应用 + application = Application.builder().token(BOT_TOKEN).post_init(post_init).build() + + # 处理器注册 + application.add_handler(CommandHandler("start", start)) + application.add_handler(MessageHandler(filters.ALL & ~filters.COMMAND, handle_message)) + + print(f"机器人已启动... 管理员ID: {ADMIN_ID}") + application.run_polling() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9f313ef --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.8' + +services: + tg-bot: + build: . + container_name: tg-contact-bot + restart: always + # 环境变量配置 + env_file: + - .env + volumes: + - ./data:/app/data + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bd4305e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +python-telegram-bot +aiosqlite +