Louai_performance_logger.ts53 matches
5timestamp: string;
6sessionId: string;
7type: 'yahoo_api' | 'mlb_data' | 'openai_request' | 'openai_response' | 'error' | 'performance';
8userId?: string;
9leagueId?: string;
31summary?: {
32yahooApiCalls: number;
33openaiRequests: number;
34totalTokensUsed: number;
35errors: number;
123124/**
125* Log OpenAI request with full prompt
126*/
127logOpenAiRequest(model: string, prompt: string, requestConfig: any, retryAttempt: number = 0): void {
128this.addLogEntry({
129type: 'openai_request',
130data: {
131model,
144145/**
146* Log OpenAI response with full content
147*/
148logOpenAiResponse(model: string, response: string, executionTime: number, tokenCount?: number): void {
149this.addLogEntry({
150type: 'openai_response',
151data: {
152model,
240241const yahooEntries = session.entries.filter(e => e.type === 'yahoo_api');
242const openaiRequests = session.entries.filter(e => e.type === 'openai_request');
243const openaiResponses = session.entries.filter(e => e.type === 'openai_response');
244const errors = session.entries.filter(e => e.type === 'error');
245256257## AI Processing
258- OpenAI Requests: ${openaiRequests.length}
259- OpenAI Responses: ${openaiResponses.length}
260- Total Tokens Used: ${openaiResponses.reduce((sum, e) => sum + (e.metadata?.tokenCount || 0), 0)}
261- Average AI Response Time: ${openaiResponses.length > 0 ? Math.round(openaiResponses.reduce((sum, e) => sum + (e.metadata?.executionTime || 0), 0) / openaiResponses.length) : 0}ms
262263## Errors
312313/**
314* Extract all OpenAI prompts and responses for analysis
315*/
316extractOpenAiData(sessionId: string): any {
317const session = this.sessions.get(sessionId);
318if (!session) return null;
319320const openaiRequests = session.entries.filter(e => e.type === 'openai_request');
321const openaiResponses = session.entries.filter(e => e.type === 'openai_response');
322323return {
324sessionId,
325timestamp: session.startTime,
326requests: openaiRequests.map((entry, index) => ({
327requestId: index,
328timestamp: entry.timestamp,
333config: entry.data.config
334})),
335responses: openaiResponses.map((entry, index) => ({
336responseId: index,
337timestamp: entry.timestamp,
355356const yahooData = this.extractYahooData(sessionId);
357const openaiData = this.extractOpenAiData(sessionId);
358359return `
366- Total Data Collected: ${yahooData?.yahooApiCalls?.reduce((sum, call) => sum + (call.dataSize || 0), 0)} bytes
367368## OpenAI Processing Quality
369- Requests Made: ${openaiData?.requests?.length || 0}
370- Responses Received: ${openaiData?.responses?.length || 0}
371- Average Prompt Length: ${openaiData?.requests?.reduce((sum, req) => sum + (req.promptLength || 0), 0) / (openaiData?.requests?.length || 1)} characters
372- Parse Success Rate: ${openaiData?.responses?.filter(r => r.parsedSuccessfully).length / (openaiData?.responses?.length || 1) * 100}%
373- Average Response Time: ${openaiData?.responses?.reduce((sum, res) => sum + (res.executionTime || 0), 0) / (openaiData?.responses?.length || 1)}ms
374375## Recommendations for Prompt Optimization
376${this.generatePromptOptimizationRecommendations(openaiData)}
377`;
378}
396},
397yahooData: this.extractYahooData(sessionId),
398openaiData: this.extractOpenAiData(sessionId),
399performance: session.entries.filter(e => e.type === 'performance'),
400errors: session.entries.filter(e => e.type === 'error'),
433private generateSessionSummary(session: LogSession): LogSession['summary'] {
434const yahooApiCalls = session.entries.filter(e => e.type === 'yahoo_api').length;
435const openaiRequests = session.entries.filter(e => e.type === 'openai_request').length;
436const totalTokensUsed = session.entries
437.filter(e => e.type === 'openai_response')
438.reduce((sum, e) => sum + (e.metadata?.tokenCount || 0), 0);
439const errors = session.entries.filter(e => e.type === 'error').length;
441return {
442yahooApiCalls,
443openaiRequests,
444totalTokensUsed,
445errors,
450private calculateDataQualityScore(session: LogSession): number {
451// Simple scoring based on successful responses and data completeness
452const totalRequests = session.entries.filter(e => e.type === 'yahoo_api' || e.type === 'openai_request').length;
453const errors = session.entries.filter(e => e.type === 'error').length;
454const successfulResponses = session.entries.filter(e => e.type === 'openai_response' && e.data.parsedSuccessfully).length;
455
456if (totalRequests === 0) return 0;
457
458const errorRate = errors / totalRequests;
459const successRate = successfulResponses / session.entries.filter(e => e.type === 'openai_request').length;
460
461return Math.round((1 - errorRate) * successRate * 100);
464private analyzeDataQuality(session: LogSession): string {
465const yahooEntries = session.entries.filter(e => e.type === 'yahoo_api');
466const openaiResponses = session.entries.filter(e => e.type === 'openai_response');
467
468const insights = [];
475}
476
477if (openaiResponses.length > 0) {
478const successfulParses = openaiResponses.filter(e => e.data.parsedSuccessfully).length;
479const parseSuccessRate = (successfulParses / openaiResponses.length) * 100;
480insights.push(`- OpenAI JSON parse success rate: ${Math.round(parseSuccessRate)}%`);
481}
482
488
489const yahooEntries = session.entries.filter(e => e.type === 'yahoo_api');
490const openaiRequests = session.entries.filter(e => e.type === 'openai_request');
491const openaiResponses = session.entries.filter(e => e.type === 'openai_response');
492const errors = session.entries.filter(e => e.type === 'error');
493
498
499// Check for large prompts
500const avgPromptSize = openaiRequests.reduce((sum, e) => sum + (e.data.promptLength || 0), 0) / openaiRequests.length;
501if (avgPromptSize > 5000) {
502recommendations.push('- Consider reducing prompt size for faster OpenAI responses');
503}
504
505// Check for parsing errors
506const parseFailures = openaiResponses.filter(e => !e.data.parsedSuccessfully).length;
507if (parseFailures > 0) {
508recommendations.push('- Improve prompt clarity to reduce JSON parsing failures');
510
511// Check for slow responses
512const slowResponses = openaiResponses.filter(e => (e.metadata?.executionTime || 0) > 15000).length;
513if (slowResponses > 0) {
514recommendations.push('- Consider using a faster OpenAI model or reducing prompt complexity');
515}
516
522}
523524private generatePromptOptimizationRecommendations(openaiData: any): string {
525if (!openaiData?.requests?.length) {
526return '- No OpenAI requests to analyze';
527}
528529const recommendations = [];
530const avgPromptLength = openaiData.requests.reduce((sum: number, req: any) => sum + (req.promptLength || 0), 0) / openaiData.requests.length;
531const avgResponseTime = openaiData.responses?.reduce((sum: number, res: any) => sum + (res.executionTime || 0), 0) / (openaiData.responses?.length || 1);
532const parseSuccessRate = (openaiData.responses?.filter((r: any) => r.parsedSuccessfully).length || 0) / (openaiData.responses?.length || 1);
533534if (avgPromptLength > 8000) {
Louai_performance_openai_client.ts53 matches
1// Lou Fantasy Baseball OpenAI AI Analysis Client
2// Robust OpenAI API integration for fantasy baseball performance analysis
3// Val.town Compatible TypeScript Implementation
478// ============================================================================
9// OPENAI CLIENT INTERFACES
10// ============================================================================
1112/**
13* AI Performance Analysis Response Interface
14* Structured output from OpenAI analysis of fantasy baseball performance
15*/
16export interface AIPerformanceAnalysis {
9091/**
92* OpenAI API Configuration Interface
93*/
94export interface OpenAIConfig {
95apiKey: string;
96model: string;
102103/**
104* OpenAI API Error Interface
105*/
106export interface OpenAIError {
107type: 'RATE_LIMIT' | 'API_ERROR' | 'TIMEOUT' | 'PARSE_ERROR' | 'AUTH_ERROR' | 'UNKNOWN';
108message: string;
113114// ============================================================================
115// OPENAI CLIENT IMPLEMENTATION
116// ============================================================================
117118/**
119* Lou OpenAI Client - Robust AI Analysis for Fantasy Baseball
120*
121* Features:
126* - Val.town optimized implementation
127*/
128export class LouOpenAIClient {
129private config: OpenAIConfig;
130private requestQueue: Array<() => Promise<any>> = [];
131private isProcessingQueue: boolean = false;
133private readonly MIN_REQUEST_INTERVAL = 1000; // 1 second between requests
134135constructor(config?: Partial<OpenAIConfig>) {
136this.config = {
137apiKey: config?.apiKey || process.env.OPENAI_API_KEY || '',
138model: config?.model || process.env.OPENAI_MODEL || 'o4-mini',
139maxTokens: config?.maxTokens || 2000,
140temperature: config?.temperature || 0.7,
144145if (!this.config.apiKey) {
146console.error('❌ OpenAI API key not provided. Set OPENAI_API_KEY environment variable.');
147}
148149console.log(`🤖 Lou OpenAI Client initialized with model: ${this.config.model}`);
150}
151180181// Log the request
182aiLogger.logOpenAiRequest(this.config.model, prompt, this.config);
183184// Execute OpenAI request with retry logic
185const response = await this.executeWithRetry(async () => {
186return await this.makeOpenAIRequest(prompt, 'performance_analysis');
187});
188242243// Log the request
244aiLogger.logOpenAiRequest(this.config.model, prompt, this.config);
245246// Execute OpenAI request
247const response = await this.executeWithRetry(async () => {
248return await this.makeOpenAIRequest(prompt, 'waiver_recommendations');
249});
250271272/**
273* Execute OpenAI API request with comprehensive retry logic
274*/
275private async executeWithRetry<T>(operation: () => Promise<T>): Promise<T | null> {
307308/**
309* Make OpenAI API request with proper error handling
310*/
311private async makeOpenAIRequest(prompt: string, requestType: string): Promise<string | null> {
312const startTime = Date.now();
313
314try {
315console.log(`🤖 Making OpenAI request: ${requestType}`);
316317// Validate API key
318if (!this.config.apiKey) {
319throw new Error('OpenAI API key not configured');
320}
321342const timeoutId = setTimeout(() => controller.abort(), this.config.requestTimeout);
343344const response = await fetch('https://api.openai.com/v1/chat/completions', {
345method: 'POST',
346headers: {
357if (!response.ok) {
358const errorText = await response.text();
359throw this.createOpenAIError(response.status, errorText);
360}
361365366if (!content) {
367throw new Error('Empty response from OpenAI API');
368}
369370const duration = Date.now() - startTime;
371console.log(`✅ OpenAI request completed in ${duration}ms`);
372373// Log the response
374aiLogger.logOpenAiResponse(this.config.model, content, duration, data.usage?.total_tokens);
375376return content;
380
381if (error.name === 'AbortError') {
382console.error(`⏰ OpenAI request timeout after ${duration}ms`);
383throw this.createOpenAIError(408, 'Request timeout');
384}
385386console.error(`❌ OpenAI request failed after ${duration}ms:`, error);
387throw error;
388}
793794/**
795* Create standardized OpenAI error
796*/
797private createOpenAIError(statusCode: number, message: string): OpenAIError {
798let type: OpenAIError['type'] = 'UNKNOWN';
799
800if (statusCode === 401) type = 'AUTH_ERROR';
819820/**
821* Validate OpenAI configuration
822*/
823public validateConfig(): { valid: boolean; errors: string[] } {
825826if (!this.config.apiKey) {
827errors.push('OpenAI API key is required');
828}
829830if (!this.config.model) {
831errors.push('OpenAI model is required');
832}
833849* Get current configuration (without API key)
850*/
851public getConfig(): Omit<OpenAIConfig, 'apiKey'> {
852const { apiKey, ...configWithoutKey } = this.config;
853return configWithoutKey;
855856/**
857* Test OpenAI API connection
858*/
859async testConnection(): Promise<{ success: boolean; error?: string; model?: string }> {
860try {
861console.log('🧪 Testing OpenAI API connection...');
862
863const response = await this.makeOpenAIRequest(
864'Please respond with a simple JSON object: {"status": "connected", "message": "API test successful"}',
865'connection_test'
872const parsed = JSON.parse(response);
873if (parsed.status === 'connected') {
874console.log('✅ OpenAI API connection successful');
875return { success: true, model: this.config.model };
876}
879880} catch (error) {
881console.error('❌ OpenAI API connection test failed:', error);
882return {
883success: false,
893894/**
895* Create a configured LouOpenAIClient instance
896* @param config Optional configuration overrides
897* @returns Configured OpenAI client
898*/
899export function createOpenAIClient(config?: Partial<OpenAIConfig>): LouOpenAIClient {
900return new LouOpenAIClient(config);
901}
902906907/**
908* Validate performance data before sending to OpenAI
909* @param data Performance data to validate
910* @returns Validation result
Louai_performance_orchestrator.ts6 matches
8import { LouPerformanceAnalyzer, PerformanceAnalysisReport } from "./ai_performance_yahoo_integration.ts";
9import {
10LouOpenAIClient,
11createOpenAIClient,
12AIPerformanceAnalysis,
13WaiverRecommendation
14} from "./ai_performance_openai_client.ts";
15import { LouTokenStorage } from "../oauth/token_storage.tsx";
16import {
89
90const performanceAnalyzer = new LouPerformanceAnalyzer();
91const openaiClient = createOpenAIClient({
92model: 'gpt-4o-mini', // More reliable than o4-mini
93maxTokens: 1500, // Reduce tokens for speed
123try {
124// Run team analysis first (faster, more important)
125aiAnalysis = await openaiClient.analyzeTeamPerformance({
126teamStats: performanceReport.team_analysis.overall_performance,
127playerStats: performanceReport.player_insights.top_performers.concat(performanceReport.player_insights.underperformers).slice(0, 8), // Limit players
143const topCandidates = availableWaiverPlayers.slice(0, 6); // Limit to 6 candidates
144
145waiverRecommendations = await openaiClient.getPickupRecommendations(
146performanceReport.player_insights.underperformers.slice(0, 4), // Top 4 underperformers
147topCandidates
blockFreeEmailActionCLAUDE.md4 matches
88Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
8990### OpenAI
9192```ts
93import { OpenAI } from "https://esm.town/v/std/openai";
94const openai = new OpenAI();
95const completion = await openai.chat.completions.create({
96messages: [
97{ role: "user", content: "Say hello in a creative way" },
atproto-to-fediverse-testval-town.md4 matches
95_2 or_3) to create a fresh table.
9697### OpenAI
9899```ts
100import { OpenAI } from "https://esm.town/v/std/openai";
101const openai = new OpenAI();
102const completion = await openai.chat.completions.create({
103messages: [
104{ role: "user", content: "Say hello in a creative way" },
AICompletetest.ts2 matches
1import OpenAI from "npm:openai";
2const client = new OpenAI();
34const response = await client.responses.create({
blockGmailActionCLAUDE.md4 matches
88Note: When changing a SQLite table's schema, change the table's name (e.g., add _2 or _3) to create a fresh table.
8990### OpenAI
9192```ts
93import { OpenAI } from "https://esm.town/v/std/openai";
94const openai = new OpenAI();
95const completion = await openai.chat.completions.create({
96messages: [
97{ role: "user", content: "Say hello in a creative way" },
58}))
5960const { categorizeIssues: categorizeWithAI } = await import('./openai.ts')
61return categorizeWithAI(processedIssues)
62}
analyze-github-issuesREADME.md2 matches
112. **Environment Variables** (left sidebar)
12```bash
13OPENAI_API_KEY=your_openai_api_key_here
14```
1516## Customization
1718Edit the system prompt in `openai.ts` to change how issues are categorized.
1920## Output
analyze-github-issuesopenai.ts7 matches
1import OpenAI from 'npm:openai'
23const openai = new OpenAI({
4apiKey: Deno.env.get('OPENAI_API_KEY')
5})
67export async function categorizeIssues(issues: any[]) {
8const completion = await openai.chat.completions.create({
9model: "gpt-4o-mini",
10messages: [{ role: "user", content: `Analyze these GitHub issues and categorize them into a two-level system:
3637const aiResponse = completion.choices[0].message.content
38if (!aiResponse) throw new Error('OpenAI returned empty response')
39
40try {
41return JSON.parse(aiResponse)
42} catch (error) {
43console.error('Failed to parse OpenAI response:', aiResponse.substring(0, 1000) + '...')
44
45// Try to repair truncated JSON by finding the last complete array
49return JSON.parse(repairedResponse)
50} catch (repairError) {
51throw new Error(`Invalid JSON response from OpenAI: ${error.message}`)
52}
53}