#! /usr/bin/env python3 # -*- coding: utf-8 -*- import logging import threading from argparse import ArgumentParser import uvicorn from fastapi import FastAPI from gewechat_client import GewechatClient import socket # 启动FastAPI服务器 # 从callback_url中提取主机和端口 import urllib.parse from configuration import Config from constants import ChatType from robot import Robot from gewechat.api.callback import router as callback_router # 配置日志 logger = logging.getLogger(__name__) def is_port_in_use(port, host='0.0.0.0'): """检查端口是否被占用""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.bind((host, port)) return False except socket.error: return True def start_fastapi_server(host="0.0.0.0", port=8999): """启动FastAPI服务器""" # 检查端口是否被占用 if is_port_in_use(port, host): logger.warning(f"端口 {port} 已被占用,尝试使用其他端口") # 尝试其他端口 for test_port in range(9000, 9100): if not is_port_in_use(test_port, host): port = test_port break else: logger.error("无法找到可用端口,服务器启动失败") return False try: app = FastAPI() app.include_router(callback_router) # 添加健康检查路由 @app.get("/health") async def health_check(): return {"status": "ok"} logger.info(f"正在启动FastAPI服务器,地址: http://{host}:{port}") # 使用线程启动uvicorn服务器 server_thread = threading.Thread( target=uvicorn.run, args=(app,), kwargs={"host": host, "port": port, "log_level": "info"}, daemon=True ) server_thread.start() logger.info(f"FastAPI 服务已在 http://{host}:{port} 启动") logger.info(f"回调URL: http://{host}:{port}/gewechat/callback") # 返回启动的端口,以便调用者知道实际使用的端口 return port except Exception as e: logger.error(f"启动FastAPI服务器失败: {e}", exc_info=True) return False def main(chat_type: int): config = Config() base_url = config.BASE_URL token = config.GEWECHAT_TOKEN app_id = config.APP_ID callback_url = config.CALLBACK_URL send_msg_wxid = "filehelper" # 要发送消息的好友昵称 parsed_url = urllib.parse.urlparse(callback_url) host = parsed_url.hostname or "0.0.0.0" port = parsed_url.port or 8999 # start_fastapi_server(host, port) # 创建 GewechatClient 实例 client = GewechatClient(base_url, token) # 登录, 自动创建二维码,扫码后自动登录 app_id, error_msg = client.login(app_id=app_id) if error_msg: print("登录失败") return resp = client.set_callback(token, callback_url) print(f"set_callback:{resp}") # 如果启动时,配置文件中的app_id为空,那么将app_id写入配置文件 if not config.APP_ID: # 更新配置文件中的APP_ID config.update_config('gewechat', 'app_id', app_id) print(f"已将新的APP_ID: {app_id} 写入配置文件") # 同时更新当前配置对象中的APP_ID config.APP_ID = app_id # 创建机器人实例 robot = Robot(config, app_id, client, chat_type) robot.LOG.info(f"WeChatRobot gewechat 成功启动···") # # 注册Robot实例到callback模块 from gewechat.api.callback import register_robot register_robot(app_id, robot) # 机器人启动发送测试消息 client.post_text(app_id, send_msg_wxid, "gewechat client 启动成功!") # # # 每天 8:30 发送新闻 # robot.onEveryTime("08:30", robot.news_baidu_report_auto) # # # epic # robot.onEveryTime("10:30", robot.send_epic_free_games) # # # message report 1:数据自动从redis 转到sqllite # robot.onEveryTime("02:30", robot.message_count_to_db) # # 从db中提取并发送给相关群 # robot.onEveryTime("09:30", robot.generate_and_send_ranking) # # # sehuatang # robot.onEveryTime("15:30", robot.generate_sehuatang_pdf) # # # 秀人网每天自动下载帖子 # robot.onEveryTime("01:30", robot.xiu_ren_download_task) # # # 秀人网每天自动发pdf # robot.onEveryTime("17:30", robot.xiu_ren_pdf_send) # 启动Dashboard服务器 dashboard_server = None # try: # # 创建Dashboard服务器实例,共享robot对象 # from admin.dashboard.server import DashboardServer # dashboard_server = DashboardServer(robot_instance=robot) # # # 在单独的线程中启动Dashboard服务器 # dashboard_thread = threading.Thread(target=dashboard_server.run, daemon=True) # dashboard_thread.start() # robot.LOG.info(f"Dashboard服务器已在 http://{dashboard_server.host}:{dashboard_server.port} 启动") # except Exception as e: # robot.LOG.error(f"Dashboard服务器启动失败: {e}") # 让机器人一直跑 robot.keep_running_and_block_process() if __name__ == "__main__": parser = ArgumentParser() parser.add_argument('-c', type=int, default=0, help=f'选择模型参数序号: {ChatType.help_hint()}') args = parser.parse_args().c main(args)