Feat/ai samples multimodal - #1073
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new set of Firebase AI samples demonstrating capabilities like text generation, multi-turn chat, and multimodal input. Key feedback focuses on fixing critical issues, including replacing the non-existent model name 'gemini-3.5-flash' with 'gemini-1.5-flash' across multiple services, and resolving a security vulnerability where the App Check debug token was hardcoded to true. Additionally, recommendations were made to uncomment and correctly export the local Firebase configuration, use ReCaptchaV3Provider to align with the documentation, improve type safety in file parsing, and wrap React handlers in useCallback to satisfy hook dependency rules.
I am having trouble creating individual review comments. Click here to see my feedback.
ai/ai-samples/src/config/firebase-config.ts (1-7)
Uncomment and export the firebaseConfig object so that it can be imported and used by firebaseAIService.ts. This aligns the code with the setup instructions in the README.
export const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};
ai/ai-samples/src/services/firebaseAIService.ts (1-4)
Import ReCaptchaV3Provider instead of ReCaptchaEnterpriseProvider to match the README instructions (which specify reCAPTCHA v3). Also, import firebaseConfig from the configuration file to support local configuration.
import { initializeApp } from 'firebase/app';
import { getAI, getGenerativeModel } from 'firebase/ai';
import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check';
import { firebaseConfig as localConfig } from '../config/firebase-config';
ai/ai-samples/src/services/firebaseAIService.ts (6-15)
Use the imported localConfig as the fallback when VITE_FIREBASE_CONFIG is not set. This ensures that the configuration changes made by users in src/config/firebase-config.ts (as instructed by the README) are actually used by the application.
const firebaseConfig = import.meta.env.VITE_FIREBASE_CONFIG
? JSON.parse(import.meta.env.VITE_FIREBASE_CONFIG)
: localConfig;ai/ai-samples/src/services/firebaseAIService.ts (19-30)
Only enable the App Check debug token if VITE_APPCHECK_DEBUG_TOKEN is explicitly set to 'true' in the environment. Hardcoding it to true exposes production environments to App Check bypasses. Also, use ReCaptchaV3Provider to match the README instructions.
// initialize app check with debug token
if (typeof window !== 'undefined') {
if (import.meta.env.VITE_APPCHECK_DEBUG_TOKEN === 'true') {
(window as any).FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}
initializeAppCheck(app, {
// The string here doesn't matter in this specific case, as setting
// FIREBASE_APPCHECK_DEBUG_TOKEN above means it will be ignored.
// However, in production, this MUST be a valid reCAPTCHA site key.
provider: new ReCaptchaV3Provider('YOUR_RECAPTCHA_SITE_KEY'),
isTokenAutoRefreshEnabled: true
});
}
ai/ai-samples/src/services/firebaseAIService.ts (34)
The model name 'gemini-3.5-flash' does not exist. Change the default model to 'gemini-1.5-flash' to prevent API errors when running the samples.
export const getAiModel = (modelName: string = 'gemini-1.5-flash', additionalConfig: Record<string, any> = {}) => {
ai/ai-samples/src/features/chat/service.ts (11)
Change the model name from 'gemini-3.5-flash' to 'gemini-1.5-flash' as 'gemini-3.5-flash' is not a valid model name and will cause API errors.
const model = getAiModel('gemini-1.5-flash');
ai/ai-samples/src/features/multimodal/service.ts (41)
Change the model name from 'gemini-3.5-flash' to 'gemini-1.5-flash' as 'gemini-3.5-flash' is not a valid model name and will cause API errors.
const model = getAiModel('gemini-1.5-flash');
ai/ai-samples/src/features/text-generation/service.ts (10)
Change the model name from 'gemini-3.5-flash' to 'gemini-1.5-flash' as 'gemini-3.5-flash' is not a valid model name and will cause API errors.
const model = getAiModel('gemini-1.5-flash');
ai/ai-samples/src/features/text-generation/service.ts (27)
Change the model name from 'gemini-3.5-flash' to 'gemini-1.5-flash' as 'gemini-3.5-flash' is not a valid model name and will cause API errors.
const model = getAiModel('gemini-1.5-flash');
ai/ai-samples/src/features/text-generation/service.ts (50)
Change the model name from 'gemini-3.5-flash' to 'gemini-1.5-flash' as 'gemini-3.5-flash' is not a valid model name and will cause API errors.
const model = getAiModel('gemini-1.5-flash', { systemInstruction });
ai/ai-samples/src/features/multimodal/service.ts (10-30)
Improve type safety and error handling in fileToGenerativePart. Checking if reader.result is a string and safely splitting it prevents potential runtime TypeErrors if the file reading fails or returns unexpected results.
export async function fileToGenerativePart(file: File): Promise<Part> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
const result = reader.result;
if (typeof result === 'string') {
const splitResult = result.split(',');
if (splitResult.length > 1) {
resolve({
inlineData: {
data: splitResult[1],
mimeType: file.type
}
});
return;
}
}
reject(new Error('Failed to parse file data as Base64.'));
};
reader.onerror = () => reject(reader.error || new Error('Error reading file.'));
// Trigger the file read
reader.readAsDataURL(file);
});
}ai/ai-samples/src/features/chat/index.tsx (1)
Import useCallback from 'react' to wrap the handleResetChat function and avoid React hook dependency warnings/unnecessary recreations.
import React, { useState, useRef, useEffect, useCallback } from 'react';
ai/ai-samples/src/features/chat/index.tsx (21-34)
Wrap handleResetChat in useCallback and add it to the dependency array of useEffect. This prevents the function from being recreated on every render and satisfies the React hooks dependency rules.
const handleResetChat = useCallback(() => {
try {
chatSessionRef.current = startNewChat();
setError(null);
} catch (err: any) {
setError(err.message || 'Failed to initialize chat session. Please check your Firebase configuration.');
}
setMessages([]);
setInput('');
}, []);
// Initialize the chat when the component mounts
useEffect(() => {
handleResetChat();
}, [handleResetChat]);
…able into array earlier
…ial Firebase SDK Documentation
-Multimodal sample:The user should be able to upload a pdf file/image and enter a prompt to receive a response in plain text.