UNPKG

gemini-ai-sdk

Version:
336 lines (333 loc) 10.2 kB
var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/index.ts import { GoogleGenerativeAI } from "@google/generative-ai"; import { fileTypeFromBuffer } from "file-type"; import mime from "mime-lite"; // src/constants.ts var constants_exports = {}; __export(constants_exports, { defaultTools: () => defaultTools, safetyDisabledSettings: () => safetyDisabledSettings }); import { HarmCategory, HarmBlockThreshold, DynamicRetrievalMode } from "@google/generative-ai"; var safetyDisabledSettings = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }, { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE } ]; var defaultTools = { webSearch: { googleSearchRetrieval: { dynamicRetrievalConfig: { mode: DynamicRetrievalMode.MODE_DYNAMIC, dynamicThreshold: 0.7 } } }, codeExecution: { codeExecution: {} } }; // src/index.ts function isFileUpload(data) { return data && data.buffer && data.filePath; } var supportedFileFormats = [ "image/png", "image/jpeg", "image/webp", "image/heic", "image/heif", "audio/wav", "audio/mp3", "audio/mpeg", "audio/aiff", "audio/aac", "audio/ogg", "audio/flac", "video/mp4", "video/mpeg", "video/mov", "video/avi", "video/x-flv", "video/mpg", "video/webm", "video/wmv", "video/3gpp", "text/plain", "text/html", "text/css", "text/javascript", "application/x-javascript", "text/x-typescript", "application/x-typescript", "text/csv", "text/markdown", "text/x-python", "application/x-python-code", "application/json", "text/xml", "application/rtf", "text/rtf", "application/pdf" ]; var formatMap = { "audio/mpeg": "audio/mp3", "video/quicktime": "video/mov" }; var getFileType = async (buffer, filePath = void 0, { strict = false } = {}) => { const fileType = await fileTypeFromBuffer(buffer); let format = formatMap[fileType == null ? void 0 : fileType.mime] || (fileType == null ? void 0 : fileType.mime); let valid = supportedFileFormats.includes(format); if (!valid && filePath) { format = mime.getType(filePath); format = formatMap[format] || format; valid = supportedFileFormats.includes(format); } if (!valid) { if (strict) { throw new Error( "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" ); } else { format = "text/plain"; } } return format; }; var Chat = class { /** * Creates a new Chat instance. * @param gemini - The Gemini instance to use. * @param options - Optional parameters for the chat. */ constructor(gemini, options = {}) { this.gemini = gemini; this.history = options.history || []; this.options = options; } /** * Appends a message to the chat history. * @param message - The message to append. */ appendMessage(message) { this.history.push(message); } /** * Sends a message to Gemini and returns the response. * @param message - The message to send. * @param options - Optional parameters for the request. * @returns The response from Gemini. If options.stream = false, returns a single object. * Otherwise, returns an AsyncGenerator of results. */ async ask(message, options = {}) { const mergedOptions = __spreadValues(__spreadValues({}, this.options), options); return this.gemini.ask(message, __spreadValues({ history: this.history }, mergedOptions)); } }; var Gemini = class { /** * Creates a new Gemini instance. * @param apiKey - Your API key for the Gemini API. * @param options - Optional parameters for initializing the instance. */ constructor(apiKey, options = {}) { this.genAI = new GoogleGenerativeAI(apiKey); this.options = __spreadValues({ apiVersion: "v1beta" }, options); } /** * Uploads a file to the Gemini API. * @param options - Options for the file upload. * @returns The URI of the uploaded file. */ async uploadFile({ file, mimeType }) { const gemini = this.genAI; function generateBoundary() { let str = ""; for (let i = 0; i < 2; i++) { str = str + Math.random().toString().slice(2); } return str; } const boundary = generateBoundary(); const apiVersion = this.options.apiVersion; const apiKey = gemini.apiKey; const generateBlob = (boundary2, file2, mime2) => new Blob([ `--${boundary2}\r Content-Type: application/json; charset=utf-8\r \r ${JSON.stringify({ file: { mimeType: mime2 } })}\r --${boundary2}\r Content-Type: ${mime2}\r \r `, file2, `\r --${boundary2}--` ]); const fileSendDataRaw = await fetch( `https://generativelanguage.googleapis.com/upload/${apiVersion}/files?key=${apiKey}`, { method: "POST", headers: { "Content-Type": `multipart/related; boundary=${boundary}`, "X-Goog-Upload-Protocol": "multipart" }, body: generateBlob(boundary, file, mimeType) } ).then((res) => res.json()); const fileSendData = fileSendDataRaw.file; let waitTime = 250; const MAX_BACKOFF = 5e3; while (true) { try { const url = `https://generativelanguage.googleapis.com/${apiVersion}/${fileSendData.name}?key=${apiKey}`; const response = await fetch(url, { method: "GET" }); const data = await response.json(); if (data.error) { throw new Error(`Google's File API responded with an error: ${data.error.message}`); } if (data.state === "ACTIVE") break; await new Promise((resolve) => setTimeout(resolve, waitTime)); waitTime = Math.min(waitTime * 1.5, MAX_BACKOFF); } catch (error) { throw new Error(`An error occurred while uploading to Google's File API: ${error.message}`); } } return fileSendData.uri; } /** * Converts a list of messages or files to Gemini API parts. * @param messages - The messages or files to convert. * @returns An array of Gemini API parts. */ async messageToParts(messages) { const parts = []; let totalBytes = 0; for (const msg of messages) { if (typeof msg === "string") { parts.push({ text: msg }); } else if (msg instanceof ArrayBuffer || msg instanceof Uint8Array || isFileUpload(msg)) { const is_file_upload = isFileUpload(msg); const buffer = is_file_upload ? msg.buffer : msg; const filePath = is_file_upload ? msg.filePath : void 0; totalBytes += Buffer.from(buffer).byteLength; const mimeType = await getFileType(buffer, filePath); if (!mimeType.startsWith("video")) { const part = { inlineData: { mimeType, data: Buffer.from(buffer).toString("base64") } }; parts.push(part); } else { const fileURI = await this.uploadFile({ file: buffer, mimeType }); const part = { fileData: { mimeType, fileUri: fileURI } }; parts.push(part); } } } if (totalBytes > 20 * 1024 * 1024) { for (const idx in parts) { const part = parts[idx]; if (part.inlineData) { const fileURI = await this.uploadFile({ file: Buffer.from(part.inlineData.data, "base64"), mimeType: part.inlineData.mimeType }); const newPart = { fileData: { mimeType: part.inlineData.mimeType, fileUri: fileURI } }; parts[idx] = newPart; } } } return parts; } /** * Sends a request to the Gemini API and returns the response. * @param message - The message to send. * @param options - Optional parameters for the request. * @returns The response from the Gemini API. If options.stream = false, returns a single object. * Otherwise, returns an AsyncGenerator of results. */ async ask(message, options = {}) { const model = this.genAI.getGenerativeModel( { model: options.model, tools: options.tools }, { apiVersion: this.options.apiVersion } ); const parts = typeof message === "string" ? [{ text: message }] : message; const { generationConfig, safetySettings, systemInstruction, history } = options; const chat = model.startChat({ history: history || [], generationConfig, safetySettings, systemInstruction }); if (options.stream) { return chat.sendMessageStream(parts); } else { return chat.sendMessage(parts); } } /** * Creates a new chat session. * @param options - Optional parameters for the chat. * @returns A new Chat instance. */ createChat(options = {}) { return new Chat(this, options); } }; var index_default = Gemini; export { Chat, Gemini, constants_exports as constants, index_default as default, getFileType, isFileUpload }; //# sourceMappingURL=index.mjs.map