Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,7 @@ import io
|
|
| 17 |
import time
|
| 18 |
import threading
|
| 19 |
from PIL import Image, ImageDraw, ImageFont
|
| 20 |
-
import gradio as gr
|
| 21 |
|
| 22 |
# ==============================================================================
|
| 23 |
# 0. 机构级审计日志 (Institutional Logging)
|
|
@@ -35,7 +35,6 @@ logger = logging.getLogger("BK_GTA_ARCHITECT_GRADIO")
|
|
| 35 |
def get_status():
|
| 36 |
"""
|
| 37 |
提供给 UptimeRobot 的监控探针内容
|
| 38 |
-
Gradio 会自动将其渲染为一个 API 端点,确保 HF 容器不休眠
|
| 39 |
"""
|
| 40 |
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 41 |
latency = "N/A"
|
|
@@ -47,7 +46,7 @@ def get_status():
|
|
| 47 |
|
| 48 |
return {
|
| 49 |
"status": "BK-GTA-GRADIO-TITAN-ACTIVE",
|
| 50 |
-
"version": "V62.9-
|
| 51 |
"bot_latency": latency,
|
| 52 |
"server_time": now,
|
| 53 |
"keys_loaded": len(KEY_POOL),
|
|
@@ -87,16 +86,16 @@ intents.message_content = True
|
|
| 87 |
intents.members = True
|
| 88 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
| 89 |
|
| 90 |
-
# 并发审计锁
|
| 91 |
audit_lock = asyncio.Lock()
|
| 92 |
|
| 93 |
-
# 数据库路径适配
|
| 94 |
if os.path.exists('/data'):
|
| 95 |
DB_PATH_CONFIG = '/data/bk_gta_v62_unified.json'
|
| 96 |
logger.info(f"📂 [Storage] Using Persistent Storage: {DB_PATH_CONFIG}")
|
| 97 |
else:
|
| 98 |
DB_PATH_CONFIG = 'bk_gta_v62_unified.json'
|
| 99 |
-
logger.warning(f"⚠️ [Storage] Using Ephemeral Storage
|
| 100 |
|
| 101 |
# ==============================================================================
|
| 102 |
# 3. 状态引擎 (BKEngine Core)
|
|
@@ -136,7 +135,6 @@ class BKEngine:
|
|
| 136 |
|
| 137 |
def save_db(self):
|
| 138 |
try:
|
| 139 |
-
# 原子写入防止文件损坏
|
| 140 |
temp = self.db_file + '.tmp'
|
| 141 |
with open(temp, 'w', encoding='utf-8') as f:
|
| 142 |
json.dump(self.data, f, ensure_ascii=False, indent=4)
|
|
@@ -215,9 +213,6 @@ def safe_extract_text(text, key_start, key_end=None):
|
|
| 215 |
except: return "N/A"
|
| 216 |
|
| 217 |
async def call_gemini_multiplex(prompt, attachment=None):
|
| 218 |
-
"""
|
| 219 |
-
[Core Logic] 8 密钥自动轮询与故障转移
|
| 220 |
-
"""
|
| 221 |
if not KEY_POOL: return "ERROR: NO_KEYS_CONFIGURED"
|
| 222 |
|
| 223 |
image_data = None
|
|
@@ -254,7 +249,7 @@ async def call_gemini_multiplex(prompt, attachment=None):
|
|
| 254 |
return "ERROR: ALL_KEYS_EXHAUSTED"
|
| 255 |
|
| 256 |
# ==============================================================================
|
| 257 |
-
# 5. 模块一:全网天梯
|
| 258 |
# ==============================================================================
|
| 259 |
@bot.command()
|
| 260 |
async def profile(ctx, member: discord.Member = None):
|
|
@@ -262,7 +257,6 @@ async def profile(ctx, member: discord.Member = None):
|
|
| 262 |
u = bk_engine.get_user(target.id)
|
| 263 |
elo = u['elo']
|
| 264 |
|
| 265 |
-
# 完整段位逻辑
|
| 266 |
if elo < 1300: rank, color = "Iron (学徒) 🗑️", 0x717d7e
|
| 267 |
elif elo < 1500: rank, color = "Bronze (资深) 🥉", 0xcd7f32
|
| 268 |
elif elo < 1800: rank, color = "Silver (精英) 🥈", 0xbdc3c7
|
|
@@ -301,7 +295,6 @@ async def leaderboard(ctx):
|
|
| 301 |
|
| 302 |
emb = discord.Embed(title="🏆 Global Ranking (Institutional)", description=desc or "No data available.", color=0xf1c40f)
|
| 303 |
|
| 304 |
-
# 阵营战况
|
| 305 |
f_txt = ""
|
| 306 |
for k, v in bk_engine.data["factions"].items():
|
| 307 |
f_txt += f"{v['emoji']} {k}: {v['score']} pts | "
|
|
@@ -310,7 +303,7 @@ async def leaderboard(ctx):
|
|
| 310 |
await ctx.send(embed=emb)
|
| 311 |
|
| 312 |
# ==============================================================================
|
| 313 |
-
# 6. 模块二:宏观情报
|
| 314 |
# ==============================================================================
|
| 315 |
@bot.command()
|
| 316 |
async def news(ctx):
|
|
@@ -336,16 +329,11 @@ async def news(ctx):
|
|
| 336 |
await ctx.send(embed=emb)
|
| 337 |
|
| 338 |
# ==============================================================================
|
| 339 |
-
# 7. 模块三:量化审计
|
| 340 |
# ==============================================================================
|
| 341 |
@bot.command()
|
| 342 |
async def evaluate(ctx):
|
| 343 |
-
"""
|
| 344 |
-
带有并发锁的审计功能,防止 HF 容器 OOM
|
| 345 |
-
"""
|
| 346 |
if not ctx.message.attachments: return await ctx.send("❌ No image detected.")
|
| 347 |
-
|
| 348 |
-
# [Lock Check] 检查是否忙碌
|
| 349 |
if audit_lock.locked():
|
| 350 |
return await ctx.send("⚠️ **[System Busy]** Another audit is processing. Please wait 10s.")
|
| 351 |
|
|
@@ -376,7 +364,6 @@ async def evaluate(ctx):
|
|
| 376 |
status = "REJECTED (High Risk)"
|
| 377 |
color = 0xe74c3c
|
| 378 |
else:
|
| 379 |
-
# 完整评分公式
|
| 380 |
trades_adj = math.log10(max(trades, 1)) / 1.5
|
| 381 |
s_final = s_base * min(max(trades_adj, 0.5), 1.2) * (sharpe/2.0 if sharpe>0 else 0.5)
|
| 382 |
s_final = min(max(s_final, 0.0), 100.0)
|
|
@@ -395,7 +382,7 @@ async def evaluate(ctx):
|
|
| 395 |
await ctx.send(embed=emb)
|
| 396 |
|
| 397 |
# ==============================================================================
|
| 398 |
-
# 8. 模块四:博弈盘口
|
| 399 |
# ==============================================================================
|
| 400 |
@bot.command()
|
| 401 |
@commands.has_permissions(administrator=True)
|
|
@@ -446,7 +433,7 @@ async def settle_bet(ctx, bid: str, winner: str):
|
|
| 446 |
await ctx.send(f"🏁 Bet {bid} Settled. Winner: {winner}. Payouts Distributed.")
|
| 447 |
|
| 448 |
# ==============================================================================
|
| 449 |
-
# 9. 模块五:PVP 竞技场
|
| 450 |
# ==============================================================================
|
| 451 |
@bot.command()
|
| 452 |
async def challenge(ctx, member: discord.Member):
|
|
@@ -493,13 +480,12 @@ async def duel_submit(ctx, did: str):
|
|
| 493 |
await m.delete()
|
| 494 |
|
| 495 |
# ==============================================================================
|
| 496 |
-
# 10. 模块六:海报渲染
|
| 497 |
# ==============================================================================
|
| 498 |
@bot.command()
|
| 499 |
async def viral_audit(ctx):
|
| 500 |
"""
|
| 501 |
[完整版] 提取审计数据并渲染具备社交传播属性的海报图片
|
| 502 |
-
包含完整的 PIL 绘图逻辑,无省略。
|
| 503 |
"""
|
| 504 |
if not ctx.message.attachments:
|
| 505 |
return await ctx.send("❌ 请上传审计截图。")
|
|
@@ -512,29 +498,23 @@ async def viral_audit(ctx):
|
|
| 512 |
|
| 513 |
try:
|
| 514 |
W, H = 600, 800
|
| 515 |
-
# 创建暗黑科技风底色
|
| 516 |
base = Image.new('RGB', (W, H), color=(18, 20, 30))
|
| 517 |
draw = ImageDraw.Draw(base)
|
| 518 |
|
| 519 |
-
# 1. 绘制装饰性雷达背景
|
| 520 |
for i in range(0, W, 40): draw.line([(i, 0), (i, H)], fill=(30, 35, 45), width=1)
|
| 521 |
for j in range(0, H, 40): draw.line([(0, j), (W, j)], fill=(30, 35, 45), width=1)
|
| 522 |
|
| 523 |
-
# 2. 绘制外边框
|
| 524 |
draw.rectangle([10, 10, 590, 790], outline=(46, 204, 113), width=2)
|
| 525 |
draw.rectangle([20, 20, 580, 780], outline=(46, 204, 113), width=5)
|
| 526 |
|
| 527 |
-
# 3. 填充文字数据 (默认字体降级)
|
| 528 |
draw.text((40, 60), "BK-GTA QUANTITATIVE SYSTEM", fill=(255, 255, 255))
|
| 529 |
draw.text((40, 150), f"TRADER ID: {ctx.author.name.upper()}", fill=(46, 204, 113))
|
| 530 |
draw.text((40, 260), f"ALPHA RETURN: +{ret}%", fill=(255, 255, 255))
|
| 531 |
draw.text((40, 360), f"SHARPE RATIO: {sharpe}", fill=(255, 255, 255))
|
| 532 |
draw.text((40, 460), f"SESSION: {SESSION_ID}", fill=(120, 120, 130))
|
| 533 |
|
| 534 |
-
# 加入验证水印
|
| 535 |
draw.text((40, 720), "VERIFIED BY BK-GTA SENTINEL AI", fill=(46, 204, 113))
|
| 536 |
|
| 537 |
-
# 内存缓冲交付
|
| 538 |
fp = io.BytesIO()
|
| 539 |
base.save(fp, 'PNG')
|
| 540 |
fp.seek(0)
|
|
@@ -572,14 +552,13 @@ if __name__ == "__main__":
|
|
| 572 |
# 1. 在后台线程启动 Discord 机器人 (非阻塞)
|
| 573 |
threading.Thread(target=run_discord_bot).start()
|
| 574 |
|
| 575 |
-
# 2. 在主线程启动 Gradio UI
|
| 576 |
-
#
|
| 577 |
iface = gr.Interface(
|
| 578 |
fn=get_status,
|
| 579 |
inputs=None,
|
| 580 |
outputs="json",
|
| 581 |
title="BK-GTA Sentinel",
|
| 582 |
-
description="Core logic is running in background thread."
|
| 583 |
-
every=5 # 自动刷新
|
| 584 |
)
|
| 585 |
iface.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 17 |
import time
|
| 18 |
import threading
|
| 19 |
from PIL import Image, ImageDraw, ImageFont
|
| 20 |
+
import gradio as gr
|
| 21 |
|
| 22 |
# ==============================================================================
|
| 23 |
# 0. 机构级审计日志 (Institutional Logging)
|
|
|
|
| 35 |
def get_status():
|
| 36 |
"""
|
| 37 |
提供给 UptimeRobot 的监控探针内容
|
|
|
|
| 38 |
"""
|
| 39 |
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 40 |
latency = "N/A"
|
|
|
|
| 46 |
|
| 47 |
return {
|
| 48 |
"status": "BK-GTA-GRADIO-TITAN-ACTIVE",
|
| 49 |
+
"version": "V62.9-Stable",
|
| 50 |
"bot_latency": latency,
|
| 51 |
"server_time": now,
|
| 52 |
"keys_loaded": len(KEY_POOL),
|
|
|
|
| 86 |
intents.members = True
|
| 87 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
| 88 |
|
| 89 |
+
# 并发审计锁
|
| 90 |
audit_lock = asyncio.Lock()
|
| 91 |
|
| 92 |
+
# 数据库路径适配
|
| 93 |
if os.path.exists('/data'):
|
| 94 |
DB_PATH_CONFIG = '/data/bk_gta_v62_unified.json'
|
| 95 |
logger.info(f"📂 [Storage] Using Persistent Storage: {DB_PATH_CONFIG}")
|
| 96 |
else:
|
| 97 |
DB_PATH_CONFIG = 'bk_gta_v62_unified.json'
|
| 98 |
+
logger.warning(f"⚠️ [Storage] Using Ephemeral Storage.")
|
| 99 |
|
| 100 |
# ==============================================================================
|
| 101 |
# 3. 状态引擎 (BKEngine Core)
|
|
|
|
| 135 |
|
| 136 |
def save_db(self):
|
| 137 |
try:
|
|
|
|
| 138 |
temp = self.db_file + '.tmp'
|
| 139 |
with open(temp, 'w', encoding='utf-8') as f:
|
| 140 |
json.dump(self.data, f, ensure_ascii=False, indent=4)
|
|
|
|
| 213 |
except: return "N/A"
|
| 214 |
|
| 215 |
async def call_gemini_multiplex(prompt, attachment=None):
|
|
|
|
|
|
|
|
|
|
| 216 |
if not KEY_POOL: return "ERROR: NO_KEYS_CONFIGURED"
|
| 217 |
|
| 218 |
image_data = None
|
|
|
|
| 249 |
return "ERROR: ALL_KEYS_EXHAUSTED"
|
| 250 |
|
| 251 |
# ==============================================================================
|
| 252 |
+
# 5. 模块一:全网天梯
|
| 253 |
# ==============================================================================
|
| 254 |
@bot.command()
|
| 255 |
async def profile(ctx, member: discord.Member = None):
|
|
|
|
| 257 |
u = bk_engine.get_user(target.id)
|
| 258 |
elo = u['elo']
|
| 259 |
|
|
|
|
| 260 |
if elo < 1300: rank, color = "Iron (学徒) 🗑️", 0x717d7e
|
| 261 |
elif elo < 1500: rank, color = "Bronze (资深) 🥉", 0xcd7f32
|
| 262 |
elif elo < 1800: rank, color = "Silver (精英) 🥈", 0xbdc3c7
|
|
|
|
| 295 |
|
| 296 |
emb = discord.Embed(title="🏆 Global Ranking (Institutional)", description=desc or "No data available.", color=0xf1c40f)
|
| 297 |
|
|
|
|
| 298 |
f_txt = ""
|
| 299 |
for k, v in bk_engine.data["factions"].items():
|
| 300 |
f_txt += f"{v['emoji']} {k}: {v['score']} pts | "
|
|
|
|
| 303 |
await ctx.send(embed=emb)
|
| 304 |
|
| 305 |
# ==============================================================================
|
| 306 |
+
# 6. 模块二:宏观情报
|
| 307 |
# ==============================================================================
|
| 308 |
@bot.command()
|
| 309 |
async def news(ctx):
|
|
|
|
| 329 |
await ctx.send(embed=emb)
|
| 330 |
|
| 331 |
# ==============================================================================
|
| 332 |
+
# 7. 模块三:量化审计
|
| 333 |
# ==============================================================================
|
| 334 |
@bot.command()
|
| 335 |
async def evaluate(ctx):
|
|
|
|
|
|
|
|
|
|
| 336 |
if not ctx.message.attachments: return await ctx.send("❌ No image detected.")
|
|
|
|
|
|
|
| 337 |
if audit_lock.locked():
|
| 338 |
return await ctx.send("⚠️ **[System Busy]** Another audit is processing. Please wait 10s.")
|
| 339 |
|
|
|
|
| 364 |
status = "REJECTED (High Risk)"
|
| 365 |
color = 0xe74c3c
|
| 366 |
else:
|
|
|
|
| 367 |
trades_adj = math.log10(max(trades, 1)) / 1.5
|
| 368 |
s_final = s_base * min(max(trades_adj, 0.5), 1.2) * (sharpe/2.0 if sharpe>0 else 0.5)
|
| 369 |
s_final = min(max(s_final, 0.0), 100.0)
|
|
|
|
| 382 |
await ctx.send(embed=emb)
|
| 383 |
|
| 384 |
# ==============================================================================
|
| 385 |
+
# 8. 模块四:博弈盘口
|
| 386 |
# ==============================================================================
|
| 387 |
@bot.command()
|
| 388 |
@commands.has_permissions(administrator=True)
|
|
|
|
| 433 |
await ctx.send(f"🏁 Bet {bid} Settled. Winner: {winner}. Payouts Distributed.")
|
| 434 |
|
| 435 |
# ==============================================================================
|
| 436 |
+
# 9. 模块五:PVP 竞技场
|
| 437 |
# ==============================================================================
|
| 438 |
@bot.command()
|
| 439 |
async def challenge(ctx, member: discord.Member):
|
|
|
|
| 480 |
await m.delete()
|
| 481 |
|
| 482 |
# ==============================================================================
|
| 483 |
+
# 10. 模块六:海报渲染
|
| 484 |
# ==============================================================================
|
| 485 |
@bot.command()
|
| 486 |
async def viral_audit(ctx):
|
| 487 |
"""
|
| 488 |
[完整版] 提取审计数据并渲染具备社交传播属性的海报图片
|
|
|
|
| 489 |
"""
|
| 490 |
if not ctx.message.attachments:
|
| 491 |
return await ctx.send("❌ 请上传审计截图。")
|
|
|
|
| 498 |
|
| 499 |
try:
|
| 500 |
W, H = 600, 800
|
|
|
|
| 501 |
base = Image.new('RGB', (W, H), color=(18, 20, 30))
|
| 502 |
draw = ImageDraw.Draw(base)
|
| 503 |
|
|
|
|
| 504 |
for i in range(0, W, 40): draw.line([(i, 0), (i, H)], fill=(30, 35, 45), width=1)
|
| 505 |
for j in range(0, H, 40): draw.line([(0, j), (W, j)], fill=(30, 35, 45), width=1)
|
| 506 |
|
|
|
|
| 507 |
draw.rectangle([10, 10, 590, 790], outline=(46, 204, 113), width=2)
|
| 508 |
draw.rectangle([20, 20, 580, 780], outline=(46, 204, 113), width=5)
|
| 509 |
|
|
|
|
| 510 |
draw.text((40, 60), "BK-GTA QUANTITATIVE SYSTEM", fill=(255, 255, 255))
|
| 511 |
draw.text((40, 150), f"TRADER ID: {ctx.author.name.upper()}", fill=(46, 204, 113))
|
| 512 |
draw.text((40, 260), f"ALPHA RETURN: +{ret}%", fill=(255, 255, 255))
|
| 513 |
draw.text((40, 360), f"SHARPE RATIO: {sharpe}", fill=(255, 255, 255))
|
| 514 |
draw.text((40, 460), f"SESSION: {SESSION_ID}", fill=(120, 120, 130))
|
| 515 |
|
|
|
|
| 516 |
draw.text((40, 720), "VERIFIED BY BK-GTA SENTINEL AI", fill=(46, 204, 113))
|
| 517 |
|
|
|
|
| 518 |
fp = io.BytesIO()
|
| 519 |
base.save(fp, 'PNG')
|
| 520 |
fp.seek(0)
|
|
|
|
| 552 |
# 1. 在后台线程启动 Discord 机器人 (非阻塞)
|
| 553 |
threading.Thread(target=run_discord_bot).start()
|
| 554 |
|
| 555 |
+
# 2. 在主线程启动 Gradio UI
|
| 556 |
+
# [FIX] 移除了 every=5 参数以修复 TypeError
|
| 557 |
iface = gr.Interface(
|
| 558 |
fn=get_status,
|
| 559 |
inputs=None,
|
| 560 |
outputs="json",
|
| 561 |
title="BK-GTA Sentinel",
|
| 562 |
+
description="Core logic is running in background thread."
|
|
|
|
| 563 |
)
|
| 564 |
iface.launch(server_name="0.0.0.0", server_port=7860)
|