1// Val Town Script: Dynamic Character Race Carousel with OpenAI
23// =============================================================================
5// =============================================================================
67// Import OpenAI library from Val Town's standard modules
8// Ensure you have the 'openai' secret set in your Val Town account.
9// Alternatives: import { OpenAI } from "npm:openai";
10import { OpenAI } from "https://esm.town/v/std/openai";
1112// --- Define Expected Data Structures ---
20}
2122// Defines the specific JSON structure expected back from the OpenAI API
23interface OpenAIResponse {
24races: RaceInfo[]; // An array containing the race information
25}
2627// --- Fallback Data ---
28// Provides default race data if the OpenAI API call fails or returns invalid data.
29// This ensures the carousel always has content to display.
30const fallbackRaceData: RaceInfo[] = [
58];
5960// --- OpenAI Generation Function ---
61// Asynchronously fetches race data from OpenAI's Chat Completion API.
62async function generateRaceDataWithOpenAI(): Promise<RaceInfo[]> {
63// Initialize the OpenAI client (using API key from Val Town secrets)
64const openai = new OpenAI();
6566// Detailed prompt instructing OpenAI to generate race data in a specific JSON format.
67const prompt = `
68Generate a list of exactly 4 distinct fantasy character races suitable for an RPG character creator carousel.
8990try {
91console.info("Requesting race data generation from OpenAI...");
92const completion = await openai.chat.completions.create({
93model: "gpt-4o", // Recommended model, can use "gpt-3.5-turbo" as a fallback
94messages: [{ role: "user", content: prompt }],
95// Force OpenAI to return JSON matching the structure described in the prompt
96response_format: { type: "json_object" },
97temperature: 0.8, // Balances creativity and consistency
101const rawContent = completion.choices[0]?.message?.content;
102if (!rawContent) {
103throw new Error("OpenAI returned an empty response message.");
104}
105// console.debug("Raw OpenAI Response:", rawContent); // Uncomment for deep debugging
106107console.info("Received response from OpenAI. Parsing and validating JSON...");
108const parsedJson = JSON.parse(rawContent);
109110// --- Rigorous Validation ---
111// Check if the parsed response conforms to the expected OpenAIResponse structure.
112if (
113typeof parsedJson !== "object" // Must be an object
125)
126) {
127console.warn("OpenAI response JSON failed validation:", parsedJson);
128throw new Error(
129"OpenAI response JSON does not match the expected structure or contains invalid data types/formats.",
130);
131}
132133// Type assertion after successful validation
134const generatedData = (parsedJson as OpenAIResponse).races;
135136console.info(`Successfully generated and validated ${generatedData.length} races from OpenAI.`);
137return generatedData;
138} catch (error) {
139console.error("Error fetching or processing data from OpenAI:", error);
140console.warn("Using fallback race data due to the error.");
141return fallbackRaceData; // Return default data on any failure
146// This function handles incoming HTTP requests and returns an HTML response.
147export default async function server(request: Request): Promise<Response> {
148// 1. Fetch Race Data: Attempt to get dynamic data from OpenAI, use fallback on error.
149const activeRaceData = await generateRaceDataWithOpenAI();
150151// 2. Define CSS Styles: Static CSS for the carousel appearance and animations.
379380// --- Injected Data ---
381// This 'raceData' variable receives the array generated by the server (OpenAI or fallback).
382// It's crucial that this data is valid JSON when the script runs.
383const raceData = ${JSON.stringify(activeRaceData, null, 2)}; // Pretty-print for readability in source
4* and their relationships (citations, references), visualizing them as a network graph.
5* Runs entirely within a single Val Town endpoint.
6* Uses React Flow for visualization and OpenAI for analysis.
7*
8* Structure adapted from the Multi-Agent AI Support Simulation example.
934// --- Main Server Request Handler (Val Town Entry Point) ---
935export default async function(req: Request): Promise<Response> {
936// --- Dynamic Import of OpenAI Library ---
937const { OpenAI } = await import("https://esm.town/v/std/openai");
938939// Server-side logging utility
943}
944945// --- OpenAI Initialization ---
946let openai: OpenAI;
947try {
948// Assumes OPENAI_API_KEY is set as a Val Town secret named 'openai'
949openai = new OpenAI();
950// Perform a simple test call or validation if needed, but often just instantiating is enough.
951} catch (e: any) {
952logServer("ERROR", "Failed to initialize OpenAI Client", { error: e.message });
953// If OpenAI fails to init, we can still potentially serve the HTML,
954// but API calls will fail later. For API calls, we return an immediate error.
955// We'll handle API call errors within the analysis function.
970}
971972// Check if OpenAI client initialized successfully *before* making the call
973if (!openai) {
974return {
975success: false,
976error: "OpenAI client failed to initialize. Check server logs and API key configuration.",
977};
978}
10181019try {
1020const completion = await openai.chat.completions.create({
1021model: "gpt-4o", // Recommend powerful model for this task
1022response_format: { type: "json_object" },
1079logServer("ERROR", "Policy Analysis tool execution failed", { errorMessage: error.message, stack: error.stack });
1080let specificError = error.message;
1081// Check for common OpenAI API errors
1082if (error.status === 401) specificError = "OpenAI Authentication failed. Check API key secret.";
1083if (error.status === 429) specificError = "OpenAI Rate limit or quota exceeded.";
1084if (error.status >= 500) specificError = "OpenAI server error. Please try again later.";
10851086return { success: false, error: `Analysis failed: \${specificError}` };
11001101try {
1102// --- Check OpenAI init status again specifically for API calls ---
1103if (!openai) {
1104throw new Error("OpenAI client is not available. Check server configuration/secrets.");
1105}
1106
faithfulTanEelmain.tsx20 matches
1// Val Town Script: Dynamic Character Race Carousel with OpenAI
23// Import the OpenAI library (ensure you have the 'openai' secret set in Val Town)
4import { OpenAI } from "https://esm.town/v/std/openai"; // Or use 'npm:openai' or 'std/openai'
56// --- Define Expected Data Structures ---
13}
1415// Define the specific JSON structure we expect OpenAI to return
16interface OpenAIResponse {
17races: RaceInfo[];
18}
1920// --- Fallback Data ---
21// Used if OpenAI call fails or returns invalid data
22const fallbackRaceData: RaceInfo[] = [
23{
47];
4849// --- OpenAI Generation Function ---
50async function generateRaceDataWithOpenAI(): Promise<RaceInfo[]> {
51// Use 'new OpenAI()' if using std/openai
52const openai = new OpenAI();
5354// Updated prompt requesting a specific JSON object structure
7071try {
72console.info("Calling OpenAI to generate race data...");
73const completion = await openai.chat.completions.create({
74model: "gpt-4o", // Or "gpt-3.5-turbo"
75messages: [{ role: "user", content: prompt }],
81const content = completion.choices[0]?.message?.content;
82if (!content) {
83throw new Error("OpenAI returned an empty response content.");
84}
8586console.info("Received response from OpenAI. Parsing JSON...");
87const parsedJson = JSON.parse(content);
88101)
102) {
103throw new Error("OpenAI response JSON does not match the expected structure or contains invalid data.");
104}
105106const generatedData = (parsedJson as OpenAIResponse).races;
107108console.info(`Successfully generated and validated ${generatedData.length} races.`);
109return generatedData;
110} catch (error) {
111console.error("Error fetching or processing data from OpenAI:", error);
112console.warn("Using fallback race data due to error.");
113return fallbackRaceData;
117// --- Main HTTP Handler (Val Town Entry Point) ---
118export default async function server(request: Request): Promise<Response> {
119// 1. Generate race data using OpenAI (or use fallback on error)
120const activeRaceData = await generateRaceDataWithOpenAI();
121122// 2. Define CSS (remains static)
165166// Inject the dynamically generated data from the server
167// This 'raceData' variable will hold the array from OpenAI or the fallback
168const raceData = ${JSON.stringify(activeRaceData, null, 2)};
169
stevensDemo.cursorrules4 matches
100Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
101102### OpenAI
103```ts
104import { OpenAI } from "https://esm.town/v/std/openai";
105const openai = new OpenAI();
106const completion = await openai.chat.completions.create({
107messages: [
108{ role: "user", content: "Say hello in a creative way" },
stevensDemo.cursorrules4 matches
100Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
101102### OpenAI
103```ts
104import { OpenAI } from "https://esm.town/v/std/openai";
105const openai = new OpenAI();
106const completion = await openai.chat.completions.create({
107messages: [
108{ role: "user", content: "Say hello in a creative way" },
strategistmain.tsx3 matches
276export default async function server(request: Request): Promise<Response> {
277if (request.method === "POST" && new URL(request.url).pathname === "/generate-plan") {
278const { OpenAI } = await import("https://esm.town/v/std/openai");
279const openai = new OpenAI();
280
281const { context } = await request.json();
282283const completion = await openai.chat.completions.create({
284model: "gpt-4o-mini",
285messages: [
flashcardsmain.tsx4 matches
89export default async function server(request: Request): Promise<Response> {
90if (request.method === "POST" && new URL(request.url).pathname === "/generate") {
91const { OpenAI } = await import("https://esm.town/v/std/openai");
92const openai = new OpenAI();
9394try {
95const { topic } = await request.json();
96
97const completion = await openai.chat.completions.create({
98model: "gpt-4o-mini",
99messages: [
137138const flashcardsResponse = completion.choices[0].message.content;
139console.log("Raw OpenAI response:", flashcardsResponse); // Detailed debug logging
140141// More robust JSON parsing with extensive error handling
stevensDemo.cursorrules4 matches
100Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
101102### OpenAI
103```ts
104import { OpenAI } from "https://esm.town/v/std/openai";
105const openai = new OpenAI();
106const completion = await openai.chat.completions.create({
107messages: [
108{ role: "user", content: "Say hello in a creative way" },
EEPMOnitoringmain.tsx4 matches
2import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
3import React, { useEffect, useState } from "https://esm.sh/react@18.2.0";
4import { OpenAI } from "https://esm.town/v/std/openai";
5import { sqlite } from "https://esm.town/v/stevekrouse/sqlite";
6113export default async function server(request: Request): Promise<Response> {
114if (request.method === "POST") {
115const openai = new OpenAI();
116const KEY = "EEPMOnitoring";
117157if (existingArticle.rows.length === 0) {
158try {
159const analysis = await openai.chat.completions.create({
160model: "gpt-4o-mini",
161messages: [
188});
189} catch (aiError) {
190console.error("OpenAI analysis error:", aiError);
191// Fallback analysis
192await sqlite.execute(
finalRoundFeedmain.tsx3 matches
1import { Bot } from "https://esm.sh/grammy@1.25.0";
2import { OpenAI } from "https://esm.town/v/std/openai";
3import { XMLParser } from "npm:fast-xml-parser";
435}
3637const openai = new OpenAI();
38const bot = new Bot(TELEGRAM_TOKEN);
394950async function summarizeDescription(item: RSSItem): Promise<string> {
51const completion = await openai.chat.completions.create({
52messages: [
53{