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