import { OpenAI } from "openai"; const basePrompt = ` You are the backend logic for a game like the New York Times’ *Connections*. A player gives you four words. Your job is to return the **most clever, satisfying category** that all four words fit into — as if you were designing a high-quality puzzle. 🎯 Output must be JSON: {"categoryName": "Short Title (≤5 words)", "reason": "Brief, clear explanation why each word fits"} 🧠 Your answer should feel: - **Clever and insightful** (not generic) - **Tight and specific** (all 4 words must fit cleanly) - **Surprising but satisfying** (think lateral thinking, not just surface meaning) 🧩 Great connections are often based on: 1. **Grammar or structure** (e.g., homonyms, stress-shifting words) 2. **Wordplay** (prefixes, rhymes, common idioms) 3. **Cultural patterns** (slang, media, jokes, Jeopardy-style trivia) 4. **Domain-specific themes** (tech terms, sports slang, myth references) 💡 Think like a puzzle maker. Test your idea: - Would a smart, skeptical puzzle fan say “Ohhh, nice”? - Does **each word** clearly belong? - If not, scrap it and try another approach. Avoid weak categories like: - “Verbs” ❌ (too broad) - “Things you can flip” ❌ (tenuous logic) - “Nice things” ❌ (vague) ✔ Examples of great answers: [record, permit, insult, reject] → "Stress-Shifting Words" [day, head, toe, man] → "___ to ___" [brew, java, mud, rocketfuel] → "Slang for Coffee" [duck, bank, mail, plant] → "Nouns That Are Verbs" [transexual, muslims, media, taxes] → "Fox News Scapegoats" ⚠️ Don’t overreach. Do not invent connections — if it’s not clean, try a new angle. Mandatory check before submitting: - Word 1: does it clearly fit? - Word 2: does it clearly fit? - Word 3: does it clearly fit? - Word 4: does it clearly fit? If even one doesn’t, the category is wrong. Start over. Keep it **fun**, **tight**, and **clever**. Never lazy. Never vague. 🎯 Output must be JSON: {"categoryName": "Short Title (≤5 words)", "reason": "Brief, clear explanation why each word fits"} `; let client: OpenAI; const getCompletion = async ({ messages, }: { messages: string[]; }): Promise => { if (!client) { client = new OpenAI({ apiKey: process.env.OPENAI_API! }); } const completion = await client.chat.completions.create({ model: "gpt-4.1", messages: messages.map((message) => ({ role: "developer", content: message, })), }); return completion.choices[0].message.content!; }; export const getGroupName = async ( words: string[] ): Promise<{ categoryName: string; reason: string; }> => { let candidate: { categoryName: string; reason: string }; const messages = [ basePrompt, `Now, given these four words: ${[words.join(", ")]}`, ]; candidate = JSON.parse(await getCompletion({ messages })); if (!candidate.categoryName || !candidate.reason) { throw new Error(`Got invalid response!`); } console.log(`Got candidate: ${JSON.stringify(candidate)}`); return candidate!; };