@codixfy/gemini
Version:
An npm package for nodejs that makes easier working with Gemini AI API. Includes some useful methods solving common tasks, helping quick and stable development.
221 lines (218 loc) • 6.75 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Gemini: () => Gemini,
GeminiUtils: () => GeminiUtils
});
module.exports = __toCommonJS(index_exports);
// src/providers/gemini.ts
var {
GoogleGenerativeAI,
HarmBlockThreshold,
HarmCategory
} = require("@google/generative-ai");
var Base64 = require("base64-js");
var Gemini = class {
genAI;
model;
currentModel;
apiKey;
constructor(apiKey, options) {
var _a, _b, _c, _d;
this.genAI = new GoogleGenerativeAI(apiKey);
this.apiKey = apiKey;
this.currentModel = "gemini-1.5-flash";
if (options == null ? void 0 : options.model) {
this.currentModel = options.model;
if (this.currentModel === "gemini-2.0-flash") {
this.currentModel += "-exp";
}
if (this.currentModel === "gemini-2.0-flash" && !(options == null ? void 0 : options.useLatestModel)) {
this.currentModel += "-latest";
}
}
this.model = this.genAI.getGenerativeModel({
model: this.currentModel,
safetySettings: [
{
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold: ((_a = options == null ? void 0 : options.safetySettings) == null ? void 0 : _a.blockDangerousContent) === true ? HarmBlockThreshold.BLOCK_ONLY_HIGH : HarmBlockThreshold.BLOCK_NONE
},
{
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold: ((_b = options == null ? void 0 : options.safetySettings) == null ? void 0 : _b.blockExplicitContent) === true ? HarmBlockThreshold.BLOCK_ONLY_HIGH : HarmBlockThreshold.BLOCK_NONE
},
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: ((_c = options == null ? void 0 : options.safetySettings) == null ? void 0 : _c.blockHarassmentContent) === true ? HarmBlockThreshold.BLOCK_ONLY_HIGH : HarmBlockThreshold.BLOCK_NONE
},
{
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold: ((_d = options == null ? void 0 : options.safetySettings) == null ? void 0 : _d.blockHateContent) === true ? HarmBlockThreshold.BLOCK_ONLY_HIGH : HarmBlockThreshold.BLOCK_NONE
}
],
systemInstruction: (options == null ? void 0 : options.instructions) || void 0
});
}
// Used to send a message without any context
async ask(message, extra) {
const partsWithFiles = [];
if ((extra == null ? void 0 : extra.files) && extra.files.length > 0) {
if (this.currentModel === "gemini-pro-vision") {
throw new Error(
`This model does not support files. Current model: ${this.currentModel}`
);
}
for (const file of extra.files) {
partsWithFiles.push(
{
text: "Link: " + file
}
);
}
}
const contents = [
{
role: "user",
parts: [
{
text: message
},
...partsWithFiles
]
}
];
const result = await this.model.generateContentStream({ contents });
const buffer = [];
for await (const response of result.stream) {
buffer.push(response.text());
if (extra == null ? void 0 : extra.stream) {
extra.stream(response.text());
}
}
return buffer.join(" ");
}
createChat(chartContext) {
return new GeminiChat(
this.model,
chartContext === null ? [] : chartContext,
this.currentModel
);
}
};
var GeminiChat = class {
model;
chatContext;
currentModel;
constructor(model, chatContext, currentModel) {
this.model = model;
this.chatContext = chatContext;
this.currentModel = currentModel;
}
async send(message, extra) {
const partsWithFiles = [];
if ((extra == null ? void 0 : extra.files) && extra.files.length > 0) {
if (this.currentModel === "gemini-pro-vision") {
throw new Error(
`This model does not support images. Current model: ${this.currentModel}`
);
}
for (const file of extra.files) {
partsWithFiles.push(
{
text: "Link: " + file
}
);
}
}
if (!this.chatContext) {
this.chatContext = [];
}
this.chatContext.push({
role: "user",
parts: [
{
text: message
},
...partsWithFiles
]
});
const contents = this.chatContext;
const result = await this.model.generateContentStream({ contents });
const buffer = [];
for await (const response of result.stream) {
buffer.push(response.text());
if (extra == null ? void 0 : extra.stream) {
extra.stream(response.text());
}
}
return buffer.join(" ");
}
async reset() {
this.chatContext = [];
}
async save() {
return this.chatContext;
}
async load(context) {
this.chatContext = context;
}
};
var GeminiUtils = class {
static async fileToGenerativePart(file) {
const mimeType = await this.mimeTypeFromFile(file);
const image64 = await fetch(file).then((r) => r.arrayBuffer()).then((a) => Base64.fromByteArray(new Uint8Array(a)));
return {
inline_data: {
data: image64,
mime_type: mimeType
}
};
}
static async mimeTypeFromFile(file) {
const extension = file.split(".")[file.split(".").length - 1];
switch (extension) {
case "jpg":
case "jpeg":
return "image/jpeg";
case "png":
return "image/png";
case "gif":
return "image/gif";
case "webp":
return "image/webp";
case "mp4":
return "video/mp4";
case "wav":
return "audio/wav";
case "mp3":
return "audio/mp3";
case "aac":
return "audio/aac";
default:
throw new Error("Unsupported file type (${extension})");
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Gemini,
GeminiUtils
});