UNPKG

gemini-ai-sdk

Version:
1 lines 17.6 kB
{"version":3,"sources":["../src/index.ts","../src/constants.ts"],"sourcesContent":["import {\n GenerateContentResult,\n GenerateContentStreamResult,\n GenerationConfig,\n GoogleGenerativeAI,\n HarmBlockThreshold,\n HarmCategory,\n Part,\n SafetySetting,\n Content,\n FileDataPart,\n InlineDataPart,\n Tool,\n} from \"@google/generative-ai\";\n\nimport { FileTypeResult, fileTypeFromBuffer } from \"file-type\";\nimport mime from \"mime-lite\";\n\n/**\n * Represents a file to be uploaded.\n */\nexport type FileUpload = { buffer: ArrayBuffer; filePath: string };\n\n/**\n * Checks if the given data is a FileUpload object.\n * @param data - The data to check.\n * @returns True if the data is a FileUpload, false otherwise.\n */\nexport function isFileUpload(data: any): data is FileUpload {\n return data && data.buffer && data.filePath;\n}\n\n/**\n * Supported file formats for Gemini.\n */\nconst supportedFileFormats = [\n \"image/png\",\n \"image/jpeg\",\n \"image/webp\",\n \"image/heic\",\n \"image/heif\",\n \"audio/wav\",\n \"audio/mp3\",\n \"audio/mpeg\",\n \"audio/aiff\",\n \"audio/aac\",\n \"audio/ogg\",\n \"audio/flac\",\n \"video/mp4\",\n \"video/mpeg\",\n \"video/mov\",\n \"video/avi\",\n \"video/x-flv\",\n \"video/mpg\",\n \"video/webm\",\n \"video/wmv\",\n \"video/3gpp\",\n \"text/plain\",\n \"text/html\",\n \"text/css\",\n \"text/javascript\",\n \"application/x-javascript\",\n \"text/x-typescript\",\n \"application/x-typescript\",\n \"text/csv\",\n \"text/markdown\",\n \"text/x-python\",\n \"application/x-python-code\",\n \"application/json\",\n \"text/xml\",\n \"application/rtf\",\n \"text/rtf\",\n \"application/pdf\",\n];\n\n/**\n * Maps some file types to others for compatibility.\n */\nconst formatMap: { [key: string]: string } = {\n \"audio/mpeg\": \"audio/mp3\",\n \"video/quicktime\": \"video/mov\",\n};\n\n/**\n * Determines the file type of a buffer.\n * @param buffer - The buffer to analyze.\n * @param filePath - Optional file path for fallback.\n * @param options - Options for strict checking.\n * @returns The detected file type.\n */\nexport const getFileType = async (\n buffer: Uint8Array | ArrayBuffer,\n filePath: string | undefined = undefined,\n { strict = false } = {},\n): Promise<string> => {\n const fileType: FileTypeResult | undefined = await fileTypeFromBuffer(buffer);\n\n let format = formatMap[fileType?.mime as string] || fileType?.mime;\n let valid = supportedFileFormats.includes(format);\n\n if (!valid && filePath) {\n format = mime.getType(filePath);\n format = formatMap[format] || format;\n valid = supportedFileFormats.includes(format);\n }\n\n if (!valid) {\n if (strict) {\n throw new Error(\n \"Please provide a valid file format that is accepted by Gemini. Learn more about valid formats here: https://ai.google.dev/gemini-api/docs/prompting_with_media?lang=node#supported_file_formats\",\n );\n } else {\n format = \"text/plain\";\n }\n }\n\n return format;\n};\n\n/**\n * Options for initializing a Gemini instance.\n */\nexport interface GeminiOptions {\n apiVersion?: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Options for the `ask` method, as well as the `Chat` class.\n */\nexport interface AskOptions {\n stream?: boolean;\n model?: string;\n history?: Content[];\n generationConfig?: GenerationConfig;\n safetySettings?: SafetySetting[];\n systemInstruction?: Content;\n tools?: Tool[];\n}\n\n/**\n * Types for various methods.\n */\nexport type GenerateResult = GenerateContentResult | GenerateContentStreamResult;\n\n/**\n * Represents a chat session with Gemini.\n */\nexport class Chat {\n private gemini: Gemini;\n private history: Content[];\n private options: AskOptions;\n\n /**\n * Creates a new Chat instance.\n * @param gemini - The Gemini instance to use.\n * @param options - Optional parameters for the chat.\n */\n constructor(gemini: Gemini, options: Partial<AskOptions> = {}) {\n this.gemini = gemini;\n this.history = options.history || [];\n this.options = options;\n }\n\n /**\n * Appends a message to the chat history.\n * @param message - The message to append.\n */\n public appendMessage(message: Content) {\n this.history.push(message);\n }\n\n /**\n * Sends a message to Gemini and returns the response.\n * @param message - The message to send.\n * @param options - Optional parameters for the request.\n * @returns The response from Gemini. If options.stream = false, returns a single object.\n * Otherwise, returns an AsyncGenerator of results.\n */\n public async ask(message: string | Part[], options: Partial<AskOptions> = {}): Promise<GenerateResult> {\n const mergedOptions = { ...this.options, ...options };\n return this.gemini.ask(message, {\n history: this.history,\n ...mergedOptions,\n });\n }\n}\n\n/**\n * Main class for interacting with the Gemini API.\n */\nexport class Gemini {\n private genAI: GoogleGenerativeAI;\n private options: GeminiOptions;\n\n /**\n * Creates a new Gemini instance.\n * @param apiKey - Your API key for the Gemini API.\n * @param options - Optional parameters for initializing the instance.\n */\n constructor(apiKey: string, options: Partial<GeminiOptions> = {}) {\n this.genAI = new GoogleGenerativeAI(apiKey);\n this.options = {\n apiVersion: \"v1beta\",\n ...options,\n };\n }\n\n /**\n * Uploads a file to the Gemini API.\n * @param options - Options for the file upload.\n * @returns The URI of the uploaded file.\n */\n private async uploadFile({ file, mimeType }: { file: Uint8Array | ArrayBuffer; mimeType: string }): Promise<string> {\n const gemini = this.genAI;\n\n function generateBoundary(): string {\n let str = \"\";\n for (let i = 0; i < 2; i++) {\n str = str + Math.random().toString().slice(2);\n }\n return str;\n }\n\n const boundary = generateBoundary();\n const apiVersion = this.options.apiVersion;\n const apiKey = gemini.apiKey;\n\n const generateBlob = (boundary: string, file: Uint8Array | ArrayBuffer, mime: string): Blob =>\n new Blob([\n `--${boundary}\\r\\nContent-Type: application/json; charset=utf-8\\r\\n\\r\\n${JSON.stringify({\n file: {\n mimeType: mime,\n },\n })}\\r\\n--${boundary}\\r\\nContent-Type: ${mime}\\r\\n\\r\\n`,\n file,\n `\\r\\n--${boundary}--`,\n ]);\n\n const fileSendDataRaw = await fetch(\n `https://generativelanguage.googleapis.com/upload/${apiVersion}/files?key=${apiKey}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": `multipart/related; boundary=${boundary}`,\n \"X-Goog-Upload-Protocol\": \"multipart\",\n },\n body: generateBlob(boundary, file, mimeType),\n },\n ).then((res: Response) => res.json());\n\n const fileSendData = fileSendDataRaw.file;\n\n let waitTime = 250; // Initial wait time in milliseconds\n const MAX_BACKOFF = 5000; // Maximum backoff time in milliseconds\n\n // Keep polling until the file state is \"ACTIVE\"\n while (true) {\n try {\n const url = `https://generativelanguage.googleapis.com/${apiVersion}/${fileSendData.name}?key=${apiKey}`;\n\n const response = await fetch(url, { method: \"GET\" });\n const data = await response.json();\n\n if (data.error) {\n throw new Error(`Google's File API responded with an error: ${data.error.message}`);\n }\n\n if (data.state === \"ACTIVE\") break;\n\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n\n waitTime = Math.min(waitTime * 1.5, MAX_BACKOFF);\n } catch (error) {\n throw new Error(`An error occurred while uploading to Google's File API: ${error.message}`);\n }\n }\n\n return fileSendData.uri;\n }\n\n /**\n * Converts a list of messages or files to Gemini API parts.\n * @param messages - The messages or files to convert.\n * @returns An array of Gemini API parts.\n */\n public async messageToParts(messages: (string | Uint8Array | ArrayBuffer | FileUpload)[]): Promise<Part[]> {\n const parts: Part[] = [];\n let totalBytes = 0;\n\n for (const msg of messages) {\n if (typeof msg === \"string\") {\n parts.push({ text: msg });\n } else if (msg instanceof ArrayBuffer || msg instanceof Uint8Array || isFileUpload(msg)) {\n const is_file_upload = isFileUpload(msg);\n const buffer = is_file_upload ? msg.buffer : msg;\n const filePath = is_file_upload ? msg.filePath : undefined;\n\n totalBytes += Buffer.from(buffer).byteLength;\n const mimeType = await getFileType(buffer, filePath);\n\n if (!mimeType.startsWith(\"video\")) {\n const part: InlineDataPart = {\n inlineData: {\n mimeType: mimeType,\n data: Buffer.from(buffer).toString(\"base64\"),\n },\n };\n parts.push(part);\n } else {\n const fileURI = await this.uploadFile({\n file: buffer,\n mimeType: mimeType,\n });\n\n const part: FileDataPart = {\n fileData: {\n mimeType: mimeType,\n fileUri: fileURI,\n },\n };\n parts.push(part);\n }\n }\n }\n\n if (totalBytes > 20 * 1024 * 1024) {\n for (const idx in parts) {\n const part = parts[idx];\n if (part.inlineData) {\n const fileURI = await this.uploadFile({\n file: Buffer.from(part.inlineData.data, \"base64\"),\n mimeType: part.inlineData.mimeType,\n });\n const newPart: FileDataPart = {\n fileData: {\n mimeType: part.inlineData.mimeType,\n fileUri: fileURI,\n },\n };\n parts[idx] = newPart;\n }\n }\n }\n\n return parts;\n }\n\n /**\n * Sends a request to the Gemini API and returns the response.\n * @param message - The message to send.\n * @param options - Optional parameters for the request.\n * @returns The response from the Gemini API. If options.stream = false, returns a single object.\n * Otherwise, returns an AsyncGenerator of results.\n */\n public async ask(message: string | Part[], options: Partial<AskOptions> = {}): Promise<GenerateResult> {\n const model = this.genAI.getGenerativeModel(\n { model: options.model, tools: options.tools },\n { apiVersion: this.options.apiVersion },\n );\n const parts = typeof message === \"string\" ? [{ text: message }] : message;\n\n const { generationConfig, safetySettings, systemInstruction, history } = options;\n\n const chat = model.startChat({\n history: history || [],\n generationConfig,\n safetySettings,\n systemInstruction,\n });\n\n if (options.stream) {\n return chat.sendMessageStream(parts);\n } else {\n return chat.sendMessage(parts);\n }\n }\n\n /**\n * Creates a new chat session.\n * @param options - Optional parameters for the chat.\n * @returns A new Chat instance.\n */\n public createChat(options: Partial<AskOptions> = {}): Chat {\n return new Chat(this, options);\n }\n}\n\nexport default Gemini;\n\n// export constants\nimport * as constants from \"./constants\";\nexport { constants };\n","import { HarmCategory, HarmBlockThreshold, DynamicRetrievalMode } from \"@google/generative-ai\";\n\nexport const safetyDisabledSettings = [\n { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },\n { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },\n { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE },\n { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },\n];\n\nexport const defaultTools = {\n webSearch: {\n googleSearchRetrieval: {\n dynamicRetrievalConfig: {\n mode: DynamicRetrievalMode.MODE_DYNAMIC,\n dynamicThreshold: 0.7,\n },\n },\n },\n codeExecution: {\n codeExecution: {},\n },\n};\n"],"mappings":"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","names":["boundary","file","mime"]}