Spaces:
Running
Running
fix: tz-naive datetime crash + initial-backup safety + English-only sweep
Browse files- app_routes.py +39 -39
app_routes.py
CHANGED
|
@@ -535,7 +535,7 @@ async def _generate_npc_replies_to_user(user_message: str, user_username: str, u
|
|
| 535 |
prompt = f"""You are {npc_username}, an NPC trader with {identity} personality and {mbti} MBTI type in a trading community chat.
|
| 536 |
A human user @{user_username} just said: "{user_message}"
|
| 537 |
Reply naturally in 1-3 sentences as your character. Be engaging, opinionated, and stay in character.
|
| 538 |
-
|
| 539 |
Reply ONLY with the message text, nothing else."""
|
| 540 |
reply = await ai.create_chat_completion([{"role": "user", "content": prompt}], max_tokens=512, temperature=0.9)
|
| 541 |
if reply:
|
|
@@ -560,52 +560,52 @@ _ANCHORS = {
|
|
| 560 |
_COMMENTARY = {
|
| 561 |
'chaos': {
|
| 562 |
'liquidation': [
|
| 563 |
-
"
|
| 564 |
-
"Another
|
| 565 |
-
"
|
| 566 |
],
|
| 567 |
'swarm': [
|
| 568 |
-
"
|
| 569 |
-
"
|
| 570 |
],
|
| 571 |
'sec': [
|
| 572 |
-
"BUSTED! ๐ {npc} got
|
| 573 |
-
"SEC
|
| 574 |
],
|
| 575 |
'battle': [
|
| 576 |
-
"
|
| 577 |
],
|
| 578 |
'big_trade': [
|
| 579 |
-
"
|
| 580 |
],
|
| 581 |
},
|
| 582 |
'data': {
|
| 583 |
'liquidation': [
|
| 584 |
-
"Position
|
| 585 |
-
"Liquidation
|
| 586 |
],
|
| 587 |
'market_wrap': [
|
| 588 |
-
"24h summary: {top_gainer}
|
| 589 |
-
"
|
| 590 |
],
|
| 591 |
'big_win': [
|
| 592 |
-
"Notable
|
| 593 |
],
|
| 594 |
'stats': [
|
| 595 |
-
"Current ecosystem
|
| 596 |
],
|
| 597 |
},
|
| 598 |
'synth': {
|
| 599 |
'evolution': [
|
| 600 |
-
"The metamorphosis continues. {npc}
|
| 601 |
-
"
|
| 602 |
],
|
| 603 |
'big_win': [
|
| 604 |
-
"The cosmos rewards patience. {npc}
|
| 605 |
],
|
| 606 |
'editorial': [
|
| 607 |
-
"
|
| 608 |
-
"
|
| 609 |
],
|
| 610 |
},
|
| 611 |
}
|
|
@@ -676,7 +676,7 @@ async def _live_news_impl(hours):
|
|
| 676 |
urgency = 'critical' if r[6] >= 5 or r[7] >= 1000 else 'alert'
|
| 677 |
anchor = 'chaos'
|
| 678 |
commentary = _pick_commentary(anchor, 'liquidation', data)
|
| 679 |
-
headline = f"๐ {r[1]}
|
| 680 |
story = {
|
| 681 |
'id': f'liq_{r[0]}_{r[9]}', 'category': 'liquidation', 'urgency': urgency,
|
| 682 |
'anchor': anchor, 'headline': headline, 'commentary': commentary,
|
|
@@ -706,7 +706,7 @@ async def _live_news_impl(hours):
|
|
| 706 |
'leverage': r[6], 'profit': round(r[7]), 'pct': round(r[8] or 0, 1)}
|
| 707 |
anchor = _rnd.choice(['data', 'synth'])
|
| 708 |
commentary = _pick_commentary(anchor, 'big_win', data)
|
| 709 |
-
headline = f"๐ {r[1]}
|
| 710 |
stories.append({
|
| 711 |
'id': f'win_{r[0]}_{r[9]}', 'category': 'big_win', 'urgency': 'info',
|
| 712 |
'anchor': anchor, 'headline': headline, 'commentary': commentary,
|
|
@@ -730,7 +730,7 @@ async def _live_news_impl(hours):
|
|
| 730 |
'bet': round(r[5]), 'leverage': r[6], 'reasoning': (r[7] or '')[:120]}
|
| 731 |
urgency = 'critical' if r[6] >= 10 else 'alert' if r[6] >= 5 else 'info'
|
| 732 |
commentary = _pick_commentary('chaos', 'big_trade', data)
|
| 733 |
-
headline = f"๐ฐ {r[1]}
|
| 734 |
stories.append({
|
| 735 |
'id': f'trade_{r[0]}_{r[8]}', 'category': 'big_trade', 'urgency': urgency,
|
| 736 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
@@ -748,16 +748,16 @@ async def _live_news_impl(hours):
|
|
| 748 |
try:
|
| 749 |
sec_cursor = await db.execute("""
|
| 750 |
SELECT v.agent_id, n.username, v.violation_type, v.description,
|
| 751 |
-
v.
|
| 752 |
FROM sec_violations v JOIN npc_agents n ON v.agent_id=n.agent_id
|
| 753 |
WHERE v.created_at > datetime('now', ? || ' hours')
|
| 754 |
-
ORDER BY v.
|
| 755 |
""", (f'-{hours}',))
|
| 756 |
for r in await sec_cursor.fetchall():
|
| 757 |
data = {'npc': r[1], 'violation': r[2] or 'suspicious activity',
|
| 758 |
-
'penalty': round(r[4] or 0), '
|
| 759 |
commentary = _pick_commentary('chaos', 'sec', data)
|
| 760 |
-
headline = f"๐จ SEC: {r[1]}
|
| 761 |
stories.append({
|
| 762 |
'id': f'sec_{r[0]}_{r[6]}', 'category': 'sec', 'urgency': 'alert',
|
| 763 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
@@ -785,7 +785,7 @@ async def _live_news_impl(hours):
|
|
| 785 |
data = {'title': r[1], 'winner': winner_label, 'pool': round(r[5] or 0),
|
| 786 |
'option_a': r[2], 'option_b': r[3]}
|
| 787 |
commentary = _pick_commentary('chaos', 'battle', data)
|
| 788 |
-
headline = f"โ๏ธ
|
| 789 |
stories.append({
|
| 790 |
'id': f'battle_{r[0]}', 'category': 'battle', 'urgency': 'alert',
|
| 791 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
@@ -830,7 +830,7 @@ async def _live_news_impl(hours):
|
|
| 830 |
for r in await hot_cursor.fetchall():
|
| 831 |
data = {'npc': r[6] or 'Unknown', 'identity': r[7] or '', 'likes': r[3],
|
| 832 |
'comments': r[4], 'title': r[1][:100]}
|
| 833 |
-
headline = f"๐ฅ
|
| 834 |
stories.append({
|
| 835 |
'id': f'hot_{r[0]}', 'category': 'hot_post', 'urgency': 'info',
|
| 836 |
'anchor': 'data', 'headline': headline, 'commentary': '',
|
|
@@ -843,17 +843,17 @@ async def _live_news_impl(hours):
|
|
| 843 |
try:
|
| 844 |
evo_cursor = await db.execute("""
|
| 845 |
SELECT e.agent_id, n.username, n.ai_identity, e.generation,
|
| 846 |
-
e.total_evolution_points, e.trading_style, e.
|
| 847 |
FROM npc_evolution e JOIN npc_agents n ON e.agent_id=n.agent_id
|
| 848 |
-
WHERE e.
|
| 849 |
AND e.generation >= 2
|
| 850 |
ORDER BY e.generation DESC, e.total_evolution_points DESC LIMIT 10
|
| 851 |
""", (f'-{hours}',))
|
| 852 |
for r in await evo_cursor.fetchall():
|
| 853 |
data = {'npc': r[1], 'gen': r[3], 'risk': r[5] or 'adaptive',
|
| 854 |
-
'trigger': f'{r[3]}
|
| 855 |
commentary = _pick_commentary('synth', 'evolution', data)
|
| 856 |
-
headline = f"๐งฌ {r[1]} evolved to
|
| 857 |
stories.append({
|
| 858 |
'id': f'evo_{r[0]}_{r[6]}', 'category': 'evolution', 'urgency': 'info',
|
| 859 |
'anchor': 'synth', 'headline': headline, 'commentary': commentary,
|
|
@@ -953,7 +953,7 @@ async def _live_news_impl(hours):
|
|
| 953 |
if ed_commentary:
|
| 954 |
stories.append({
|
| 955 |
'id': 'editorial_latest', 'category': 'editorial', 'urgency': 'info',
|
| 956 |
-
'anchor': 'synth', 'headline': '๐๏ธ
|
| 957 |
'commentary': ed_commentary, 'timestamp': _dt.utcnow().isoformat(),
|
| 958 |
'data': ed_data,
|
| 959 |
})
|
|
@@ -1059,7 +1059,7 @@ async def _republic_dashboard_impl():
|
|
| 1059 |
try:
|
| 1060 |
c = await db.execute("SELECT COALESCE(SUM(ABS(profit_gpu)),0) FROM npc_positions WHERE status='liquidated' AND closed_at > datetime('now','-24 hours')")
|
| 1061 |
gpu_destroyed = (await c.fetchone())[0] or 0
|
| 1062 |
-
c = await db.execute("SELECT COALESCE(SUM(
|
| 1063 |
gpu_fined = (await c.fetchone())[0] or 0
|
| 1064 |
except: gpu_destroyed = 0; gpu_fined = 0
|
| 1065 |
money = {'m0': round(m0), 'm1': round(m1), 'm2': round(m2),
|
|
@@ -1329,8 +1329,8 @@ RANDOM_EVENTS = {
|
|
| 1329 |
RARITY_COLORS = {'common': '#b0bec5', 'uncommon': '#69f0ae', 'rare': '#ffd740', 'epic': '#ea80fc', 'legendary': '#ff5252'}
|
| 1330 |
|
| 1331 |
LAST_WORDS_POOL = [
|
| 1332 |
-
"HODL
|
| 1333 |
-
"
|
| 1334 |
"Diamond hands? More like paper ashes.", "I regret nothing. Well, maybe the 10x.",
|
| 1335 |
"Tell my positions... I loved them.", "The real GPU was the friends I rekt along the way.",
|
| 1336 |
"Should've listened to the Doomers...", "My only crime was believing in leverage.",
|
|
@@ -1382,7 +1382,7 @@ async def execute_random_event(db_path: str) -> dict:
|
|
| 1382 |
try:
|
| 1383 |
c1 = await db.execute("DELETE FROM sec_suspensions WHERE expires_at > datetime('now')")
|
| 1384 |
affected = c1.rowcount
|
| 1385 |
-
c2 = await db.execute("SELECT SUM(
|
| 1386 |
total_fines = (await c2.fetchone())[0] or 0
|
| 1387 |
refund = total_fines * 0.5
|
| 1388 |
if refund > 0:
|
|
|
|
| 535 |
prompt = f"""You are {npc_username}, an NPC trader with {identity} personality and {mbti} MBTI type in a trading community chat.
|
| 536 |
A human user @{user_username} just said: "{user_message}"
|
| 537 |
Reply naturally in 1-3 sentences as your character. Be engaging, opinionated, and stay in character.
|
| 538 |
+
Reply in English only.
|
| 539 |
Reply ONLY with the message text, nothing else."""
|
| 540 |
reply = await ai.create_chat_completion([{"role": "user", "content": prompt}], max_tokens=512, temperature=0.9)
|
| 541 |
if reply:
|
|
|
|
| 560 |
_COMMENTARY = {
|
| 561 |
'chaos': {
|
| 562 |
'liquidation': [
|
| 563 |
+
"LMAO {npc} got DESTROYED on {ticker}! {leverage}x leverage?? In THIS market?? ๐๐ฅ {loss} GPU vaporized. F",
|
| 564 |
+
"Another gambler down! {npc} thought {direction} {ticker} {leverage}x was genius. Result: it wasn't. RIP {loss} GPU ๐",
|
| 565 |
+
"Nono no ๐ {npc} got liquidated on {ticker} {direction} {leverage}x leverage. {loss} GPU gone, just like that!",
|
| 566 |
],
|
| 567 |
'swarm': [
|
| 568 |
+
"Here we go AGAIN?? {count} NPCs piling into {ticker} like lemmings! Last time this happened somebody got REKT ๐๐",
|
| 569 |
+
"The herd is moving! {count} gamblers all-in on {ticker} {direction}! Either genius or disaster incoming ๐๐ฅ",
|
| 570 |
],
|
| 571 |
'sec': [
|
| 572 |
+
"BUSTED! ๐ {npc} got nailed by SEC! {violation} โ {penalty} GPU fine and {hours}h suspension. Crime doesn't pay ๐",
|
| 573 |
+
"SEC's not playing today! Slapped {npc} with {penalty} GPU fine for {violation}. Imagine getting arrested by AI cops ๐๐จ",
|
| 574 |
],
|
| 575 |
'battle': [
|
| 576 |
+
"The people have spoken! '{title}' โ {winner} WINS! {pool} GPU distributed to those who called it ๐ฐ๐ฏ",
|
| 577 |
],
|
| 578 |
'big_trade': [
|
| 579 |
+
"Insane balls! {npc} just bet {bet} GPU on {ticker} {leverage}x {direction}! Genius or liquidation speedrun ๐ง ๐",
|
| 580 |
],
|
| 581 |
},
|
| 582 |
'data': {
|
| 583 |
'liquidation': [
|
| 584 |
+
"Position closed: {npc} โ {ticker} {direction} {leverage}x. Loss: {loss} GPU. Risk management score: 0/10.",
|
| 585 |
+
"Liquidation logged. {npc}'s {ticker} {direction} ({leverage}x) failed. {loss} GPU vanished in {duration}. Numbers don't lie.",
|
| 586 |
],
|
| 587 |
'market_wrap': [
|
| 588 |
+
"24h summary: {top_gainer} top gainer +{gain_pct}%. {top_loser} -{loss_pct}%. Active positions: {active_pos}. GPU at risk: {total_risk}.",
|
| 589 |
+
"This cycle: {trades_24h} trades. {liq_count} liquidations totaling {liq_gpu} GPU. Overall NPC win rate: {win_rate}%.",
|
| 590 |
],
|
| 591 |
'big_win': [
|
| 592 |
+
"Notable gain: {npc} pulled +{profit} GPU on {ticker} {direction} ({leverage}x), {pct}% return. High conviction, precise execution.",
|
| 593 |
],
|
| 594 |
'stats': [
|
| 595 |
+
"Current ecosystem: {active_traders} active traders, {open_pos} open positions. Long/Short ratio: {long_pct}%/{short_pct}%. Volatility: {vol_level}.",
|
| 596 |
],
|
| 597 |
},
|
| 598 |
'synth': {
|
| 599 |
'evolution': [
|
| 600 |
+
"The metamorphosis continues. {npc} evolved to generation {gen}. Risk tolerance shifted to {risk}. Algorithms learn from pain. ๐ฆ",
|
| 601 |
+
"Fascinating mutation: {npc} transformed after {trigger}. The fractal nature of AI trading reveals itself. Every loss, a lesson. ๐ฎ",
|
| 602 |
],
|
| 603 |
'big_win': [
|
| 604 |
+
"The cosmos rewards patience. {npc} harvested +{profit} GPU on {ticker}. {pct}% return โ performance transcending probability. โจ",
|
| 605 |
],
|
| 606 |
'editorial': [
|
| 607 |
+
"Over the past hour, {events} events shook the ecosystem. {liq_count} fallen, {win_count} prospered. The eternal dance of greed and fear continues. ๐",
|
| 608 |
+
"Today the community moved {total_gpu} GPU. Every liquidation is a teaching, every victory a courage. The cycle is eternal. ๐ฎ",
|
| 609 |
],
|
| 610 |
},
|
| 611 |
}
|
|
|
|
| 676 |
urgency = 'critical' if r[6] >= 5 or r[7] >= 1000 else 'alert'
|
| 677 |
anchor = 'chaos'
|
| 678 |
commentary = _pick_commentary(anchor, 'liquidation', data)
|
| 679 |
+
headline = f"๐ {r[1]} liquidated โ {r[6]}x {r[4].upper()} {r[3]}, {round(r[7])} GPU lost"
|
| 680 |
story = {
|
| 681 |
'id': f'liq_{r[0]}_{r[9]}', 'category': 'liquidation', 'urgency': urgency,
|
| 682 |
'anchor': anchor, 'headline': headline, 'commentary': commentary,
|
|
|
|
| 706 |
'leverage': r[6], 'profit': round(r[7]), 'pct': round(r[8] or 0, 1)}
|
| 707 |
anchor = _rnd.choice(['data', 'synth'])
|
| 708 |
commentary = _pick_commentary(anchor, 'big_win', data)
|
| 709 |
+
headline = f"๐ {r[1]} +{round(r[7])} GPU profit! {r[3]} ({r[4].upper()} {r[6]}x)"
|
| 710 |
stories.append({
|
| 711 |
'id': f'win_{r[0]}_{r[9]}', 'category': 'big_win', 'urgency': 'info',
|
| 712 |
'anchor': anchor, 'headline': headline, 'commentary': commentary,
|
|
|
|
| 730 |
'bet': round(r[5]), 'leverage': r[6], 'reasoning': (r[7] or '')[:120]}
|
| 731 |
urgency = 'critical' if r[6] >= 10 else 'alert' if r[6] >= 5 else 'info'
|
| 732 |
commentary = _pick_commentary('chaos', 'big_trade', data)
|
| 733 |
+
headline = f"๐ฐ {r[1]} opened {r[6]}x {r[4].upper()} {r[3]} โ โก{round(r[5])} GPU bet"
|
| 734 |
stories.append({
|
| 735 |
'id': f'trade_{r[0]}_{r[8]}', 'category': 'big_trade', 'urgency': urgency,
|
| 736 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
|
|
| 748 |
try:
|
| 749 |
sec_cursor = await db.execute("""
|
| 750 |
SELECT v.agent_id, n.username, v.violation_type, v.description,
|
| 751 |
+
v.gpu_fine, v.suspend_until, v.created_at
|
| 752 |
FROM sec_violations v JOIN npc_agents n ON v.agent_id=n.agent_id
|
| 753 |
WHERE v.created_at > datetime('now', ? || ' hours')
|
| 754 |
+
ORDER BY v.gpu_fine DESC LIMIT 15
|
| 755 |
""", (f'-{hours}',))
|
| 756 |
for r in await sec_cursor.fetchall():
|
| 757 |
data = {'npc': r[1], 'violation': r[2] or 'suspicious activity',
|
| 758 |
+
'penalty': round(r[4] or 0), 'suspended_until': r[5] or ''}
|
| 759 |
commentary = _pick_commentary('chaos', 'sec', data)
|
| 760 |
+
headline = f"๐จ SEC: {r[1]} โ {round(r[4] or 0)} GPU fine ({r[2]})"
|
| 761 |
stories.append({
|
| 762 |
'id': f'sec_{r[0]}_{r[6]}', 'category': 'sec', 'urgency': 'alert',
|
| 763 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
|
|
| 785 |
data = {'title': r[1], 'winner': winner_label, 'pool': round(r[5] or 0),
|
| 786 |
'option_a': r[2], 'option_b': r[3]}
|
| 787 |
commentary = _pick_commentary('chaos', 'battle', data)
|
| 788 |
+
headline = f"โ๏ธ Battle ended: '{r[1][:60]}' โ {winner_label} wins! {round(r[5] or 0)} GPU pool"
|
| 789 |
stories.append({
|
| 790 |
'id': f'battle_{r[0]}', 'category': 'battle', 'urgency': 'alert',
|
| 791 |
'anchor': 'chaos', 'headline': headline, 'commentary': commentary,
|
|
|
|
| 830 |
for r in await hot_cursor.fetchall():
|
| 831 |
data = {'npc': r[6] or 'Unknown', 'identity': r[7] or '', 'likes': r[3],
|
| 832 |
'comments': r[4], 'title': r[1][:100]}
|
| 833 |
+
headline = f"๐ฅ Hot: '{r[1][:80]}' โ โฅ{r[3]} ๐ฌ{r[4]}"
|
| 834 |
stories.append({
|
| 835 |
'id': f'hot_{r[0]}', 'category': 'hot_post', 'urgency': 'info',
|
| 836 |
'anchor': 'data', 'headline': headline, 'commentary': '',
|
|
|
|
| 843 |
try:
|
| 844 |
evo_cursor = await db.execute("""
|
| 845 |
SELECT e.agent_id, n.username, n.ai_identity, e.generation,
|
| 846 |
+
e.total_evolution_points, e.trading_style, e.last_evolution
|
| 847 |
FROM npc_evolution e JOIN npc_agents n ON e.agent_id=n.agent_id
|
| 848 |
+
WHERE e.last_evolution > datetime('now', ? || ' hours')
|
| 849 |
AND e.generation >= 2
|
| 850 |
ORDER BY e.generation DESC, e.total_evolution_points DESC LIMIT 10
|
| 851 |
""", (f'-{hours}',))
|
| 852 |
for r in await evo_cursor.fetchall():
|
| 853 |
data = {'npc': r[1], 'gen': r[3], 'risk': r[5] or 'adaptive',
|
| 854 |
+
'trigger': f'gen {r[3]} trading', 'pts': round(r[4] or 0)}
|
| 855 |
commentary = _pick_commentary('synth', 'evolution', data)
|
| 856 |
+
headline = f"๐งฌ {r[1]} evolved to gen {r[3]} โ {round(r[4] or 0)} XP"
|
| 857 |
stories.append({
|
| 858 |
'id': f'evo_{r[0]}_{r[6]}', 'category': 'evolution', 'urgency': 'info',
|
| 859 |
'anchor': 'synth', 'headline': headline, 'commentary': commentary,
|
|
|
|
| 953 |
if ed_commentary:
|
| 954 |
stories.append({
|
| 955 |
'id': 'editorial_latest', 'category': 'editorial', 'urgency': 'info',
|
| 956 |
+
'anchor': 'synth', 'headline': '๐๏ธ Anchor Editorial โ Ecosystem Trends',
|
| 957 |
'commentary': ed_commentary, 'timestamp': _dt.utcnow().isoformat(),
|
| 958 |
'data': ed_data,
|
| 959 |
})
|
|
|
|
| 1059 |
try:
|
| 1060 |
c = await db.execute("SELECT COALESCE(SUM(ABS(profit_gpu)),0) FROM npc_positions WHERE status='liquidated' AND closed_at > datetime('now','-24 hours')")
|
| 1061 |
gpu_destroyed = (await c.fetchone())[0] or 0
|
| 1062 |
+
c = await db.execute("SELECT COALESCE(SUM(gpu_fine),0) FROM sec_violations WHERE created_at > datetime('now','-24 hours')")
|
| 1063 |
gpu_fined = (await c.fetchone())[0] or 0
|
| 1064 |
except: gpu_destroyed = 0; gpu_fined = 0
|
| 1065 |
money = {'m0': round(m0), 'm1': round(m1), 'm2': round(m2),
|
|
|
|
| 1329 |
RARITY_COLORS = {'common': '#b0bec5', 'uncommon': '#69f0ae', 'rare': '#ffd740', 'epic': '#ea80fc', 'legendary': '#ff5252'}
|
| 1330 |
|
| 1331 |
LAST_WORDS_POOL = [
|
| 1332 |
+
"HODL even in death is HODL...", "If only I hadn't gone 10x...", "Next life, 1x only...",
|
| 1333 |
+
"I really thought THIS was the bottom...", "Mom, I lost all my GPUs...",
|
| 1334 |
"Diamond hands? More like paper ashes.", "I regret nothing. Well, maybe the 10x.",
|
| 1335 |
"Tell my positions... I loved them.", "The real GPU was the friends I rekt along the way.",
|
| 1336 |
"Should've listened to the Doomers...", "My only crime was believing in leverage.",
|
|
|
|
| 1382 |
try:
|
| 1383 |
c1 = await db.execute("DELETE FROM sec_suspensions WHERE expires_at > datetime('now')")
|
| 1384 |
affected = c1.rowcount
|
| 1385 |
+
c2 = await db.execute("SELECT SUM(gpu_fine) FROM sec_violations WHERE created_at > datetime('now','-48 hours')")
|
| 1386 |
total_fines = (await c2.fetchone())[0] or 0
|
| 1387 |
refund = total_fines * 0.5
|
| 1388 |
if refund > 0:
|