christopher's picture
Update app.py
2eeb5dd verified
Raw
History Blame Contribute Delete
3.34 kB
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import chess
import chess.pgn
import time
from chess_search.sparse.bitmap import BitmapIndex
from chess_search.sparse.bitmap.parser import parse
from chess_search.sparse.bitmap.expressions import execute
idx = BitmapIndex.load_from_hub("christopher/chess-index")
games = {}
pgn = open("games.pgn")
i = 0
while (game := chess.pgn.read_game(pgn)):
gid = f"{game.headers.get('White', '?')} vs {game.headers.get('Black', '?')} {game.headers.get('Date', '')}"
board = game.board()
boards = []
for move in game.mainline_moves():
board.push(move)
boards.append(board.copy())
games[gid] = {"headers": dict(game.headers), "boards": boards}
i += 1
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
from pyroaring import BitMap
from chess_search.sparse.bitmap.query import (
on_file, on_rank, in_center, on_kingside, on_queenside,
empty_square, open_file, anywhere,
)
@app.get("/")
def read_root(request: Request):
return templates.TemplateResponse(request=request, name="index.html")
@app.post("/search")
async def search(data: dict):
start = time.time()
board = chess.Board(data["fen"])
tokens = [f"{p.symbol()}_{chess.square_name(sq)}" for sq, p in board.piece_map().items()]
matches = idx.query(tokens)
resolved = idx.resolve(matches)
seen_games = {}
for game_id, move_idx in resolved:
if game_id not in seen_games:
seen_games[game_id] = move_idx
results = []
for game_id, move_idx in seen_games.items():
g = games.get(game_id)
if not g or move_idx >= len(g["boards"]):
continue
results.append({
"FEN": g["boards"][move_idx].fen(),
"White": g["headers"].get("White", ""),
"Black": g["headers"].get("Black", ""),
"Event": g["headers"].get("Event", ""),
"Date": g["headers"].get("Date", ""),
"Result": g["headers"].get("Result", ""),
"MatchedMove": move_idx,
})
elapsed_ms = (time.time() - start) * 1000
return {"count": len(results), "results": results, "time_ms": elapsed_ms}
@app.post("/text-search")
async def text_search(data: dict):
start = time.time()
q = parse(data["query"])
matches = execute(q, idx)
resolved = idx.resolve(matches)
seen_games = {}
for game_id, move_idx in resolved:
if game_id not in seen_games:
seen_games[game_id] = move_idx
results = []
for game_id, move_idx in seen_games.items():
g = games.get(game_id)
if not g or move_idx >= len(g["boards"]):
continue
results.append({
"FEN": g["boards"][move_idx].fen(),
"White": g["headers"].get("White", ""),
"Black": g["headers"].get("Black", ""),
"Event": g["headers"].get("Event", ""),
"Date": g["headers"].get("Date", ""),
"Result": g["headers"].get("Result", ""),
"MatchedMove": move_idx,
})
elapsed_ms = (time.time() - start) * 1000
return {"count": len(results), "results": results, "time_ms": elapsed_ms}