게시판SGF 기보로 학습하는 바둑 LLM 인공지능예제 소스

예제 소스

SGF 기보로 학습하는 바둑 LLM 인공지능 · 파일 169개

route.ts

import { NextRequest, NextResponse } from "next/server";
import { spawn } from "node:child_process";
import path from "node:path";
import type { MoveRec } from "@/lib/gameTypes";

export const runtime = "nodejs";
export const maxDuration = 60;

type Body = {
  moves?: MoveRec[];
  komi?: number;
  maxVisits?: number;
};

function pyBin(): string {
  const venv = path.join(process.cwd(), "..", ".venv", "bin", "python");
  return venv;
}

export async function POST(req: NextRequest) {
  const body = (await req.json().catch(() => null)) as Body | null;
  if (!body || !Array.isArray(body.moves)) {
    return NextResponse.json({ error: "moves required" }, { status: 400 });
  }

  const script = path.join(process.cwd(), "..", "scripts", "katago_analyze.py");
  const payload = JSON.stringify({
    moves: body.moves,
    komi: body.komi ?? 6.5,
    maxVisits: body.maxVisits ?? 80,
  });

  return new Promise<Response>((resolve) => {
    const proc = spawn(pyBin(), [script], {
      cwd: path.join(process.cwd(), ".."),
      stdio: ["pipe", "pipe", "pipe"],
    });

    let out = "";
    let err = "";
    proc.stdout.on("data", (d) => {
      out += String(d);
    });
    proc.stderr.on("data", (d) => {
      err += String(d);
    });

    const timer = setTimeout(() => {
      proc.kill("SIGTERM");
      resolve(
        NextResponse.json({ error: "KataGo 분석 시간 초과" }, { status: 504 }),
      );
    }, 55_000);

    proc.on("close", (code) => {
      clearTimeout(timer);
      if (code !== 0) {
        resolve(
          NextResponse.json(
            {
              error: "KataGo 분석 실패",
              detail: err.slice(-800) || `exit ${code}`,
            },
            { status: 502 },
          ),
        );
        return;
      }
      try {
        const line = out.trim().split("\n").filter(Boolean).pop() || "{}";
        const data = JSON.parse(line) as Record<string, unknown>;
        resolve(NextResponse.json(data));
      } catch (e) {
        resolve(
          NextResponse.json(
            { error: "분석 결과 파싱 실패", detail: String(e), raw: out.slice(-500) },
            { status: 502 },
          ),
        );
      }
    });

    proc.stdin.write(payload);
    proc.stdin.end();
  });
}