| 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]) |
|
|
|
|
| |
| ai = TicTacToeAI() |
|
|
|
|
|
|
| |
| 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"): |
| print(f"Path: {route.path}, Name: {route.name}, Methods: {route.methods}") |
| elif isinstance(route, Mount): |
| print(f"Mounted Path: {route.path}, Name: {route.name}, App: {route.app}") |
| else: |
| print(f"Other Route Path: {route.path}, Name: {route.name}") |
|
|
| |
| 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, |
| "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() |
| 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)) |
|
|
|
|
|
|