openfree commited on
Commit
08e7201
·
verified ·
1 Parent(s): 0c006f3

Update app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +192 -67
app-backup.py CHANGED
@@ -418,31 +418,61 @@ class ArenaDatabase:
418
  cursor.execute('UPDATE model_stats SET elo_rating = ? WHERE model_name = ?', (new_elo_b, model_b))
419
 
420
  def _sync_to_hf(self):
421
- """Sync local database to Hugging Face - battles와 stats를 분리하지 않고 battles만 저장"""
422
  if not self.use_hf:
 
423
  return
424
 
425
  try:
426
  conn = sqlite3.connect(self.db_path)
427
 
428
- # Export battles only - stats는 battles에서 재계산 가능
429
  battles_df = pd.read_sql_query("SELECT * FROM battles", conn)
 
430
  if len(battles_df) > 0:
 
 
 
431
  battles_dataset = Dataset.from_pandas(battles_df)
432
- battles_dataset.push_to_hub(
433
- self.hf_repo_id,
434
- split="train",
435
- token=self.hf_token,
436
- private=True
437
- )
438
- print(f"✅ Pushed {len(battles_df)} battles to HF")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
 
440
  conn.close()
441
 
442
  except Exception as e:
443
- print(f"⚠️ Warning: Could not sync to HF: {e}")
444
-
445
-
446
 
447
  def init_database(self):
448
  """Initialize SQLite database - ONLY called when no existing data"""
@@ -502,11 +532,21 @@ class ArenaDatabase:
502
  conn.close()
503
 
504
  def save_battle(self, battle: Battle):
505
- """Save battle result - 중복 방지 추가"""
506
  conn = sqlite3.connect(self.db_path)
507
  cursor = conn.cursor()
508
 
509
  try:
 
 
 
 
 
 
 
 
 
 
