use the unofficial API for Google Gemini
Self-built from https://codeberg.org/buzzcode2007/GoogleGeminiAPI_Test/src/branch/js/gemini.js
This commit is contained in:
parent
dbb8b47b38
commit
8229db8a3a
1 changed files with 180 additions and 0 deletions
180
scripts/gemini.js
Normal file
180
scripts/gemini.js
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
|
||||||
|
// Import the file module.
|
||||||
|
// import file from `./net.js`;
|
||||||
|
|
||||||
|
export default class gemini {
|
||||||
|
#key;
|
||||||
|
#request;
|
||||||
|
|
||||||
|
/* Set the model to use.
|
||||||
|
|
||||||
|
@param {string} key the API key. Remember to not commit your API keys.
|
||||||
|
@param {string} model the model to use
|
||||||
|
*/
|
||||||
|
constructor (key, model) {
|
||||||
|
if ((key) ? (((typeof key).includes(`str`)) ? !(key.trim()) : true) : true) {
|
||||||
|
throw new Error(`The API key is required.`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register the API key privately.
|
||||||
|
this.#key = key.trim();
|
||||||
|
|
||||||
|
// Create the headers for future interaction.
|
||||||
|
this.#request = {}
|
||||||
|
this.#request[`headers`] = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-goog-api-key": this.#key
|
||||||
|
};
|
||||||
|
|
||||||
|
this.model = {};
|
||||||
|
// Set the model. If not provided, use the default of gemini-pro. Make sure to determine if "models/" was accidentally included, which is really part of the URL and not the model name itself.
|
||||||
|
this.model[`name`] = ((typeof model).includes(`str`) && model) ? ((model.includes(`models/`)) ? model : `models/`.concat(model)) : 'gemini-pro';
|
||||||
|
|
||||||
|
// Set the request location.
|
||||||
|
this.#request[`location`] = `https://generativelanguage.googleapis.com/v1beta/`.concat(this.model.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Ask Google Gemini.
|
||||||
|
|
||||||
|
@param {object} prompt the prompts; may accept a string to be converted to an object
|
||||||
|
@param {object} images the images
|
||||||
|
@param {boolean} continued whether to continue the existing prompt
|
||||||
|
*/
|
||||||
|
async generate(prompt, safetySettings, generationConfig, continued = false) {
|
||||||
|
let create = async () => {
|
||||||
|
let REQUEST = {}, PROMPT = [];
|
||||||
|
|
||||||
|
if (typeof(prompt) != `object`) {
|
||||||
|
PROMPT.push({"text": String(prompt)});
|
||||||
|
} else if (Array.isArray(prompt)) {
|
||||||
|
while (PROMPT.length < prompt.length) {
|
||||||
|
if ((typeof prompt[PROMPT.length]).includes(`obj`) && prompt[PROMPT.length] != null && !Array.isArray(prompt[PROMPT.length])) {
|
||||||
|
PROMPT.push(prompt[PROMPT.length]);
|
||||||
|
} else {
|
||||||
|
PROMPT.push({"text": prompt[PROMPT.length]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof prompt == `object` && prompt != null && !Array.isArray(prompt)) {
|
||||||
|
PROMPT.push(prompt);
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUEST[`contents`] = [];
|
||||||
|
|
||||||
|
// Function below by Google (https://ai.google.dev/tutorials/get_started_web)
|
||||||
|
async function fileToGenerativePart(file) {
|
||||||
|
if (typeof FileReader != 'undefined') {
|
||||||
|
const base64EncodedDataPromise = new Promise((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => resolve(reader.result.split(',')[1]);
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
inlineData: { data: await base64EncodedDataPromise, mimeType: file.type },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (REQUEST[`contents`].length < PROMPT.length) {
|
||||||
|
let MESSAGE = {};
|
||||||
|
|
||||||
|
|
||||||
|
// Add the role.
|
||||||
|
MESSAGE[`role`] = (PROMPT[REQUEST[`contents`].length][`role`]) ? PROMPT[REQUEST[`contents`].length][`role`] : `user`;
|
||||||
|
MESSAGE[`parts`] = [];
|
||||||
|
|
||||||
|
|
||||||
|
// Convert the photos to a list if it isn't set to be one.
|
||||||
|
if (PROMPT[REQUEST[`contents`].length][`images`] ? !Array.isArray(PROMPT[REQUEST[`contents`].length][`images`]) : false) {
|
||||||
|
PROMPT[REQUEST[`contents`].length][`images`] = [PROMPT[REQUEST[`contents`].length][`images`]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the photos.
|
||||||
|
while ((PROMPT[REQUEST[`contents`].length][`images`]) ? (MESSAGE[`parts`].length < PROMPT[REQUEST[`contents`].length][`images`].length) : false) {
|
||||||
|
let MESSAGE_IMAGE = await fileToGenerativePart(PROMPT[REQUEST[`contents`].length][`images`][MESSAGE[`parts`].length]);
|
||||||
|
if (MESSAGE_IMAGE) {
|
||||||
|
MESSAGE[`parts`].push();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the message.
|
||||||
|
MESSAGE[`parts`].unshift({"text": PROMPT[REQUEST[`contents`].length][`text`]});
|
||||||
|
|
||||||
|
// Add the message itself.
|
||||||
|
REQUEST[`contents`].push(MESSAGE);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the continuation.
|
||||||
|
if (continued && Object.keys(this).includes(`history`)) {
|
||||||
|
// Merge the two lists.
|
||||||
|
REQUEST[`contents`] = [...this[`history`], ...REQUEST[`contents`]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the additional configuration.
|
||||||
|
if (safetySettings) {
|
||||||
|
REQUEST[`safetySettings`] = safetySettings;
|
||||||
|
}
|
||||||
|
if (generationConfig) {
|
||||||
|
REQUEST[`generationConfig`] = generationConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
let send = async (REQUEST) => {
|
||||||
|
// Send the request.
|
||||||
|
let CONNECT = await fetch(this.#request[`location`].concat(`:generateContent`), {method: `POST`, headers: this.#request[`headers`], body: JSON.stringify(REQUEST)});
|
||||||
|
|
||||||
|
if (CONNECT.ok) {
|
||||||
|
let RESPONSE = await CONNECT.json();
|
||||||
|
if (Object.keys(RESPONSE).includes(`error`)) {
|
||||||
|
throw new Error(RESPONSE[`error`]);
|
||||||
|
} else {
|
||||||
|
// this[`history`] = REQUEST[`contents`];
|
||||||
|
this.response = RESPONSE;
|
||||||
|
return RESPONSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`The request failed.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Analyze the response. */
|
||||||
|
let analyze = (RESPONSE_RAW) => {
|
||||||
|
let RESPONSES = [];
|
||||||
|
|
||||||
|
// Check if the prompt has been blocked.
|
||||||
|
while (RESPONSES.length < RESPONSE_RAW[`candidates`].length) {
|
||||||
|
// Check if the response is blocked.
|
||||||
|
if (!RESPONSE_RAW[`candidates`][RESPONSES.length][`safetyRatings`][`blocked`] && RESPONSE_RAW[`candidates`][RESPONSES.length][`content`]) {
|
||||||
|
let RESPONSE_CURRENT = [];
|
||||||
|
|
||||||
|
let RESPONSES_RAW_ALL = RESPONSE_RAW[`candidates`][RESPONSES.length][`content`][`parts`];
|
||||||
|
while (RESPONSE_CURRENT.length < RESPONSES_RAW_ALL.length) {
|
||||||
|
RESPONSE_CURRENT.push(String(RESPONSES_RAW_ALL[RESPONSE_CURRENT.length][`text`]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the item to this response.
|
||||||
|
RESPONSES.push(RESPONSE_CURRENT.join());
|
||||||
|
|
||||||
|
// Add the response to the history.
|
||||||
|
if (!Object.keys(this).includes(`history`)) {this[`history`] = []}
|
||||||
|
this[`history`].concat(RESPONSE_RAW[`candidates`][RESPONSES.length - 1][`content`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RESPONSES.length > 0) {
|
||||||
|
// Merge the responses.
|
||||||
|
this.candidate = RESPONSES.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
let REQUEST = await create();
|
||||||
|
let RESPONSE_RAW = await send(REQUEST);
|
||||||
|
return(analyze(RESPONSE_RAW));
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue