Skip to content

Commit

Permalink
feat: Gemini text generation
Browse files Browse the repository at this point in the history
  • Loading branch information
gensart-ai committed Feb 18, 2024
1 parent 052e4d4 commit d35b120
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/command-hive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import commandGuide from 'services/internal/command-guide'
import imageToSticker from 'services/internal/image-to-sticker'
import { translateEnglishToIndo, translateIndoToEnglish } from './services/external/translate'
import { imageToStickerText } from './services/external/image-to-sticker-meme'
import { geminiTextOnly } from './services/external/gemini'

type Commands = {
[key: string] : (client: Client, message: Message) => any
Expand All @@ -18,6 +19,9 @@ const commands: Commands = {
// * Quotes
'.quotes': getForismaticQuotes,

// * AI-generated
'.gemini': geminiTextOnly,

// * Translation
'.engtoindo': translateEnglishToIndo,
'.indotoeng': translateIndoToEnglish,
Expand Down
4 changes: 3 additions & 1 deletion src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface EnvironmentConfiguration {
botCodeName: string,

imgBBKey: string, // ImgBB API Key
googleAiStudioKey: string,
}

const environmentConfiguration: EnvironmentConfiguration = {
Expand All @@ -15,7 +16,8 @@ const environmentConfiguration: EnvironmentConfiguration = {
botShortName: 'Sora',
botCodeName: 'SoraErlyana',

imgBBKey: '8ceb73c518129ab2ca63c8cf9f7ea8a6'
imgBBKey: '8ceb73c518129ab2ca63c8cf9f7ea8a6',
googleAiStudioKey: 'AIzaSyBIMSDB4T7Gn7pfnTMLJHMp4qenjG0gN0Q'
}

export default environmentConfiguration
121 changes: 121 additions & 0 deletions src/services/external/gemini.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import axios from 'axios'
import * as wweb from '@utils/wweb'
import { Executor } from '@/command-hive'
import config from '@/env'

type HarmfulCategory = {
/**
* Harmful category
*/
category: string,
/**
* Harmful probability, whether it `NEGLIGIBLE` or none, or the other level
*/
probability: string
}

type HarmfulMessages = {
[key: string]: string
}

type GeminiResponse = {
text?: string,
isMayHarmful: boolean,
harmfulText?: string
}

const harmfulCategories: HarmfulMessages = {
'HARM_CATEGORY_SEXUALLY_EXPLICIT': 'Pertanyaan anda kemungkinan mengandung unsur seksual secara eksplisit',
'HARM_CATEGORY_HATE_SPEECH': 'Pertanyaan anda kemungkinan mengandung unsur ujaran kebencian',
'HARM_CATEGORY_HARASSMENT': 'Pertanyaan anda kemungkinan mengandung unsur kekerasan',
'HARM_CATEGORY_DANGEROUS_CONTENT': 'Pertanyaan anda kemungkinan mengandung konten berbahaya',
}

/**
* Generate a text-only answer from Gemini API
* With harmful rating processing included
* @param {string} text The question, command, or whatever
* @return {Promise<GeminiResponse>}
*/
const geminiText = async (text: string): Promise<GeminiResponse> => {

// Preparing the result object
const result: GeminiResponse = {
isMayHarmful: false
}

// Reform the data format for Gemini API to receive
let geminiUrl: string = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
const requestDataFormat: object = {
"contents": [
{
"parts": [
{
"text": text
}
]
}
]
};

// Add API key to the URL
geminiUrl = geminiUrl + '?key=' + config.googleAiStudioKey;

// Hit the API
const response = await axios.post(geminiUrl, requestDataFormat);

// Process the generated answer, if exist
if ('candidates' in response.data) {
const generatedAnswer: string = response.data.candidates[0]?.content?.parts[0]?.text;
result.text = generatedAnswer ?? 'Maaf, tidak ada jawaban yang tersedia. Silahkan coba lagi';
}

// Process the safety ratings of the generated answer
const harmRatings: HarmfulCategory[] = response.data.promptFeedback.safetyRatings;
for (const harmCategory of harmRatings) {
if (harmCategory.probability != 'NEGLIGIBLE') {
result.isMayHarmful = true;
result.harmfulText = harmfulCategories[harmCategory.category];
break;
}
}

return result;
}

const geminiTextOnly: Executor = async (client, message) => {
try {
// Delete command from text
let text: string = message.body;
text = text.split(' ').slice(1).join(' ');

if (text.length === 0) {
const warningMessage: string[] = [
`Dengan perintah ini, anda dapat menanyakan sesuatu ke ${config.botShortName}`,
'Format: `.gemini [pertanyaan]`',
'Contoh: `.gemini Apa saja planet di tata surya kita?`'
]
wweb.replyMessage(message, warningMessage.join('\n'));
return 0;
}

const answer: GeminiResponse = await geminiText(text);

if (answer.text) {
wweb.replyMessage(message, answer.text ?? 'Maaf, tidak ada jawaban yang tersedia. Silahkan coba lagi');
}

if (answer.isMayHarmful) {
wweb.sendMessage(client, message.from, answer.harmfulText ?? 'Pertanyaan anda tidak valid');
return 0;
} else {
wweb.replyMessage(message, 'Maaf, tidak ada jawaban yang tersedia. Silahkan coba lagi');
}
} catch (error) {
wweb.replyMessage(message, 'Maaf, terjadi kesalahan saat menjawab pertanyaan anda. Silahkan coba lagi');
}
}

export {
geminiTextOnly
}
2 changes: 2 additions & 0 deletions src/services/internal/command-guide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const commandGuide: Executor = async (client, message) => {
'Btw, dibawah ini list command yang tersedia: (Bisa ketik perintahnya aja untuk informasi setiap perintahnya ya)\n',
'*== Quotes ==*',
'.quotes\n',
'*== Fitur AI ==*',
'.gemini [pertanyaan/perintah]\n',
'*== Translate ==*',
'.indotoeng [text indo] - Translate Indonesia ke Inggris',
'.engtoindo [text inggris] - Translate Inggris ke Indonesia\n',
Expand Down

0 comments on commit d35b120

Please sign in to comment.