510
  cursor.execute('''
511
  INSERT OR REPLACE INTO battles VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
512
  ''', (
@@ -529,21 +569,23 @@ class ArenaDatabase:
529
  winner = battle.winner
530
  loser = battle.model_b if winner == battle.model_a else battle.model_a
531
 
532
- # 이전 투표가 있었는지 확인
533
- cursor.execute('SELECT winner FROM battles WHERE id = ?', (battle.id,))
534
- previous = cursor.fetchone()
535
-
536
- if not previous or previous[0] != battle.winner:
537
- # 새 투표이거나 변경된 경우만 업데이트
538
  cursor.execute('''
539
  UPDATE model_stats
540
- SET total_battles = total_battles + 1, wins = wins + 1
 
541
  WHERE model_name = ?
542
  ''', (winner,))
543
-
 
544
  cursor.execute('''
545
  UPDATE model_stats
546
- SET total_battles = total_battles + 1, losses = losses + 1
 
547
  WHERE model_name = ?
548
  ''', (loser,))
549
 
@@ -551,20 +593,22 @@ class ArenaDatabase:
551
  self._update_category_scores(cursor, winner, battle.category, True)
552
  self._update_category_scores(cursor, loser, battle.category, False)
553
 
554
- # Update ELO
555
  self._update_elo_ratings(cursor, winner, loser)
 
 
556
 
557
  conn.commit()
 
 
558
  except Exception as e:
559
- print(f"Error saving battle: {e}")
560
  conn.rollback()
561
  finally:
562
  conn.close()
563
 
564
  # Sync to Hugging Face after saving
565
  self._sync_to_hf()
566
-
567
-
568
 
569
  def _update_category_scores(self, cursor, model, category, is_winner):
570
  """Update category-specific scores"""
@@ -658,6 +702,41 @@ class ArenaDatabase:
658
 
659
  df.insert(0, 'rank', range(1, len(df) + 1))
660
  return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
661
 
662
  # ==================== Fixed LLM Interface with 4 Models ====================
663
  class LLMInterface:
@@ -851,7 +930,7 @@ class LLMInterface:
851
  top_k=40,
852
  )
853
 
854
- # 전체 응답을 수집
855
  full_response = ""
856
 
857
  for chunk in self.gemini_client.models.generate_content_stream(
@@ -874,8 +953,6 @@ class LLMInterface:
874
  fallback = self._generate_fallback("Gemini-2.5-Pro", prompt, "en")
875
  yield fallback
876
 
877
-
878
-
879
  def _stream_claude(self, prompt: str) -> Generator[str, None, None]:
880
  """Stream Claude Opus 4.1 response"""
881
  if not self.claude_client:
@@ -1283,15 +1360,28 @@ class CreativityArena:
1283
  }
1284
 
1285
  def vote(self, choice: str, voter_id: str = None):
1286
- """Process vote"""
1287
  if not self.current_battle:
 
1288
  return {"error": "No active battle"}
1289
 
 
 
 
 
 
 
1290
  self.current_battle.winner = self.current_battle.model_a if choice == "A" else self.current_battle.model_b
1291
- self.current_battle.voter_id = voter_id or "anonymous"
 
 
1292
 
 
1293
  self.db.save_battle(self.current_battle)
1294
 
 
 
 
1295
  return {
1296
  "model_a": self.current_battle.model_a,
1297
  "model_b": self.current_battle.model_b,
@@ -1302,7 +1392,17 @@ class CreativityArena:
1302
  """Get leaderboard from database"""
1303
  return self.db.get_leaderboard(category)
1304
 
1305
- # ==================== Gradio Interface ====================
 
 
 
 
 
 
 
 
 
 
1306
  # ==================== Gradio Interface ====================
1307
  def create_app():
1308
  arena = CreativityArena()
@@ -1679,16 +1779,29 @@ def create_app():
1679
 
1680
  def process_vote(choice, state, lang):
1681
  if not state or 'battle' not in state:
 
1682
  return (
1683
  gr.update(),
1684
  gr.update(),
1685
  "Error: No active battle"
1686
  )
1687
 
1688
- # Update the current battle from state
1689
- arena.current_battle = state['battle']
 
 
 
1690
 
 
1691
  result = arena.vote(choice)
 
 
 
 
 
 
 
 
1692
  ui = UI_TEXT[lang]
1693
 
1694
  winner_emoji = "🏆" if result['winner'] == result['model_a'] else "🥈"
@@ -1705,6 +1818,9 @@ def create_app():
1705
  {ui['elo_updated']}
1706
  """
1707
 
 
 
 
1708
  return (
1709
  gr.update(value=result['model_a'], visible=True),
1710
  gr.update(value=result['model_b'], visible=True),
@@ -1785,36 +1901,45 @@ def create_app():
1785
 
1786
  # ==================== Main ====================
1787
  if __name__ == "__main__":
1788
- print("="*50)
1789
- print("🚀 AI Models Creativity Battle Arena")
1790
- print("="*50)
1791
- print("\n📋 Environment Setup:")
1792
- print("1. Set OPENAI_API_KEY for GPT-5")
1793
- print("2. Set GEMINI_API_KEY for Gemini 2.5 Pro")
1794
- print("3. Set ANTHROPIC_API_KEY for Claude Opus 4.1")
1795
- print("4. jetXA will use 'aiqtech/tests' by default")
1796
- print("5. Set HF_TOKEN for persistent data storage (REQUIRED)")
1797
- print("6. Optional: Set HF_DATASET_NAME (default: ai_models_arena)")
1798
- print("\n⚠️ Without HF_TOKEN, data will be lost on server restart!")
1799
- print("\n" + "="*50 + "\n")
1800
-
1801
- # Check for required API keys
1802
- if not os.getenv("HF_TOKEN"):
1803
- print("⚠️ WARNING: HF_TOKEN not set - data will not persist!")
1804
- print("Set it with: export HF_TOKEN='your_token_here'")
1805
- print("")
1806
-
1807
- if not os.getenv("OPENAI_API_KEY"):
1808
- print("⚠️ GPT-5: No API key found - will use fallback responses")
1809
-
1810
- if not os.getenv("GEMINI_API_KEY"):
1811
- print("⚠️ Gemini: No API key found - will use fallback responses")
1812
-
1813
- if not os.getenv("ANTHROPIC_API_KEY"):
1814
- print("⚠️ Claude: No API key found - will use fallback responses")
1815
-
1816
- print("\n🎯 Starting arena with 4 models: GPT-5, jetXA, Gemini 2.5 Pro, Claude Opus 4.1")
1817
- print("="*50 + "\n")
1818
-
1819
- app = create_app()
1820
- app.launch()
 
 
 
 
 
 
 
 
 
 
418
  cursor.execute('UPDATE model_stats SET elo_rating = ? WHERE model_name = ?', (new_elo_b, model_b))
419
 
420
  def _sync_to_hf(self):
421
+ """Sync local database to Hugging Face with improved error handling"""
422
  if not self.use_hf:
423
+ print("HF sync disabled")
424
  return
425
 
426
  try:
427
  conn = sqlite3.connect(self.db_path)
428
 
429
+ # Export battles
430
  battles_df = pd.read_sql_query("SELECT * FROM battles", conn)
431
+
432
  if len(battles_df) > 0:
433
+ print(f"📤 Syncing {len(battles_df)} battles to HF...")
434
+
435
+ # Convert to Dataset
436
  battles_dataset = Dataset.from_pandas(battles_df)
437
+
438
+ # Push to hub with retry logic
439
+ max_retries = 3
440
+ for attempt in range(max_retries):
441
+ try:
442
+ battles_dataset.push_to_hub(
443
+ self.hf_repo_id,
444
+ split="train",
445
+ token=self.hf_token,
446
+ private=True
447
+ )
448
+ print(f"✅ Successfully pushed {len(battles_df)} battles to HF")
449
+ break
450
+ except Exception as push_error:
451
+ if attempt < max_retries - 1:
452
+ print(f"⚠️ Push attempt {attempt + 1} failed, retrying...")
453
+ time.sleep(2) # Wait before retry
454
+ else:
455
+ print(f"❌ Failed to push to HF after {max_retries} attempts: {push_error}")
456
+
457
+ # Also sync model stats for backup
458
+ stats_df = pd.read_sql_query("SELECT * FROM model_stats", conn)
459
+ if len(stats_df) > 0:
460
+ try:
461
+ stats_dataset = Dataset.from_pandas(stats_df)
462
+ stats_dataset.push_to_hub(
463
+ self.hf_repo_id,
464
+ split="stats",
465
+ token=self.hf_token,
466
+ private=True
467
+ )
468
+ print(f"✅ Model stats synced to HF")
469
+ except Exception as e:
470
+ print(f"⚠️ Could not sync stats: {e}")
471
 
472
  conn.close()
473
 
474
  except Exception as e:
475
+ print(f" Critical error in HF sync: {e}")
 
 
476
 
477
  def init_database(self):
478
  """Initialize SQLite database - ONLY called when no existing data"""
 
532
  conn.close()
533
 
534
  def save_battle(self, battle: Battle):
535
+ """Save battle result with proper duplicate prevention and sync"""
536
  conn = sqlite3.connect(self.db_path)
537
  cursor = conn.cursor()
538
 
539
  try:
540
+ # First check if this battle already exists
541
+ cursor.execute('SELECT id, winner FROM battles WHERE id = ?', (battle.id,))
542
+ existing = cursor.fetchone()
543
+
544
+ if existing and existing[1]:
545
+ print(f"⚠️ Battle {battle.id} already has a winner: {existing[1]}")
546
+ conn.close()
547
+ return # Don't update if already voted
548
+
549
+ # Insert or update the battle
550
  cursor.execute('''
551
  INSERT OR REPLACE INTO battles VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
552
  ''', (
 
569
  winner = battle.winner
570
  loser = battle.model_b if winner == battle.model_a else battle.model_a
571
 
572
+ # Only update stats if this is a new vote
573
+ if not existing or not existing[1]:
574
+ print(f"📊 Updating stats: {winner} wins, {loser} loses")
575
+
576
+ # Update winner stats
 
577
  cursor.execute('''
578
  UPDATE model_stats
579
+ SET total_battles = total_battles + 1,
580
+ wins = wins + 1
581
  WHERE model_name = ?
582
  ''', (winner,))
583
+
584
+ # Update loser stats
585
  cursor.execute('''
586
  UPDATE model_stats
587
+ SET total_battles = total_battles + 1,
588
+ losses = losses + 1
589
  WHERE model_name = ?
590
  ''', (loser,))
591
 
 
593
  self._update_category_scores(cursor, winner, battle.category, True)
594
  self._update_category_scores(cursor, loser, battle.category, False)
595
 
596
+ # Update ELO ratings
597
  self._update_elo_ratings(cursor, winner, loser)
598
+
599
+ print(f"✅ Stats updated for battle {battle.id}")
600
 
601
  conn.commit()
602
+ print(f"💾 Battle {battle.id} saved to local database")
603
+
604
  except Exception as e:
605
+ print(f"Error saving battle: {e}")
606
  conn.rollback()
607
  finally:
608
  conn.close()
609
 
610
  # Sync to Hugging Face after saving
611
  self._sync_to_hf()
 
 
612
 
613
  def _update_category_scores(self, cursor, model, category, is_winner):
614
  """Update category-specific scores"""
 
702
 
703
  df.insert(0, 'rank', range(1, len(df) + 1))
704
  return df
705
+
706
+ def debug_database_state(self):
707
+ """Debug method to check current database state"""
708
+ conn = sqlite3.connect(self.db_path)
709
+ cursor = conn.cursor()
710
+
711
+ # Check battles count
712
+ cursor.execute("SELECT COUNT(*) FROM battles")
713
+ total_battles = cursor.fetchone()[0]
714
+
715
+ cursor.execute("SELECT COUNT(*) FROM battles WHERE winner IS NOT NULL")
716
+ voted_battles = cursor.fetchone()[0]
717
+
718
+ # Check model stats
719
+ cursor.execute("SELECT * FROM model_stats ORDER BY elo_rating DESC")
720
+ stats = cursor.fetchall()
721
+
722
+ conn.close()
723
+
724
+ print("\n" + "="*50)
725
+ print("📊 DATABASE STATE DEBUG")
726
+ print("="*50)
727
+ print(f"Total battles: {total_battles}")
728
+ print(f"Voted battles: {voted_battles}")
729
+ print("\nModel Stats:")
730
+ print("-"*50)
731
+ for stat in stats:
732
+ print(f"{stat[0]:20} | Battles: {stat[5]:3} | Wins: {stat[6]:3} | ELO: {stat[8]:4}")
733
+ print("="*50 + "\n")
734
+
735
+ return {
736
+ "total_battles": total_battles,
737
+ "voted_battles": voted_battles,
738
+ "model_stats": stats
739
+ }
740
 
741
  # ==================== Fixed LLM Interface with 4 Models ====================
742
  class LLMInterface:
 
930
  top_k=40,
931
  )
932
 
933
+ # 전체 응답을 수집
934
  full_response = ""
935
 
936
  for chunk in self.gemini_client.models.generate_content_stream(
 
953
  fallback = self._generate_fallback("Gemini-2.5-Pro", prompt, "en")
954
  yield fallback
955
 
 
 
956
  def _stream_claude(self, prompt: str) -> Generator[str, None, None]:
957
  """Stream Claude Opus 4.1 response"""
958
  if not self.claude_client:
 
1360
  }
1361
 
1362
  def vote(self, choice: str, voter_id: str = None):
1363
+ """Process vote with better error handling"""
1364
  if not self.current_battle:
1365
+ print("❌ No active battle to vote on")
1366
  return {"error": "No active battle"}
1367
 
1368
+ # Ensure we have the complete battle data
1369
+ if not self.current_battle.response_a or not self.current_battle.response_b:
1370
+ print("⚠️ Battle responses not complete")
1371
+ return {"error": "Battle responses not complete"}
1372
+
1373
+ # Set the winner
1374
  self.current_battle.winner = self.current_battle.model_a if choice == "A" else self.current_battle.model_b
1375
+ self.current_battle.voter_id = voter_id or f"anonymous_{datetime.now().timestamp()}"
1376
+
1377
+ print(f"🗳️ Vote recorded: {choice} -> {self.current_battle.winner}")
1378
 
1379
+ # Save to database
1380
  self.db.save_battle(self.current_battle)
1381
 
1382
+ # Force immediate sync to HF
1383
+ self.db._sync_to_hf()
1384
+
1385
  return {
1386
  "model_a": self.current_battle.model_a,
1387
  "model_b": self.current_battle.model_b,
 
1392
  """Get leaderboard from database"""
1393
  return self.db.get_leaderboard(category)
1394
 
1395
+ # ==================== Periodic Sync Function ====================
1396
+ def periodic_sync(arena):
1397
+ """Periodically sync to HF every 30 seconds"""
1398
+ while True:
1399
+ time.sleep(30)
1400
+ try:
1401
+ arena.db._sync_to_hf()
1402
+ print(f"⏰ Periodic sync completed at {datetime.now()}")
1403
+ except Exception as e:
1404
+ print(f"⏰ Periodic sync failed: {e}")
1405
+
1406
  # ==================== Gradio Interface ====================
1407
  def create_app():
1408
  arena = CreativityArena()
 
1779
 
1780
  def process_vote(choice, state, lang):
1781
  if not state or 'battle' not in state:
1782
+ print("❌ No battle in state")
1783
  return (
1784
  gr.update(),
1785
  gr.update(),
1786
  "Error: No active battle"
1787
  )
1788
 
1789
+ # Ensure the battle object is properly set
1790
+ battle_obj = state['battle']
1791
+ arena.current_battle = battle_obj
1792
+
1793
+ print(f"🎯 Processing vote: Choice={choice}, Battle ID={battle_obj.id}")
1794
 
1795
+ # Process the vote
1796
  result = arena.vote(choice)
1797
+
1798
+ if "error" in result:
1799
+ return (
1800
+ gr.update(),
1801
+ gr.update(),
1802
+ f"Error: {result['error']}"
1803
+ )
1804
+
1805
  ui = UI_TEXT[lang]
1806
 
1807
  winner_emoji = "🏆" if result['winner'] == result['model_a'] else "🥈"
 
1818
  {ui['elo_updated']}
1819
  """
1820
 
1821
+ # Debug: Check database state after vote
1822
+ arena.db.debug_database_state()
1823
+
1824
  return (
1825
  gr.update(value=result['model_a'], visible=True),
1826
  gr.update(value=result['model_b'], visible=True),
 
1901
 
1902
  # ==================== Main ====================
1903
  if __name__ == "__main__":
1904
+ print("="*50)
1905
+ print("🚀 AI Models Creativity Battle Arena")
1906
+ print("="*50)
1907
+ print("\n📋 Environment Setup:")
1908
+ print("1. Set OPENAI_API_KEY for GPT-5")
1909
+ print("2. Set GEMINI_API_KEY for Gemini 2.5 Pro")
1910
+ print("3. Set ANTHROPIC_API_KEY for Claude Opus 4.1")
1911
+ print("4. jetXA will use 'aiqtech/tests' by default")
1912
+ print("5. Set HF_TOKEN for persistent data storage (REQUIRED)")
1913
+ print("6. Optional: Set HF_DATASET_NAME (default: ai_models_arena)")
1914
+ print("\n⚠️ Without HF_TOKEN, data will be lost on server restart!")
1915
+ print("\n" + "="*50 + "\n")
1916
+
1917
+ # Check for required API keys
1918
+ if not os.getenv("HF_TOKEN"):
1919
+ print("⚠️ WARNING: HF_TOKEN not set - data will not persist!")
1920
+ print("Set it with: export HF_TOKEN='your_token_here'")
1921
+ print("")
1922
+
1923
+ if not os.getenv("OPENAI_API_KEY"):
1924
+ print("⚠️ GPT-5: No API key found - will use fallback responses")
1925
+
1926
+ if not os.getenv("GEMINI_API_KEY"):
1927
+ print("⚠️ Gemini: No API key found - will use fallback responses")
1928
+
1929
+ if not os.getenv("ANTHROPIC_API_KEY"):
1930
+ print("⚠️ Claude: No API key found - will use fallback responses")
1931
+
1932
+ print("\n🎯 Starting arena with 4 models: GPT-5, jetXA, Gemini 2.5 Pro, Claude Opus 4.1")
1933
+ print("="*50 + "\n")
1934
+
1935
+ # Create app
1936
+ app = create_app()
1937
+
1938
+ # Start periodic sync in background (optional)
1939
+ arena = CreativityArena()
1940
+ sync_thread = threading.Thread(target=lambda: periodic_sync(arena), daemon=True)
1941
+ sync_thread.start()
1942
+ print("✅ Background sync thread started (every 30 seconds)")
1943
+
1944
+ # Launch app
1945
+ app.launch()