|
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)) |
|
|
|
|
|
|