fix api web
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
"""Card-related API routes"""
|
||||
from typing import List
|
||||
from typing import List, Dict
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.card import Card, CardDraw, CardDrawResult
|
||||
from app.services.gacha import GachaService
|
||||
from app.services.card_master import card_master_service
|
||||
from app.repositories.user import UserRepository
|
||||
from app.repositories.card import CardRepository, UniqueCardRepository
|
||||
from app.db.base import get_session
|
||||
@ -157,4 +158,16 @@ async def get_gacha_stats(db: AsyncSession = Depends(get_session)):
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Statistics error: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Statistics error: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/master", response_model=List[Dict])
|
||||
async def get_card_master_data():
|
||||
"""
|
||||
全カードマスターデータを取得(ai.jsonから)
|
||||
"""
|
||||
try:
|
||||
cards = card_master_service.get_all_cards()
|
||||
return cards
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get card master data: {str(e)}")
|
142
api/app/services/card_master.py
Normal file
142
api/app/services/card_master.py
Normal file
@ -0,0 +1,142 @@
|
||||
"""
|
||||
Card master data fetcher from external ai.json
|
||||
"""
|
||||
import httpx
|
||||
import json
|
||||
from typing import Dict, List, Optional
|
||||
from functools import lru_cache
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CARD_MASTER_URL = "https://git.syui.ai/ai/ai/raw/branch/main/ai.json"
|
||||
|
||||
# Default CP ranges for cards (matching existing gacha.py values)
|
||||
DEFAULT_CP_RANGES = {
|
||||
0: (10, 100),
|
||||
1: (20, 120),
|
||||
2: (30, 130),
|
||||
3: (40, 140),
|
||||
4: (50, 150),
|
||||
5: (25, 125),
|
||||
6: (15, 115),
|
||||
7: (60, 160),
|
||||
8: (80, 180),
|
||||
9: (70, 170),
|
||||
10: (90, 190),
|
||||
11: (35, 135),
|
||||
12: (65, 165),
|
||||
13: (75, 175),
|
||||
14: (100, 200),
|
||||
15: (85, 185),
|
||||
135: (95, 195), # world card
|
||||
}
|
||||
|
||||
|
||||
class CardMasterService:
|
||||
def __init__(self):
|
||||
self._cache = None
|
||||
self._cache_time = 0
|
||||
self._cache_duration = 3600 # 1 hour cache
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def fetch_card_master_data(self) -> Optional[Dict]:
|
||||
"""Fetch card master data from external source"""
|
||||
try:
|
||||
response = httpx.get(CARD_MASTER_URL, timeout=10.0)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch card master data: {e}")
|
||||
return None
|
||||
|
||||
def get_card_info(self) -> Dict[int, Dict]:
|
||||
"""Get card information in the format expected by gacha service"""
|
||||
master_data = self.fetch_card_master_data()
|
||||
|
||||
if not master_data:
|
||||
# Fallback to hardcoded data
|
||||
return self._get_fallback_card_info()
|
||||
|
||||
try:
|
||||
cards = master_data.get("ai", {}).get("card", {}).get("cards", [])
|
||||
card_info = {}
|
||||
|
||||
for card in cards:
|
||||
card_id = card.get("id")
|
||||
if card_id is not None:
|
||||
# Use name from JSON, fallback to English name
|
||||
name = card.get("name", f"card_{card_id}")
|
||||
|
||||
# Get CP range from defaults
|
||||
cp_range = DEFAULT_CP_RANGES.get(card_id, (50, 150))
|
||||
|
||||
card_info[card_id] = {
|
||||
"name": name,
|
||||
"base_cp_range": cp_range,
|
||||
"ja_name": card.get("lang", {}).get("ja", {}).get("name", name),
|
||||
"description": card.get("lang", {}).get("ja", {}).get("text", "")
|
||||
}
|
||||
|
||||
return card_info
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to parse card master data: {e}")
|
||||
return self._get_fallback_card_info()
|
||||
|
||||
def _get_fallback_card_info(self) -> Dict[int, Dict]:
|
||||
"""Fallback card info if external source fails"""
|
||||
return {
|
||||
0: {"name": "ai", "base_cp_range": (10, 100)},
|
||||
1: {"name": "dream", "base_cp_range": (20, 120)},
|
||||
2: {"name": "radiance", "base_cp_range": (30, 130)},
|
||||
3: {"name": "neutron", "base_cp_range": (40, 140)},
|
||||
4: {"name": "sun", "base_cp_range": (50, 150)},
|
||||
5: {"name": "night", "base_cp_range": (25, 125)},
|
||||
6: {"name": "snow", "base_cp_range": (15, 115)},
|
||||
7: {"name": "thunder", "base_cp_range": (60, 160)},
|
||||
8: {"name": "ultimate", "base_cp_range": (80, 180)},
|
||||
9: {"name": "sword", "base_cp_range": (70, 170)},
|
||||
10: {"name": "destruction", "base_cp_range": (90, 190)},
|
||||
11: {"name": "earth", "base_cp_range": (35, 135)},
|
||||
12: {"name": "galaxy", "base_cp_range": (65, 165)},
|
||||
13: {"name": "create", "base_cp_range": (75, 175)},
|
||||
14: {"name": "supernova", "base_cp_range": (100, 200)},
|
||||
15: {"name": "world", "base_cp_range": (85, 185)},
|
||||
}
|
||||
|
||||
def get_all_cards(self) -> List[Dict]:
|
||||
"""Get all cards with full information"""
|
||||
master_data = self.fetch_card_master_data()
|
||||
|
||||
if not master_data:
|
||||
return []
|
||||
|
||||
try:
|
||||
cards = master_data.get("ai", {}).get("card", {}).get("cards", [])
|
||||
result = []
|
||||
|
||||
for card in cards:
|
||||
card_id = card.get("id")
|
||||
if card_id is not None:
|
||||
cp_range = DEFAULT_CP_RANGES.get(card_id, (50, 150))
|
||||
|
||||
result.append({
|
||||
"id": card_id,
|
||||
"name": card.get("name", f"card_{card_id}"),
|
||||
"ja_name": card.get("lang", {}).get("ja", {}).get("name", ""),
|
||||
"description": card.get("lang", {}).get("ja", {}).get("text", ""),
|
||||
"base_cp_min": cp_range[0],
|
||||
"base_cp_max": cp_range[1]
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get all cards: {e}")
|
||||
return []
|
||||
|
||||
|
||||
# Singleton instance
|
||||
card_master_service = CardMasterService()
|
@ -10,36 +10,19 @@ from app.models.card import Card, CardRarity
|
||||
from app.repositories.user import UserRepository
|
||||
from app.repositories.card import CardRepository, UniqueCardRepository
|
||||
from app.db.models import DrawHistory
|
||||
from app.services.card_master import card_master_service
|
||||
|
||||
|
||||
class GachaService:
|
||||
"""ガチャシステムのサービスクラス"""
|
||||
|
||||
# カード基本情報(ai.jsonから)
|
||||
CARD_INFO = {
|
||||
0: {"name": "ai", "base_cp_range": (10, 100)},
|
||||
1: {"name": "dream", "base_cp_range": (20, 120)},
|
||||
2: {"name": "radiance", "base_cp_range": (30, 130)},
|
||||
3: {"name": "neutron", "base_cp_range": (40, 140)},
|
||||
4: {"name": "sun", "base_cp_range": (50, 150)},
|
||||
5: {"name": "night", "base_cp_range": (25, 125)},
|
||||
6: {"name": "snow", "base_cp_range": (15, 115)},
|
||||
7: {"name": "thunder", "base_cp_range": (60, 160)},
|
||||
8: {"name": "ultimate", "base_cp_range": (80, 180)},
|
||||
9: {"name": "sword", "base_cp_range": (70, 170)},
|
||||
10: {"name": "destruction", "base_cp_range": (90, 190)},
|
||||
11: {"name": "earth", "base_cp_range": (35, 135)},
|
||||
12: {"name": "galaxy", "base_cp_range": (65, 165)},
|
||||
13: {"name": "create", "base_cp_range": (75, 175)},
|
||||
14: {"name": "supernova", "base_cp_range": (100, 200)},
|
||||
15: {"name": "world", "base_cp_range": (85, 185)},
|
||||
}
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.session = session
|
||||
self.user_repo = UserRepository(session)
|
||||
self.card_repo = CardRepository(session)
|
||||
self.unique_repo = UniqueCardRepository(session)
|
||||
# Load card info from external source
|
||||
self.CARD_INFO = card_master_service.get_card_info()
|
||||
|
||||
async def draw_card(self, user_did: str, is_paid: bool = False) -> Tuple[Card, bool]:
|
||||
"""
|
||||
|
Reference in New Issue
Block a user