Move to subfolder

This commit is contained in:
Eric Liu 2025-05-21 16:18:01 -07:00
parent a88e3afddf
commit 7eae51cc5c
23 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,76 @@
/**
* Placeholder for LLM-based move aggression/brilliance scoring.
* Will use OpenAI GPT-4o-mini via callOpenAI in the future.
*/
import { callOpenAI } from "./openai_client";
export async function scoreMoveAggression(
fenHistory: string[],
moveIdx: number,
moveSAN: string,
): Promise<string> {
const prompt = `Given the following chess game FEN history (one FEN per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\nEvaluate the aggression or brilliance of move #${moveIdx + 1} (${moveSAN}). Respond ONLY with a single digit from 1 (not aggressive) to 10 (extremely aggressive/brilliant). Be fast and concise.`;
const response = await callOpenAI(
[
{
role: "system",
content:
"You are a chess grandmaster evaluating move aggression and brilliance. Respond as quickly and concisely as possible.",
},
{ role: "user", content: prompt },
],
16,
);
return response;
}
/**
* Placeholder for LLM-based sacrifice justification.
* Will use OpenAI GPT-4o-mini via callOpenAI in the future.
*/
export async function justifySacrifice(
fenHistory: string[],
moveIdx: number,
moveSAN: string,
): Promise<string> {
const prompt = `Given the following chess game FEN history (one FEN per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\nWas the sacrifice in move #${moveIdx + 1} (${moveSAN}) justified? Reply in 1 short sentence: is the sacrifice justified or not, and why. Be fast and concise.`;
const response = await callOpenAI(
[
{
role: "system",
content:
"You are a chess grandmaster evaluating sacrifices. Respond as quickly and concisely as possible.",
},
{ role: "user", content: prompt },
],
16,
);
return response;
}
export async function scoreAndJustifyGame(
fenHistory: string[],
moveSANs: string[],
): Promise<{ score: string; justification: string }[]> {
const prompt = `Given the following chess game FEN history (one FEN per move) and the corresponding SAN moves, evaluate each move for aggression/brilliance and sacrifice justification.\n\nFEN history (one per move):\n${fenHistory.map((f, i) => `${i + 1}: ${f}`).join("\n")}\n\nSAN moves (one per move):\n${moveSANs.map((san, i) => `${i + 1}: ${san}`).join("\n")}\n\nFor each move, respond with a JSON array of objects, each with:\n- score: a single digit from 1 (not aggressive) to 10 (extremely aggressive/brilliant)\n- justification: 1 short sentence on whether the move is a justified sacrifice or not, and why.\n\nExample:\n[{"score": "7", "justification": "The sacrifice is risky but justified."}, ...]\n\nRespond ONLY with the JSON array, nothing else.`;
const response = await callOpenAI(
[
{
role: "system",
content:
"You are a chess grandmaster evaluating a full game for aggression and sacrifice justification. Respond as quickly and concisely as possible.",
},
{ role: "user", content: prompt },
],
512,
);
try {
const parsed = JSON.parse(response);
if (Array.isArray(parsed)) {
return parsed;
}
throw new Error("Response is not an array");
} catch (e) {
throw new Error("Failed to parse LLM response as JSON: " + response);
}
}

View file

@ -0,0 +1,31 @@
/**
* OpenAI API client for GPT-4o-mini feedback.
* Expects to run in Bun/Node.js where process.env is available.
* If you see a type error for 'process', install @types/node as a dev dependency.
*/
import OpenAI from "openai";
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
const OPENAI_API_KEY = process.env.OPENAI_API_KEY || "";
const MODEL = "gpt-4o-mini"; // Use gpt-4o-mini if available, else gpt-4o
if (!OPENAI_API_KEY) {
throw new Error("OPENAI_API_KEY is not set");
}
const openai = new OpenAI({ apiKey: OPENAI_API_KEY });
export async function callOpenAI(
messages: ChatCompletionMessageParam[],
max_tokens = 64,
): Promise<string> {
const response = await openai.chat.completions.create({
model: MODEL,
messages,
max_tokens,
});
const content = response.choices[0]?.message?.content;
if (!content) throw new Error("No content returned from OpenAI");
return content.trim();
}