fix: support legacy Discord channel env alias and align docs (#659)

This commit is contained in:
Xavier Zhou
2026-03-15 20:09:14 +09:00
committed by GitHub
parent 76fe472f17
commit 7b7eff7187
9 changed files with 66 additions and 12 deletions

View File

@@ -234,6 +234,7 @@ AGENT_SKILLS=bull_trend,ma_golden_cross,volume_breakout,shrink_pullback
# 3. 获取频道 IDDiscord 开启开发者模式 -> 右键频道 -> 复制 ID
# DISCORD_BOT_TOKEN=
# DISCORD_MAIN_CHANNEL_ID=
# DISCORD_CHANNEL_ID= # 兼容旧变量名,推荐改用 DISCORD_MAIN_CHANNEL_ID
#
# 【方式九】Server酱3 配置(国内推送服务,支持微信推送)
# 注册Server酱3账号并获取SendKey https://sc3.ft07.com/

View File

@@ -9,7 +9,7 @@
[![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-Ready-2088FF?logo=github-actions&logoColor=white)](https://github.com/features/actions)
[![Docker](https://img.shields.io/badge/Docker-Ready-2496ED?logo=docker&logoColor=white)](https://hub.docker.com/)
> 🤖 基于 AI 大模型的 A股/港股/美股自选股智能分析系统,每日自动分析并推送「决策仪表盘」到企业微信/飞书/Telegram/邮箱
> 🤖 基于 AI 大模型的 A股/港股/美股自选股智能分析系统,每日自动分析并推送「决策仪表盘」到企业微信/飞书/Telegram/Discord/邮箱
[**功能特性**](#-功能特性) · [**快速开始**](#-快速开始) · [**推送效果**](#-推送效果) · [**完整指南**](docs/full-guide.md) · [**常见问题**](docs/FAQ.md) · [**更新日志**](docs/CHANGELOG.md)
@@ -40,7 +40,7 @@
| 历史记录 | 批量管理 | 支持多选、全选及批量删除历史分析记录,优化管理效率与 UI/UX 体验 |
| 回测 | AI 回测验证 | 自动评估历史分析准确率,方向胜率、止盈止损命中率 |
| **Agent 问股** | **策略对话** | **多轮策略问答,支持均线金叉/缠论/波浪等 11 种内置策略Web/Bot/API 全链路** |
| 推送 | 多渠道通知 | 企业微信、飞书、Telegram、钉钉、邮件、Pushover |
| 推送 | 多渠道通知 | 企业微信、飞书、Telegram、Discord、钉钉、邮件、Pushover |
| 自动化 | 定时运行 | GitHub Actions 定时执行,无需服务器 |
> 历史报告详情会优先展示 AI 返回的原始「狙击点位」文本,避免区间价、条件说明等复杂内容在历史回看时被压缩成单个数字。
@@ -115,6 +115,9 @@
| `TELEGRAM_BOT_TOKEN` | Telegram Bot Token@BotFather 获取) | 可选 |
| `TELEGRAM_CHAT_ID` | Telegram Chat ID | 可选 |
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID (用于发送到子话题) | 可选 |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | 可选 |
| `DISCORD_BOT_TOKEN` | Discord Bot Token与 Webhook 二选一) | 可选 |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID使用 Bot 时需要) | 可选 |
| `EMAIL_SENDER` | 发件人邮箱(如 `xxx@qq.com` | 可选 |
| `EMAIL_PASSWORD` | 邮箱授权码(非登录密码) | 可选 |
| `EMAIL_RECEIVERS` | 收件人邮箱(多个用逗号分隔,留空则发给自己) | 可选 |

View File

@@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- 📖 **.env.example** — added `AGENT_ARCH` and `AGENT_NL_ROUTING` configuration documentation
### Fixed
- 🎮 **Discord channel env compatibility** — runtime now accepts legacy `DISCORD_CHANNEL_ID` as a fallback for `DISCORD_MAIN_CHANNEL_ID`, and the docs/examples now use the same variable name as the actual workflow/config implementation
- 🐛 **Session secret rotation on Windows** — use atomic replace so auth toggles invalidate existing sessions even when `.session_secret` already exists
- 🐛 **Auth toggle atomicity** — persist `ADMIN_AUTH_ENABLED` before rotating session secret; on rotation failure, roll back to the previous auth state
- 🔧 **LLM runtime selection guardrails** — YAML 模式下渠道编辑器不再覆盖 `LITELLM_MODEL` / fallback / Vision系统配置校验补上全部渠道禁用后的运行时来源检查并修复 `vertexai/...` 这类协议别名模型被重复加前缀的问题

View File

@@ -95,7 +95,7 @@
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID (用於發送到子話題) | 可選 |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | 可選 |
| `DISCORD_BOT_TOKEN` | Discord Bot Token與 Webhook 二選一) | 可選 |
| `DISCORD_CHANNEL_ID` | Discord Channel ID使用 Bot 時需要) | 可選 |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID使用 Bot 時需要) | 可選 |
| `EMAIL_SENDER` | 發件人郵箱(如 `xxx@qq.com` | 可選 |
| `EMAIL_PASSWORD` | 郵箱授權碼(非登錄密碼) | 可選 |
| `EMAIL_RECEIVERS` | 收件人郵箱(多個用逗號分隔,留空則發給自己) | 可選 |

View File

@@ -97,7 +97,7 @@ Go to your forked repo → `Settings` → `Secrets and variables` → `Actions`
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID (For sending to topics) | Optional |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | Optional |
| `DISCORD_BOT_TOKEN` | Discord Bot Token (choose one with Webhook) | Optional |
| `DISCORD_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `EMAIL_SENDER` | Sender email (e.g., `xxx@qq.com`) | Optional |
| `EMAIL_PASSWORD` | Email authorization code (not login password) | Optional |
| `EMAIL_RECEIVERS` | Receiver emails (comma-separated, leave empty to send to yourself) | Optional |
@@ -256,7 +256,7 @@ DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
Bot:
```bash
DISCORD_BOT_TOKEN=your_bot_token
DISCORD_CHANNEL_ID=your_channel_id
DISCORD_MAIN_CHANNEL_ID=your_channel_id
```
### 3. Email

View File

@@ -75,7 +75,7 @@ daily_stock_analysis/
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID (用于发送到子话题) | 可选 |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL[创建方法](https://support.discord.com/hc/en-us/articles/228383668) | 可选 |
| `DISCORD_BOT_TOKEN` | Discord Bot Token与 Webhook 二选一) | 可选 |
| `DISCORD_CHANNEL_ID` | Discord Channel ID使用 Bot 时需要) | 可选 |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID使用 Bot 时需要) | 可选 |
| `EMAIL_SENDER` | 发件人邮箱(如 `xxx@qq.com` | 可选 |
| `EMAIL_PASSWORD` | 邮箱授权码(非登录密码) | 可选 |
| `EMAIL_RECEIVERS` | 收件人邮箱(多个用逗号分隔,留空则发给自己) | 可选 |
@@ -189,7 +189,7 @@ daily_stock_analysis/
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID | 可选 |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | 可选 |
| `DISCORD_BOT_TOKEN` | Discord Bot Token与 Webhook 二选一) | 可选 |
| `DISCORD_CHANNEL_ID` | Discord Channel ID使用 Bot 时需要) | 可选 |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID使用 Bot 时需要) | 可选 |
| `DISCORD_MAX_WORDS` | Discord 最大字数限制(默认 免费服务器限制2000 | 可选 |
| `EMAIL_SENDER` | 发件人邮箱 | 可选 |
| `EMAIL_PASSWORD` | 邮箱授权码(非登录密码) | 可选 |
@@ -586,7 +586,7 @@ DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
```bash
DISCORD_BOT_TOKEN=your_bot_token
DISCORD_CHANNEL_ID=your_channel_id
DISCORD_MAIN_CHANNEL_ID=your_channel_id
```
### PushoveriOS/Android 推送)

View File

@@ -75,7 +75,7 @@ Go to your forked repo → `Settings` → `Secrets and variables` → `Actions`
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID (for sending to topics) | Optional |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL ([How to create](https://support.discord.com/hc/en-us/articles/228383668)) | Optional |
| `DISCORD_BOT_TOKEN` | Discord Bot Token (choose one with Webhook) | Optional |
| `DISCORD_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `EMAIL_SENDER` | Sender email (e.g., `xxx@qq.com`) | Optional |
| `EMAIL_PASSWORD` | Email authorization code (not login password) | Optional |
| `EMAIL_RECEIVERS` | Receiver emails (comma-separated, leave empty to send to self) | Optional |
@@ -175,7 +175,7 @@ Default schedule: Every weekday at **18:00 (Beijing Time)** automatic execution.
| `TELEGRAM_MESSAGE_THREAD_ID` | Telegram Topic ID | Optional |
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | Optional |
| `DISCORD_BOT_TOKEN` | Discord Bot Token (choose one with Webhook) | Optional |
| `DISCORD_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `DISCORD_MAIN_CHANNEL_ID` | Discord Channel ID (required when using Bot) | Optional |
| `DISCORD_MAX_WORDS` | Discord Word Limit (default 2000 for un-upgraded servers) | Optional |
| `EMAIL_SENDER` | Sender email | Optional |
| `EMAIL_PASSWORD` | Email authorization code (not login password) | Optional |
@@ -460,7 +460,7 @@ DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
```bash
DISCORD_BOT_TOKEN=your_bot_token
DISCORD_CHANNEL_ID=your_channel_id
DISCORD_MAIN_CHANNEL_ID=your_channel_id
```
### Pushover (iOS/Android Push)

View File

@@ -920,7 +920,10 @@ class Config:
custom_webhook_bearer_token=os.getenv('CUSTOM_WEBHOOK_BEARER_TOKEN'),
webhook_verify_ssl=os.getenv('WEBHOOK_VERIFY_SSL', 'true').lower() == 'true',
discord_bot_token=os.getenv('DISCORD_BOT_TOKEN'),
discord_main_channel_id=os.getenv('DISCORD_MAIN_CHANNEL_ID'),
discord_main_channel_id=(
os.getenv('DISCORD_MAIN_CHANNEL_ID')
or os.getenv('DISCORD_CHANNEL_ID')
),
discord_webhook_url=os.getenv('DISCORD_WEBHOOK_URL'),
astrbot_url=os.getenv('ASTRBOT_URL'),
astrbot_token=os.getenv('ASTRBOT_TOKEN'),

View File

@@ -360,6 +360,52 @@ class TestVisionKeyValidation:
assert not any(i.field == "VISION_MODEL" for i in issues)
# ---------------------------------------------------------------------------
# Env alias compatibility
# ---------------------------------------------------------------------------
class TestEnvAliasCompatibility:
@patch("src.config.setup_env")
@patch.object(Config, "_parse_litellm_yaml", return_value=[])
def test_discord_channel_id_legacy_alias_is_still_loaded(
self,
_mock_parse_yaml,
_mock_setup_env,
):
with patch.dict(
"os.environ",
{
"DISCORD_BOT_TOKEN": "token",
"DISCORD_CHANNEL_ID": "legacy-channel",
},
clear=True,
):
config = Config._load_from_env()
assert config.discord_bot_token == "token"
assert config.discord_main_channel_id == "legacy-channel"
@patch("src.config.setup_env")
@patch.object(Config, "_parse_litellm_yaml", return_value=[])
def test_discord_main_channel_id_takes_precedence_over_legacy_alias(
self,
_mock_parse_yaml,
_mock_setup_env,
):
with patch.dict(
"os.environ",
{
"DISCORD_BOT_TOKEN": "token",
"DISCORD_CHANNEL_ID": "legacy-channel",
"DISCORD_MAIN_CHANNEL_ID": "main-channel",
},
clear=True,
):
config = Config._load_from_env()
assert config.discord_main_channel_id == "main-channel"
# ---------------------------------------------------------------------------
# validate() backward compatibility
# ---------------------------------------------------------------------------