From b573ac1dfe7f58d9d17127675f0a3a4d93dc4dec Mon Sep 17 00:00:00 2001 From: aaron <> Date: Thu, 1 May 2025 13:46:37 +0800 Subject: [PATCH] update --- .gitignore | 2 + README.md | 41 +++++++++++- cryptoai/__pycache__/main.cpython-313.pyc | Bin 1503 -> 1513 bytes .../__pycache__/crypto_agent.cpython-313.pyc | Bin 19776 -> 20413 bytes cryptoai/agents/crypto_agent.py | 14 +++- cryptoai/agents/gold_agent.py | 14 +++- cryptoai/config/config.yaml | 15 ++++- cryptoai/main.py | 9 ++- cryptoai/utils/__init__.py | 6 +- .../__pycache__/__init__.cpython-313.pyc | Bin 219 -> 416 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 6779 -> 5655 bytes cryptoai/utils/config_loader.py | 34 ++-------- cryptoai/utils/discord_bot.py | 63 ++++++++++++++++++ docker-compose.yml | 2 +- 14 files changed, 161 insertions(+), 39 deletions(-) create mode 100644 cryptoai/utils/discord_bot.py diff --git a/.gitignore b/.gitignore index d4f7977..b432af3 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ wheels/ .installed.cfg *.egg + + # 虚拟环境 venv/ ENV/ diff --git a/README.md b/README.md index f12f385..fd01315 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - 利用DeepSeek大模型进行市场分析和预测 - 提供市场趋势、价格预测和交易建议 - 支持多种加密货币分析 -- 通过钉钉机器人发送分析结果 +- 通过钉钉机器人和Discord Webhook发送分析结果 ## 项目结构 @@ -98,6 +98,10 @@ OKX_PASSPHRASE=OKX密码 DINGTALK_ENABLED=true/false DINGTALK_WEBHOOK_URL=钉钉Webhook地址 DINGTALK_SECRET=钉钉密钥 + +# Discord机器人 +DISCORD_ENABLED=true/false +DISCORD_WEBHOOK_URL=Discord Webhook地址 ``` 在Docker中可以通过`-e`参数或`.env`文件传递环境变量。 @@ -175,4 +179,39 @@ curl -X POST "http://localhost:8000/api/analyze" \ "symbol": "BTC", "task_type": "市场分析" }' +``` + +## 消息通知 + +项目支持多种消息通知方式,可以将分析结果发送到不同的平台。 + +### 钉钉机器人 + +在配置文件中设置钉钉机器人的Webhook URL和密钥,启用后会将分析结果发送到钉钉群聊。 + +```yaml +dingtalk: + enabled: true + webhook_url: your_dingtalk_webhook_url + secret: your_dingtalk_secret +``` + +### Discord机器人 + +在配置文件中设置Discord Webhook URL,启用后会将分析结果以精美的嵌入式消息发送到Discord频道。 + +```yaml +discord: + enabled: true + webhook_url: your_discord_webhook_url + username: CryptoAI分析机器人 + avatar_url: https://cdn-icons-png.flaticon.com/512/2878/2878497.png +``` + +#### 测试Discord机器人 + +可以使用以下命令测试Discord机器人的功能: + +```bash +python -m cryptoai.tests.test_discord_bot --webhook your_webhook_url ``` \ No newline at end of file diff --git a/cryptoai/__pycache__/main.cpython-313.pyc b/cryptoai/__pycache__/main.cpython-313.pyc index b6f962bcee868ca5cef6373fd8eff0eb4913bc87..895eaca83c0b5a41041380fb5e4d699ffef4709e 100644 GIT binary patch delta 396 zcmcc5{gRvSGcPX}0}zD263S3y-N<*6k%@(I@=ZoFrfAm54;hV9*+8-&z|N4!$H1V# z5X}kUGcW`*nleJz3JmfL=?u|elb~vK7#Q-9)iQ-L@G%%OA#?;Y2QzrH zWXd(zsMnfg+uWUhj2IVbq>Xg9Ew*t zlz)6tnEaI4Sxy?Lyve|rVY8^CJ@Y{>P7o=qiw(2CX3ezFUTk-#mE;^d6fl+v8k zTP!7+xv7&ISXS$U?7PJgAD@?)n;IX#lHoIu&rl=)7PZOE2dTCzQUh{90aRQwIf^wy gMv77HgB1e{Pe;{dX33i@9Ib92m>F24id2D008HOn`2YX_ delta 457 zcmYk2y-Nc@5XEP2?{t&X!zhCBBheHpC_?f*@EP zR{jOSN?R*SOHmNF(ZWKzfEJeSA)*8On8*BvVc)y`Y&##ly>ZahUhA)pbX_{PDE^@B z8Kj_u!i2HFhN5v)-9R0HaVS|o9-xR8(N8}PX{bPH_;;e&Spfc@H8#M31>K8g zINCt#>9B3o5Bfxx-dA=YsgN$MFfNtliyD_AI;ludt}?H=&6LG+e fhs>&urBJG~g23!K*}KQdCzBknbugI2Vn#FH3YT#+ diff --git a/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc b/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc index 5717230221bf0a4afa649690a21aeab2fa4d2c74..f4e3e69e0cb94b50214ba027b67de7b36f7b0fe1 100644 GIT binary patch delta 2639 zcmZWqeQaA-6@S+s&)-hskJ^bH$6rnI>NOwaqe+@(b=;&~v$ZsC3!-9gFZN5~#ql%u zKCcZE>c$_aXafnZrVaK-ThK%bn%2n@LV}H~sMDyZs71lysi0B`p&|Zg8Kba&#y!t* z6X41Iy>rhw_k7)R&)fJedgmf?f8=u6IrdEa)wBHk?6=%OwElL_*HJRdWgT;gqe+~M zazQT6Wt|;d)-_@PU5>-MmyqD5AD|z)1*F*z6-Z9O`DsP1Vgqk5ylk$1+4LHspEn2S z%~mhnFgsdX8ap}eOiZWf3BH34@rNj~c;6CgqOZ*38E3k*pC|PPc5x8!KV6|eN8IcGJ+a(l+%rbo03!9 ze56TlzaLrmwRN*h_BSP<4Sv(DX2#04jUyJ&BU?NCdA9wXIndm_BgHOSw07CNV1-$T z!piU4S~cpXOXd&KOI86*(;L}0>UBcvUl^HAdk>-d#u}&!)s+#5zopC z%ZjohR&bH2fkFjbY&8ZwY|o%1eaU{eQ}Zmzs+eyyjF?kOi-jf4y|t!!M`=cLG^GoQ zirc_fD+A4*Ul3QN5{m}oC~%=3nuV;bE+|EU<7_1uH4~AGi`Y-i&NZac^UjNb%}Bf+ z8K^}D>XA$>lKD+!=7QPmbQ_xo{Mg!A(a?-4UrdB6UZ+=7?V!Uzh8S;hJOk zPM5G5j@HBdwQ&EffkUb`L3wln+>o^yF_dG_9R_R*mGtL7Vy_Bm9&=zh|~ zj^=NkgD6e+dQUsj5bZ3$Vfsz)CK{tlzE0sY5WXL(v0Q*M7jjZjTqzbxaw8edEU%W; zH9SP$^hNrhM>HFeo|DDAq)LJfPl7?+^fbuqM3t~As)bdVx%szm5KYmP{{Z@8wctkv zbh^3{cn+aCdM}t79)qpA#a(4Am$8zQ31P*>D{wZEo%vwx<}W*$PBiRPd^#;tBd1`#gHJFJTw6KQH&X$J z2yDm@7wNB4oypf3shQyr^7wO%CN2iioe!%)>tp@sUiIK(2~#hIt%QMK#4szc9_NpM zVQTn!1Gs7W(m zYhTi56(#L3M6qAxHTGrk|Q&-PpJ8`Z(Fgvs>^*15#6PY+lU_qJ`Y}M=@jC$T0{k2R%8oY}XuN!m%?_f+u6g8hWd%mS zwjVr3Bbks@?`&3Nn$8>!>WvHM-0a&%{MYHFOcH&gdOh<`V?yuK8{p5bg(n&cTBKLjXMhF#!Ei!Q~auF#&xDUu@Rg8TL9R1U0KDmZVi# z6g7J8iShG~Gqz?dlvF&=D4Ye*XNCln5ddPx+aqJU{do}R1-S+kR0aQqf#w%QHh9%S zPLxy?7Zxh2OhgfvKmppIQCu&hx-npY{YjFw^w+rGn~py)rI9&}E@eLEbmGCRfu1~i zwX4S*SPx!JT)ihK|aWAoO`eDV_4pwr-`|#F5Nnq6uR{W(Trq`Xna{J}mFdHx3u&4jZ6 delta 2267 zcmZWpeQZ-z6o0p0Ygf9@t{dw<3LA{a+!tdXg^e*LD6m1;027BRZ|!50^^0@ga6=7h zqNp(ua*ZKKWDzAuA_1EK>L5d+@`oBoK;^|4LV}UM01+_6M9+C$Wonc6>$&Iap8GrJ z-ZKZ;0n5n;1L~KE!*gWEfO>4?cc}r6NoV3(5C2Wu)`DtChoR&67y&ln7 zneWZ8qN>mCXXsauw)Q!2?n8S(7w1Tp;bZd)T%U{1?y`Sn;YEXh@*fl5@#J%tc*O%^QJt@ z)1E^PZt_Xo6f+4 zRc25um~*bJgzTlF#yLyucGfeWIPJV9CT0vZLXMF(G#H2~F$@DJBUdU(&){Rx!FYs& z4_C5Tw{SJG1>9n*YmDWK>#l=hU)DqMQ})Z&3uQA`x|6}2ZVPJ{$K6X=o4DiN=xn1@ zodnB7Z^4gjp{VwhvRbjy<8@I^-Ks_t+8ES{?VhsQ2GTgVvO^7o6ityG&_ba`l6JCX za!mm(poOCYYLf(txML;+`-riak#j8;X(>EGI|oACLkVEIma`? zu&Np9VJ&*d)@ggJ6IO2{ru2KO*`B28-Oloi0s`pBX@-41@QYtd{Jz7ap$U6Y`rRYt zxZm3O#?F1!N0dw1^%w2+Fp%slEw-hChyE2Dt>|G%@p;93HjwRTB z=3n@OF0pa`x1I#50mzmCYA_BVF593@_^XGJ*$=B1*$h&A;zsrN1;$A?PypQsSWU1= zTzqVvQzda5LA@~7G_*g7qV5Ru_?9?C6%A;Rb+d;pzGw;`|CK;4c}iFk~wx^;xp5WPcID`gHrFUs77;G6zKCNJ02v8zc- zZG~lC6wMGrkj>CcvT-P)8K>N6!Z>N$#M%WV*rCV*KbtQOFX;6SpgK79zMv>ccKpov z-OWknH(oUDy_7F}R=enJp5+*AHsw$|erjLJ z0YnzOM?hu3QG%5Sx+%_e3tcYVvMnBtK{YAuQDs;Sg@MCvatsP@YvbYtWN~pd7BU7e z6n{3R=Lgi$M4YBLKCH$923@j!iem~LClKO5Ybze~N^6U)4WA(1k<9bYWp%f0lEd|b z-FM0EyKJ9*E!*>2)`M~>tL2KT`5~Wyk>_g*m$#U|Y{^_<&4BUb?nM3RRB#%PFMFoc(O+CBk% z2r$T)&lGpMRf~s|F+F>lmpHb(zQ~w9YG``+Ql~j9?k}%oFD1Pz?wg-6hV4Anbe3w$ zU9FA{#uW&yjA{5DjwCc=C*7fe5>yA3;IQsUKscshD}(9zG%h4<20tTk3j*zkV;);2 zvqNIvs&k>-)Z1E1UKIqh2#i~6Fhb9jaVb;1s-h*$5Y!OV5zHZ=$2oOPd??9mjm&PA zkz|4;;_KC`b}hn%ZpI3s2PIfTV7w5UNTTZjR3JQhARf)QjSL1E6C@EMa1B8(2pF`7 zg8@a;AUrstsXP#XFgXkm7-N!$QY8=;;>Ty>@V+WtwXD5kX|;B;@veIk{om1;IN5!? zywX~Dr096XN2RwV6elYu`Gu~@(Q~!;XnDI^ywbCz+{jG{ str: diff --git a/cryptoai/config/config.yaml b/cryptoai/config/config.yaml index ed5f027..fef88a9 100644 --- a/cryptoai/config/config.yaml +++ b/cryptoai/config/config.yaml @@ -27,8 +27,10 @@ crypto: base_currencies: - "BTC" - "ETH" - # - "SOL" - # - "SUI" + - "SOL" + - "SUI" + - "XRP" + - “DOGE” quote_currency: "USDT" time_interval: "4h" # 可选: 1m, 5m, 15m, 30m, 1h, 4h, 1d historical_days: 90 @@ -38,7 +40,7 @@ gold: # 黄金交易对 symbols: ["GOLD"] # 历史数据天数 - historical_days: 30 + historical_days: 90 # 时间间隔 time_interval: "4h" @@ -60,6 +62,13 @@ dingtalk: at_mobiles: [] # 需要@的手机号列表 at_all: false # 是否@所有人 +# Discord机器人配置 +discord: + enabled: true + crypto_webhook_url: "https://discord.com/api/webhooks/1286585288986198048/iQ-yr26ViW45GM48ql8rPu70Iumqcmn_XXAmxAcKGeiQBmTQoDPeq-TmlChvIHkw_HJ-" + gold_webhook_url: "https://discord.com/api/webhooks/1367341235987021914/XVcjs6ZAZad3ZezzuudyiK_KqNUowqz2o2NJPdvwWY_EvwZVJcnVHq5M0-RQhkKV-FEQ" + + # 数据库配置 database: host: "gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com" diff --git a/cryptoai/main.py b/cryptoai/main.py index 5709046..351558e 100644 --- a/cryptoai/main.py +++ b/cryptoai/main.py @@ -26,13 +26,18 @@ def main(): print("定时程序启动") CryptoAgent().start_agent() # 设置 08:00, 20:00 运行一次 + schedule.every().day.at("00:00").do(CryptoAgent().start_agent) schedule.every().day.at("08:00").do(CryptoAgent().start_agent) + schedule.every().day.at("12:00").do(CryptoAgent().start_agent) + schedule.every().day.at("16:00").do(CryptoAgent().start_agent) schedule.every().day.at("20:00").do(CryptoAgent().start_agent) + schedule.every().day.at("00:00").do(GoldAgent().start_agent) schedule.every().day.at("08:00").do(GoldAgent().start_agent) + schedule.every().day.at("12:00").do(GoldAgent().start_agent) + schedule.every().day.at("16:00").do(GoldAgent().start_agent) schedule.every().day.at("20:00").do(GoldAgent().start_agent) - # 启动定时任务 while True: schedule.run_pending() time.sleep(1) @@ -46,5 +51,5 @@ def main(): traceback.print_exc() -if __name__ == "__main__": +if __name__ == "__main__": main() \ No newline at end of file diff --git a/cryptoai/utils/__init__.py b/cryptoai/utils/__init__.py index 6ec6832..8cb6549 100644 --- a/cryptoai/utils/__init__.py +++ b/cryptoai/utils/__init__.py @@ -1,4 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -"""工具模块,提供各种辅助功能。""" \ No newline at end of file +"""工具模块,提供各种辅助功能。""" + +from cryptoai.utils.dingtalk_bot import DingTalkBot +from cryptoai.utils.discord_bot import DiscordBot +from cryptoai.utils.config_loader import ConfigLoader \ No newline at end of file diff --git a/cryptoai/utils/__pycache__/__init__.cpython-313.pyc b/cryptoai/utils/__pycache__/__init__.cpython-313.pyc index fcca2b9931ba04ce7ef5854f010c5967ba5540ea..e5124097d8a6604e569e2697cc30ae57c8475df0 100644 GIT binary patch delta 303 zcmcc3xPUq0GcPX}0}v$M5X$%qq#uJgFu(+5eAWRnrZNOG6fp!d1~YjxdNCC-DS+6_ z-ppPsMJ!-8i#MwmTM?TALprM_+e8!n`j;T>nvA!&T{831LlSeco$^b7TrQW);^h3I z6bO&UIX^EgGu5 mAD@z+93MYfn=wF!4X6a9z8GZO2WCb_#!nm!jD|%lKrR3m*WWGP+0tNZjJE$<0qG%}KQ@N}KF0rO2Pi$f*5^0Yrio F0RT%OWk&!2 delta 1248 zcmb7@%TE(Q7{F(@?{2%Tr3G4|wsb{Sp}Z3w(xeCmNobLwkthL6yFhvD*4Y+PE_f^l zgJfeMo@ipy9ynn5A3PeHMrk(Oy@HyUXiS{tnE)~R9lo7!^80?7`6jzj_p6ouW;PoE zj_r(P=BIU?epxv}0Pq@&0YpH6NJtRmJ{5k^}R7pE# zhUSTj{Z;@{_@NT5qfK4-bz*ouXaZm~5I!3HpbY>DxIvg;0Be(sWz34K z>+PB755W;xJtK(8qjD%TjLU?8j>|CY8kBvdXBB}Z0>4s{KOUs(Y$b5YOoa%+XmopDwyPG7n!(6-?LnDf4C0`?e=HkR8Ycv%#H?BGX-T`!C`v|7EV Dict[str, Any]: + """获取Discord机器人配置""" + return self.get_config('discord') + def get_database_config(self) -> Dict[str, Any]: """获取数据库配置""" - # 首先从配置文件获取 - db_config = self.get_config('database') - # 使用环境变量覆盖(如果存在) - if os.environ.get('DB_HOST'): - db_config['host'] = os.environ.get('DB_HOST') - if os.environ.get('DB_PORT'): - db_config['port'] = int(os.environ.get('DB_PORT')) - if os.environ.get('DB_USER'): - db_config['user'] = os.environ.get('DB_USER') - if os.environ.get('DB_PASSWORD'): - db_config['password'] = os.environ.get('DB_PASSWORD') - if os.environ.get('DB_NAME'): - db_config['db_name'] = os.environ.get('DB_NAME') - - # 确保返回默认值(如果配置不存在) - default_config = { - 'host': 'gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com', - 'port': 27469, - 'user': 'root', - 'password': 'Aa#223388', - 'db_name': 'cryptoai' - } - - # 合并默认配置和实际配置 - for key, value in default_config.items(): - if key not in db_config: - db_config[key] = value - - return db_config \ No newline at end of file + return self.get_config('database') \ No newline at end of file diff --git a/cryptoai/utils/discord_bot.py b/cryptoai/utils/discord_bot.py new file mode 100644 index 0000000..25aa3e5 --- /dev/null +++ b/cryptoai/utils/discord_bot.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json +import requests +import traceback +import datetime +from typing import Dict, Any, List, Optional, Union + +class DiscordBot: + """Discord Webhook机器人,用于发送分析结果到Discord频道""" + + def __init__(self, webhook_url: str): + """ + 初始化Discord Webhook机器人 + + Args: + webhook_url: Discord Webhook的URL + """ + self.webhook_url = webhook_url + + def send_message(self, content: str, username: str = None, avatar_url: str = None) -> Dict[str, Any]: + """ + 发送普通消息 + + Args: + content: 消息内容 + username: 自定义机器人名称 + avatar_url: 自定义机器人头像URL + + Returns: + 接口返回结果 + """ + data = {"content": content} + + if username: + data["username"] = username + + if avatar_url: + data["avatar_url"] = avatar_url + + return self._post(data) + + def _post(self, data: Dict[str, Any]) -> Dict[str, Any]: + """ + 发送数据到Discord Webhook + + Args: + data: 要发送的数据 + + Returns: + 接口返回结果 + """ + try: + headers = {'Content-Type': 'application/json'} + response = requests.post(self.webhook_url, json=data, headers=headers) + if response.status_code == 204: # Discord返回成功时无内容 + return {"success": True} + return response.json() + except Exception as e: + print(f"发送Discord消息时出错: {e}") + traceback.print_exc() + return {"success": False, "error": str(e)} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f6a168e..7b61d30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: cryptoai: build: . container_name: cryptoai-task - image: cryptoai:0.0.9 + image: cryptoai:0.0.10 restart: always volumes: - ./cryptoai/data:/app/cryptoai/data