from fastapi import FastAPI, HTTPException, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from starlette.routing import Mount import numpy as np from tensorflow import keras import hashlib import json import os class TicTacToeAI: def __init__(self, model_path="model/model.keras"): self.model_path = model_path self.model = None self.load_model() def load_model(self): """Wczytuje model z pliku""" if os.path.exists(self.model_path): self.model = keras.models.load_model(self.model_path) return True return False def get_move(self, board): """Zwraca najlepszy ruch dla danego stanu planszy""" if self.model is None: raise ValueError("Model nie został wczytany") board_array = np.array(board) predictions = self.model.predict(board_array.reshape(1, -1), verbose=0)[0] valid_moves = np.where(board_array == 0)[0] if len(valid_moves) == 0: raise ValueError("Brak dostępnych ruchów") valid_predictions = [(i, pred) for i, pred in enumerate(predictions) if i in valid_moves] return int(max(valid_predictions, key=lambda x: x[1])[0]) # Inicjalizacja AI ai = TicTacToeAI() # Ustawienie prefiksu aplikacji app = FastAPI(root_path="/spaces/labapawel/tictactoe") @app.on_event("startup") async def print_routes(): """Wyświetla wszystkie zarejestrowane trasy""" for route in app.routes: if hasattr(route, "methods"): # Jeśli trasa obsługuje metody HTTP print(f"Path: {route.path}, Name: {route.name}, Methods: {route.methods}") elif isinstance(route, Mount): # Jeśli to katalog statyczny print(f"Mounted Path: {route.path}, Name: {route.name}, App: {route.app}") else: # Inny typ trasy print(f"Other Route Path: {route.path}, Name: {route.name}") # Montowanie katalogu publicznego app.mount("/static", StaticFiles(directory="public"), name="static") @app.get("/", response_class=HTMLResponse) async def read_root(): try: with open("public/index.html", "r") as file: return HTMLResponse(content=file.read(), status_code=200) except FileNotFoundError: return HTMLResponse(content="Plik index.html nie został znaleziony", status_code=404) @app.get("/status") async def get_status(): print("Endpoint /status został wywołany.") return { "status": "success", "model_loaded": True, # lub odpowiedni warunek "model_path": "model/model.keras" } @app.post("/savegame") async def save_game(request: Request): try: data = await request.json() final_board = data.get("final_board") sequence = data.get("sequence") if not final_board or not sequence: raise HTTPException(status_code=400, detail="Missing required data") game_hash = hash(str(final_board) + str(sequence)) game_data = { "final_board": final_board, "sequence": sequence, "hash": game_hash } try: with open("public/games_data.json", "r") as f: existing_data = json.load(f) except (FileNotFoundError, json.JSONDecodeError): existing_data = [] existing_data.append(game_data) with open("public/games_data.json", "w") as f: json.dump(existing_data, f) return {"status": "success", "hash": game_data["hash"]} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.post("/move") async def get_move(request: Request): """ Endpoint do wykonania ruchu AI """ try: data = await request.json() # Pobierz dane JSON z żądania board = data.get("board") if not board: raise HTTPException(status_code=400, detail="Brak planszy w żądaniu") if len(board) != 9 or not all(x in [0, 1, -1] for x in board): raise HTTPException(status_code=400, detail="Nieprawidłowe dane planszy") move = ai.get_move(board) return {"status": "success", "move": move} except Exception as e: raise HTTPException(status_code=500, detail=str(e))