diff --git a/app.py b/app.py index bf2e1583..d547b5b9 100755 --- a/app.py +++ b/app.py @@ -11628,6 +11628,7 @@ def get_events_effectiveness_stats(): # 提取股票代码并获取前收盘价 all_base_codes = [row[0].split('.')[0] for row in market_data] all_prev_close = get_cached_prev_close(all_base_codes, prev_date_str) + print(f'[effectiveness-stats] 前收盘价获取: 请求 {len(all_base_codes)} 个, 返回 {len(all_prev_close)} 个') rising = 0 falling = 0 @@ -13863,6 +13864,47 @@ def broadcast_new_event(event): traceback.print_exc() +# ==================== 测试事件推送接口 ==================== +@app.route('/api/test/push-event', methods=['POST']) +def test_push_event(): + """测试事件推送(仅用于调试)""" + try: + data = request.get_json() or {} + test_event_data = { + 'id': data.get('id', 99999), + 'title': data.get('title', '测试事件标题 - 这是一个测试'), + 'description': data.get('description', '这是测试事件的详细描述内容,用于验证通知推送功能是否正常工作。'), + 'event_type': data.get('event_type', 'market'), + 'importance': data.get('importance', 'A'), + 'status': 'active', + 'created_at': datetime.now().isoformat(), + 'hot_score': 100, + 'view_count': 0, + 'related_avg_chg': 2.5, + 'related_max_chg': 5.0, + 'keywords': ['测试', '调试'], + } + + print(f'\n[测试推送] ========== 测试事件推送 ==========') + print(f'[测试推送] 事件数据: {test_event_data}') + + socketio.emit('new_event', test_event_data, room='events_all', namespace='/') + print(f'[测试推送] ✓ 已发送到 events_all') + + return jsonify({ + 'code': 200, + 'message': '测试事件已推送', + 'data': test_event_data + }) + except Exception as e: + import traceback + traceback.print_exc() + return jsonify({ + 'code': 500, + 'message': f'推送失败: {str(e)}' + }), 500 + + # ==================== WebSocket 轮询机制(检测新事件) ==================== # Redis Key 用于多 Worker 协调 diff --git a/mcp_database.py b/mcp_database.py index 0f467013..8ff2e726 100644 --- a/mcp_database.py +++ b/mcp_database.py @@ -9,16 +9,17 @@ from typing import Dict, List, Any, Optional from datetime import datetime, date from decimal import Decimal import json +import os logger = logging.getLogger(__name__) -# MySQL连接配置 +# MySQL连接配置(支持环境变量,便于多服务器部署) MYSQL_CONFIG = { - 'host': '127.0.0.1', - 'port': 3306, - 'user': 'root', - 'password': 'Zzl33818!', - 'db': 'stock', + 'host': os.environ.get('MYSQL_HOST', '127.0.0.1'), + 'port': int(os.environ.get('MYSQL_PORT', 3306)), + 'user': os.environ.get('MYSQL_USER', 'root'), + 'password': os.environ.get('MYSQL_PASSWORD', 'Zzl33818!'), + 'db': os.environ.get('MYSQL_DATABASE', 'stock'), 'charset': 'utf8mb4', 'autocommit': True } diff --git a/nginx-114.66.54.70.conf b/nginx-114.66.54.70.conf index 87b177d5..ba9ed9d5 100644 --- a/nginx-114.66.54.70.conf +++ b/nginx-114.66.54.70.conf @@ -142,10 +142,74 @@ server { proxy_buffering off; } + # ============================================ + # MCP 服务(本地) + # ============================================ + location /mcp/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization, X-Requested-With, Cookie' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + # 隐藏后端返回的 CORS 头(避免重复) + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + + proxy_pass http://127.0.0.1:8900/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ''; + + # 统一添加 CORS 头 + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + + # SSE 流式响应配置 + proxy_buffering off; + proxy_cache off; + chunked_transfer_encoding on; + gzip off; + add_header X-Accel-Buffering no; + + proxy_connect_timeout 75s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + # ============================================ # 数据服务 API 代理 (222.128.1.157) # ============================================ location /concept-api/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + # 隐藏后端返回的 CORS 头(避免重复) + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + proxy_pass http://222.128.1.157:16801/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -153,11 +217,33 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + # 统一添加 CORS 头 add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; } location /es-api/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS, HEAD' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + proxy_pass http://222.128.1.157:19200/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -167,9 +253,31 @@ server { add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + proxy_buffering off; } location /news-api/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + proxy_pass http://222.128.1.157:21891/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -179,9 +287,30 @@ server { add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; + + proxy_connect_timeout 90s; + proxy_send_timeout 90s; + proxy_read_timeout 90s; } location /report-api/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + proxy_pass http://222.128.1.157:8811/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -191,9 +320,30 @@ server { add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; } location /category-api/ { + # 处理 OPTIONS 预检请求 + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Max-Age' 86400; + add_header 'Content-Length' 0; + return 204; + } + + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header Access-Control-Expose-Headers; + proxy_pass http://222.128.1.157:18827/; proxy_http_version 1.1; proxy_set_header Host $host; @@ -203,6 +353,275 @@ server { add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + + proxy_buffering on; + proxy_buffer_size 128k; + proxy_buffers 8 256k; + proxy_busy_buffers_size 512k; + } + + # ============================================ + # Bytedesk 客服系统代理 (43.143.189.195) + # ============================================ + + location /bytedesk/ { + proxy_pass http://43.143.189.195/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + location /websocket { + proxy_pass http://43.143.189.195/websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_connect_timeout 86400s; + proxy_send_timeout 86400s; + proxy_read_timeout 86400s; + } + + location /chat/ { + proxy_pass http://43.143.189.195/chat/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 替换响应内容中的 IP 地址 + sub_filter 'http://43.143.189.195' 'https://www.valuefrontier.cn'; + sub_filter_once off; + sub_filter_types text/css text/javascript application/javascript application/json; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + location /config/ { + proxy_pass http://43.143.189.195/config/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + location ^~ /uploads/ { + proxy_pass http://43.143.189.195/uploads/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 隐藏后端返回的可能冲突的头 + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header X-Content-Type-Options; + proxy_hide_header Cross-Origin-Resource-Policy; + + # 解决 ORB 问题 + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept' always; + add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always; + + proxy_cache_valid 200 1d; + expires 1d; + add_header Cache-Control "public, max-age=86400"; + } + + location ^~ /file/ { + proxy_pass http://43.143.189.195/file/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 隐藏后端返回的可能冲突的头 + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header X-Content-Type-Options; + proxy_hide_header Cross-Origin-Resource-Policy; + + # 解决 ORB 问题 + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept' always; + add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always; + + proxy_cache_valid 200 1d; + expires 1d; + add_header Cache-Control "public, max-age=86400"; + } + + location /visitor/ { + proxy_pass http://43.143.189.195/visitor/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Accept-Encoding ""; + + # 替换 JSON 响应中的 IP 地址 + sub_filter 'http://43.143.189.195' 'https://www.valuefrontier.cn'; + sub_filter_once off; + sub_filter_types application/json; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + location = /stomp { + # 代理到 bytedesk 的 /websocket 端点 + proxy_pass http://43.143.189.195/websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + proxy_buffering off; + } + + location /stomp/ { + # 代理到 bytedesk 的 /websocket 端点 + proxy_pass http://43.143.189.195/websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + add_header 'Access-Control-Allow-Origin' $cors_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + + if ($request_method = 'OPTIONS') { + return 204; + } + + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + proxy_buffering off; + } + + location ^~ /avatars/ { + proxy_pass http://43.143.189.195/uploads/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 隐藏后端返回的可能冲突的头 + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Credentials; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + proxy_hide_header X-Content-Type-Options; + proxy_hide_header Cross-Origin-Resource-Policy; + + # 解决 ORB 问题 + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept' always; + add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always; + + proxy_cache_valid 200 1d; + proxy_cache_bypass $http_cache_control; + } + + location /assets/ { + proxy_pass http://43.143.189.195/assets/; + proxy_set_header Host $host; + + expires 1d; + add_header Cache-Control "public, immutable"; } # ============================================