Louai_performance_api.ts15 matches
1/**
2* AI Team Performance Analysis HTTP API
3*
4* Provides HTTP endpoints for triggering analysis and accessing results
1516/**
17* Main HTTP handler for AI performance analysis API
18*
19* Supported endpoints:
7172if (method === "GET" && pathname === "/") {
73return await handleApiDocumentation(corsHeaders);
74}
7594);
95} catch (error) {
96console.error("API Error:", error);
97return new Response(
98JSON.stringify({
131}
132133console.log(`π API: Starting analysis for user ${userId}, league ${leagueId}`);
134const startTime = Date.now();
135159}
160161console.log(`β API: Analysis complete in ${executionTime}ms`);
162163// Return structured response
205async function handleGetAnalysis(userId: string, corsHeaders: Record<string, string>): Promise<Response> {
206try {
207console.log(`π API: Retrieving latest analysis for user ${userId}`);
208209const latestAnalysis = await getLatestAnalysis(userId);
259timestamp: new Date().toISOString(),
260services: {
261api: "operational",
262scheduler: schedulerSummary.error ? "degraded" : "operational",
263storage: "operational",
319await addSchedulerConfig(schedulerConfig);
320321console.log(`β° API: Scheduler config added for user ${config.userId}`);
322323return new Response(
363await removeSchedulerConfig(userId, leagueId);
364365console.log(`ποΈ API: Scheduler config removed for user ${userId}`);
366367return new Response(
398summary,
399nextRun: "Configured in Val.town cron settings",
400documentation: "See API docs for scheduling configuration",
401};
402417418/**
419* Handle API documentation request
420* GET /
421*/
422async function handleApiDocumentation(corsHeaders: Record<string, string>): Promise<Response> {
423const docs = {
424title: "AI Fantasy Baseball Performance Analysis API",
425version: "1.0.0",
426description: "API for triggering AI-powered fantasy baseball analysis and waiver wire recommendations",
427endpoints: {
428"POST /analyze": {
Loudaily_lineup_scheduler.tsx26 matches
90}
9192export interface YahooAPIConfig {
93access_token: string;
94refresh_token: string;
167}
168169// Initialize Yahoo Fantasy API client
170const yahooAPI = new YahooFantasyAPIClient(tokenData, this.tokenStorage, userId);
171172// Get user's leagues
173const leagues = await yahooAPI.getUserLeagues(userId);
174console.log(`ποΈ Found ${leagues.length} leagues for user ${userId}`);
175179180// Get user's team in this league
181const teamKey = await yahooAPI.getTeamKey(userId, league.league_id);
182if (!teamKey) {
183throw new Error(`Could not find team key for league ${league.league_id}`);
185186// Schedule pitchers for today
187const scheduleResult = await this.schedulePitchersForTeam(yahooAPI, teamKey, date);
188189results.leagues_processed.push({
207}
208209private async schedulePitchersForTeam(yahooAPI: YahooFantasyAPIClient, teamKey: string, date: Date) {
210// Get today's probable pitchers from MLB API
211const probablePitchers = await this.getTodaysProbablePitchers(date);
212console.log(`π― Found ${probablePitchers.length} probable pitchers for ${date.toDateString()}`);
213214// Get current team roster
215const roster = await yahooAPI.getTeamRoster(teamKey);
216console.log(`π₯ Team roster has ${roster.length} players`);
217234for (const change of optimization.changes) {
235try {
236await yahooAPI.setPlayerPosition(teamKey, change.playerId, change.newPosition);
237results.pitchers_scheduled.push(change.playerId);
238results.changes_made.push(change);
254): Promise<Array<{ name: string; team: string; game_time?: string }>> {
255try {
256// Call MLB Stats API for probable pitchers
257const dateStr = date.toISOString().split("T")[0];
258const response = await fetch(
259`https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=${dateStr}&hydrate=probablePitcher`,
260);
261262if (!response.ok) {
263throw new Error(`MLB API error: ${response.status}`);
264}
265508}
509510// Simplified Yahoo Fantasy API client for Val.town
511export class YahooFantasyAPIClient {
512private config: YahooAPIConfig;
513private baseUrl = "https://fantasysports.yahooapis.com/fantasy/v2";
514private tokenStorage: LouTokenStorage;
515private userId: string;
516517constructor(config: YahooAPIConfig, tokenStorage: LouTokenStorage, userId: string) {
518this.config = config;
519this.tokenStorage = tokenStorage;
533private async refreshAccessToken(): Promise<void> {
534try {
535const response = await fetch("https://api.login.yahoo.com/oauth2/get_token", {
536method: "POST",
537headers: {
619620if (!retryResponse.ok) {
621throw new Error(`Yahoo API error after refresh: ${retryResponse.status} ${retryResponse.statusText}`);
622}
623626627if (!response.ok) {
628throw new Error(`Yahoo API error: ${response.status} ${response.statusText}`);
629}
630812await this.ensureValidToken();
813814// Yahoo Fantasy API requires XML for roster changes
815const dateStr = new Date().toISOString().split("T")[0];
816844if (!response.ok) {
845const responseText = await response.text();
846console.error(`β Yahoo API error response: ${responseText}`);
847throw new Error(`Failed to set player position: ${response.status} ${response.statusText}`);
848}
1092// Get player stats if available
1093const seasonStats: Record<string, string | number> = {};
1094// Note: Individual player stats would require separate API calls
1095// For waiver wire, we focus on basic availability and position info
109611481149// Check if player has ownership information
1150// Yahoo API doesn't directly provide ownership percentage, so we estimate based on availability
1151let ownershipPercentage = 0;
1152let isAvailable = true;
13911392// Store results in Val.town's blob storage for history
1393await fetch("https://api.val.town/v1/blob/scheduler_results", {
1394method: "POST",
1395headers: {
Louai_team_performance_review.ts46 matches
7TeamPerformanceStats,
8WaiverWirePlayer,
9YahooFantasyAPIClient,
10} from "../daily_lineup_scheduler.tsx";
11import { LouTokenStorage } from "../token_storage.tsx";
135review?: AITeamPerformanceReview;
136error?: {
137type: "AUTH_ERROR" | "API_ERROR" | "ANALYSIS_ERROR" | "VALIDATION_ERROR" | "UNKNOWN_ERROR";
138message: string;
139details?: any;
141execution_stats: {
142duration_ms: number;
143api_calls_made: number;
144tokens_used?: number;
145rate_limited: boolean;
213): Promise<ReviewExecutionResult> {
214const startTime = Date.now();
215let apiCallsCounter = 0;
216let rateLimited = false;
217226"No valid authentication tokens found",
227startTime,
228apiCallsCounter,
229rateLimited,
230);
231}
232233// Step 2: Initialize Yahoo API client
234const yahooAPI = new YahooFantasyAPIClient(tokenData, this.tokenStorage, userId);
235236// Step 3: Get team key if not provided
237if (!teamKey) {
238teamKey = await yahooAPI.getTeamKey(userId, leagueId);
239apiCallsCounter++;
240241if (!teamKey) {
242return this.createErrorResult(
243"API_ERROR",
244"Could not determine team key for user in league",
245startTime,
246apiCallsCounter,
247rateLimited,
248);
254// Step 4: Gather comprehensive performance data
255console.log("π Gathering performance data...");
256const performanceData = await this.gatherPerformanceData(yahooAPI, teamKey, leagueId);
257apiCallsCounter += performanceData.apiCalls;
258rateLimited = rateLimited || performanceData.rateLimited;
259260if (!performanceData.success) {
261return this.createErrorResult(
262"API_ERROR",
263"Failed to gather performance data",
264startTime,
265apiCallsCounter,
266rateLimited,
267performanceData.error,
277`Data validation failed: ${validationResult.errors.join(", ")}`,
278startTime,
279apiCallsCounter,
280rateLimited,
281);
296"Failed to generate performance analysis report",
297startTime,
298apiCallsCounter,
299rateLimited,
300);
309"AI analysis failed",
310startTime,
311apiCallsCounter,
312rateLimited,
313aiAnalysisResult.error,
326"Waiver analysis failed",
327startTime,
328apiCallsCounter,
329rateLimited,
330waiverAnalysisResult.error,
349execution_stats: {
350duration_ms: duration,
351api_calls_made: apiCallsCounter,
352rate_limited: rateLimited,
353},
359error instanceof Error ? error.message : "Unknown error occurred",
360startTime,
361apiCallsCounter,
362rateLimited,
363error,
419results: {
420authentication: boolean;
421yahooAPI: boolean;
422openAI: boolean;
423performanceAnalyzer: boolean;
429const results = {
430authentication: false,
431yahooAPI: false,
432openAI: false,
433performanceAnalyzer: false,
445}
446447// Test 2: OpenAI API
448try {
449const openAITest = await this.openaiClient.testConnection();
468}
469470// Test 4: Yahoo API (requires valid tokens, so just test instantiation)
471try {
472const testTokens = { access_token: "test", refresh_token: "test", expires_at: Date.now() + 3600000 };
473const yahooAPI = new YahooFantasyAPIClient(testTokens, this.tokenStorage, "test_user");
474results.yahooAPI = true; // If instantiation succeeds
475console.log("β Yahoo API test passed");
476} catch (error) {
477errors.push(`Yahoo API test failed: ${error}`);
478console.log("β Yahoo API test failed");
479}
480497*/
498private async gatherPerformanceData(
499yahooAPI: YahooFantasyAPIClient,
500teamKey: string,
501leagueId: string,
508leagueContext?: any;
509};
510apiCalls: number;
511rateLimited: boolean;
512error?: any;
513}> {
514let apiCalls = 0;
515let rateLimited = false;
516517try {
518// Get team performance stats
519const teamStats = await yahooAPI.getTeamPerformanceStats(teamKey, leagueId);
520apiCalls++;
521522if (!teamStats) {
525526// Get team roster
527const roster = await yahooAPI.getTeamRoster(teamKey);
528apiCalls++;
529530// Get detailed player performance (batch process to avoid rate limits)
534for (let i = 0; i < roster.length; i += batchSize) {
535const batch = roster.slice(i, i + batchSize);
536const batchPromises = batch.map(player => yahooAPI.getPlayerPerformanceStats(player.player_id, leagueId));
537538try {
539const batchResults = await Promise.allSettled(batchPromises);
540apiCalls += batch.length;
541542for (const result of batchResults) {
557558// Get waiver wire players
559const waiverPlayers = await yahooAPI.getWaiverWirePlayers(
560leagueId,
561undefined, // No position filter
562undefined, // No ownership threshold
563);
564apiCalls++;
565566// Limit waiver candidates to avoid token overflow
578teamKey,
579);
580// Note: This doesn't count as additional API calls since it uses cached data
581} catch (error) {
582console.log("β οΈ Could not gather league context:", error);
592leagueContext,
593},
594apiCalls,
595rateLimited,
596};
598return {
599success: false,
600apiCalls,
601rateLimited,
602error,
832message: string,
833startTime: number,
834apiCalls: number,
835rateLimited: boolean,
836details?: any,
841execution_stats: {
842duration_ms: Date.now() - startTime,
843api_calls_made: apiCalls,
844rate_limited: rateLimited,
845},
15Use GlobalRateLimitedChatOpenAI(model, requestsPerSecond) to enforce a global rate limit on chat completions, suitable for shared or public-facing endpoints.
16Val Town/Platform Notes
17Uses Val Townβs standard SQLite API for persistent storage.
18Designed for server-side use (no browser-specific code).
19No secrets are hardcoded; OpenAI API keys are managed by the OpenAI SDK/environment.
openai-clientopenai-client.mdc2 matches
15Use GlobalRateLimitedChatOpenAI(model, requestsPerSecond) to enforce a global rate limit on chat completions, suitable for shared or public-facing endpoints.
16Val Town/Platform Notes
17Uses Val Townβs standard SQLite API for persistent storage.
18Designed for server-side use (no browser-specific code).
19No secrets are hardcoded; OpenAI API keys are managed by the OpenAI SDK/environment.
sqliteExplorerApp1README.md1 match
13## Authentication
1415Login to your SQLite Explorer with [password authentication](https://www.val.town/v/pomdtr/password_auth) with your [Val Town API Token](https://www.val.town/settings/api) as the password.
1617## Todos / Plans
sqliteExplorerApp1main.tsx2 matches
27<head>
28<title>SQLite Explorer</title>
29<link rel="preconnect" href="https://fonts.googleapis.com" />
3031<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
32<link
33href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
34rel="stylesheet"
35/>
openai-client.cursorrules10 matches
13- Generate code in TypeScript or TSX
14- Add appropriate TypeScript types and interfaces for all data structures
15- Prefer official SDKs or libraries than writing API calls directly
16- Ask the user to supply API or library documentation if you are at all unsure about it
17- **Never bake in secrets into the code** - always use environment variables
18- Include comments explaining complex logic (avoid commenting obvious operations)
23### 1. HTTP Trigger
2425- Create web APIs and endpoints
26- Handle HTTP requests and responses
27- Example structure:
173However, it's *extremely importing* to note that `parseProject` and other Standard Library utilities ONLY RUN ON THE SERVER.
174If you need access to this data on the client, run it in the server and pass it to the client by splicing it into the HTML page
175or by making an API request for it.
176177## Val Town Platform Specifics
181- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
182- **Storage:** DO NOT use the Deno KV module for storage
183- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
184- **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified
185- **View Source:** Add a view source link by importing & using `import.meta.url.replace("ems.sh", "val.town)"` (or passing this data to the client) and include `target="_top"` attribute
186- **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors
187- **Error Handling:** Only use try...catch when there's a clear local resolution; Avoid catches that merely log or return 500s. Let errors bubble up with full context
188- **Environment Variables:** Use `Deno.env.get('keyname')` when you need to, but generally prefer APIs that don't require keys
189- **Imports:** Use `https://esm.sh` for npm and Deno dependencies to ensure compatibility on server and browser
190- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
224### Backend (Hono) Best Practices
225226- Hono is the recommended API framework
227- Main entry point should be `backend/index.ts`
228- **Static asset serving:** Use the utility functions to read and serve project files:
248});
249```
250- Create RESTful API routes for CRUD operations
251- Always include this snippet at the top-level Hono app to re-throwing errors to see full stack traces:
252```ts
285- For files in the project, use `readFile` helpers
2862875. **API Design:**
288- `fetch` handler is the entry point for HTTP vals
289- Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals`
openai-clientknowledge.md10 matches
13- Generate code in TypeScript or TSX
14- Add appropriate TypeScript types and interfaces for all data structures
15- Prefer official SDKs or libraries than writing API calls directly
16- Ask the user to supply API or library documentation if you are at all unsure about it
17- **Never bake in secrets into the code** - always use environment variables
18- Include comments explaining complex logic (avoid commenting obvious operations)
23### 1. HTTP Trigger
2425- Create web APIs and endpoints
26- Handle HTTP requests and responses
27- Example structure:
173However, it's *extremely importing* to note that `parseProject` and other Standard Library utilities ONLY RUN ON THE SERVER.
174If you need access to this data on the client, run it in the server and pass it to the client by splicing it into the HTML page
175or by making an API request for it.
176177## Val Town Platform Specifics
181- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
182- **Storage:** DO NOT use the Deno KV module for storage
183- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
184- **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified
185- **View Source:** Add a view source link by importing & using `import.meta.url.replace("ems.sh", "val.town)"` (or passing this data to the client) and include `target="_top"` attribute
186- **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors
187- **Error Handling:** Only use try...catch when there's a clear local resolution; Avoid catches that merely log or return 500s. Let errors bubble up with full context
188- **Environment Variables:** Use `Deno.env.get('keyname')` when you need to, but generally prefer APIs that don't require keys
189- **Imports:** Use `https://esm.sh` for npm and Deno dependencies to ensure compatibility on server and browser
190- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
224### Backend (Hono) Best Practices
225226- Hono is the recommended API framework
227- Main entry point should be `backend/index.ts`
228- **Static asset serving:** Use the utility functions to read and serve project files:
248});
249```
250- Create RESTful API routes for CRUD operations
251- Always include this snippet at the top-level Hono app to re-throwing errors to see full stack traces:
252```ts
285- For files in the project, use `readFile` helpers
2862875. **API Design:**
288- `fetch` handler is the entry point for HTTP vals
289- Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals`
quizMastergemini.tsx1 match
1import { GoogleGenAI, Type } from "npm:@google/genai";
23const ai = new GoogleGenAI({ apiKey: "AIzaSyDcuswpF8sAUBVTvrUlnpADXF4gHjTTAxA" });
45const _prompt = `Parse the image and extract the question and options, also find the answer if given otherwise return "".