game-advisor/src/index.ts (91 lines of code) (raw):

// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import * as z from 'zod'; // Import the Genkit core libraries and plugins. import { configureGenkit } from '@genkit-ai/core'; import { defineFlow, startFlowsServer } from '@genkit-ai/flow'; import { vertexAI } from '@genkit-ai/vertexai'; import { ollama } from 'genkitx-ollama' import { dotprompt, promptRef } from '@genkit-ai/dotprompt'; import { initializeApp, applicationDefault } from 'firebase-admin/app'; import { getFirestore, FieldValue } from 'firebase-admin/firestore'; import { getFirestore, FieldValue } from 'firebase-admin/firestore'; const OLLAMA_ADDRESS = process.env.OLLAMA_ADDRESS || 'http://localhost:8080'; initializeApp({ credential: applicationDefault() }); const db = getFirestore(); configureGenkit({ plugins: [ vertexAI({ location: 'us-west4' }), ollama({ models: [ { name: 'llama3.1:70b', type: 'generate', }, ], serverAddress: OLLAMA_ADDRESS }), dotprompt() ], // Log debug output to tbe console. logLevel: 'debug', // Perform OpenTelemetry instrumentation and enable trace collection. enableTracingAndMetrics: true, }); const gameSummaryOutputSchema = z.object({ headline: z.string(), analysis: z.string(), tips: z.array(z.string()), grade: z.string(), }); export const gameSummaryFlow = defineFlow( { name: 'gameSummaryFlow', inputSchema: z.string(), outputSchema: gameSummaryOutputSchema }, async (gameId) => { for (let retries = 0; retries < 5; retries += 1) { try { const snapshot = await db.collection('AllGameEvents') .where('GameId', '==', gameId) .get(); let content = ""; snapshot.forEach(doc => { const eventData = doc.data(); let line = `PinballEventType:${eventData.PinballEventType} `; // Add data fields from eventData.data if (eventData.data) { for (const [key, value] of Object.entries(eventData.data)) { line += `${key}:${value} `; } } content += line.trim() + "\n"; }); // Construct a request and send it to the model API. const prompt = promptRef("summary"); const resp = await prompt.generate({ input: { gameLog: content } }); // console.log(resp.output()) // Store the analysis in Firestore const analysis = resp.output(); const gameAnalysesRef = db.collection('GameAnalyses').doc(gameId); await gameAnalysesRef.set({ ...analysis, insertionTimestamp: FieldValue.serverTimestamp() // Add timestamp }); return analysis; } catch (error) { console.error('Error fetching events:', error); console.log('On retry #', retries); } } // Construct a request and send it to the model API. const prompt = promptRef("summary"); const resp = await prompt.generate({ input: { gameLog: content } }); // console.log(resp.output()) // Store the analysis in Firestore const analysis = resp.output(); const gameAnalysesRef = db.collection('GameAnalyses').doc(gameId); await gameAnalysesRef.set({ ...analysis, insertionTimestamp: FieldValue.serverTimestamp() // Add timestamp }); return analysis; } catch (error) { console.error('Error fetching events:', error); console.log('On retry #', retries); } } } ) // Start a flow server, which exposes your flows as HTTP endpoints. This call // must come last, after all of your plug-in configuration and flow definitions. // You can optionally specify a subset of flows to serve, and configure some // HTTP server options, but by default, the flow server serves all defined flows. startFlowsServer();