예제 소스
바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개
vlmClient.ts
/** Browser client for the MariaGO WebSocket bridge. */
import { getSelectedVlmModelId } from "@/lib/vlmModels";
export type VlmMove =
| { ok: true; pass: true }
| { ok: true; pass: false; row: number; col: number }
| { ok: false; error: string };
/**
* HTTPS(baduk.mariago.kr)에서는 브라우저가 ws:// 를 막으므로
* nginx `/vlm-ws` → :9320 프록시를 통해 wss 동일 오리진으로 연결한다.
* 로컬 http는 기존처럼 hostname:9320.
* 오버라이드: localStorage.mariago_ws
*/
export function getBridgeUrl(): string {
if (typeof window === "undefined") return "ws://127.0.0.1:9320";
const override = localStorage.getItem("mariago_ws");
if (override) return override;
if (window.location.protocol === "https:") {
return `wss://${window.location.host}/vlm-ws`;
}
return `ws://${window.location.hostname}:9320`;
}
export async function requestVlmMove(opts: {
board: number[];
aiSide: 1 | 2;
gameEpoch: number;
rejects?: Array<[number, number]>;
timeoutMs?: number;
engine?: string;
ko?: [number, number] | null;
}): Promise<VlmMove> {
const url = getBridgeUrl();
const timeoutMs = opts.timeoutMs ?? 240_000;
return new Promise((resolve) => {
let settled = false;
const finish = (v: VlmMove) => {
if (settled) return;
settled = true;
try {
ws.close();
} catch {
/* ignore */
}
resolve(v);
};
let ws: WebSocket;
try {
ws = new WebSocket(url);
} catch (e) {
finish({ ok: false, error: `WebSocket 연결 실패: ${String(e)}` });
return;
}
const timer = setTimeout(() => {
finish({ ok: false, error: "VLM 응답 시간 초과" });
}, timeoutMs);
ws.onopen = () => {
ws.send(
JSON.stringify({
type: "move",
board: opts.board,
ai_side: opts.aiSide,
game_epoch: opts.gameEpoch,
rejects: opts.rejects ?? [],
engine: opts.engine || getSelectedVlmModelId(),
ko: opts.ko ?? null,
}),
);
};
ws.onmessage = (ev) => {
clearTimeout(timer);
try {
const msg = JSON.parse(String(ev.data));
if (msg.type === "error") {
finish({ ok: false, error: msg.error || "서버 오류" });
return;
}
if (msg.type === "move") {
if (msg.pass) finish({ ok: true, pass: true });
else finish({ ok: true, pass: false, row: msg.row, col: msg.col });
return;
}
finish({ ok: false, error: "알 수 없는 응답" });
} catch (e) {
finish({ ok: false, error: String(e) });
}
};
ws.onerror = () => {
clearTimeout(timer);
finish({
ok: false,
error: `브리지 연결 실패 (${url}). scripts/mariago_ws_bridge.py 실행 여부를 확인하세요.`,
});
};
});
}