diff --git a/frontend/src/components/LLMSelection/GeminiLLMOptions/index.jsx b/frontend/src/components/LLMSelection/GeminiLLMOptions/index.jsx
index 8cb513f3..d2846704 100644
--- a/frontend/src/components/LLMSelection/GeminiLLMOptions/index.jsx
+++ b/frontend/src/components/LLMSelection/GeminiLLMOptions/index.jsx
@@ -19,25 +19,47 @@ export default function GeminiLLMOptions({ settings }) {
{!settings?.credentialsOnly && (
-
-
-
-
+ <>
+
+
+
+
+
+
+
+
+ >
)}
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js
index a5bb6a23..70913fd9 100644
--- a/server/models/systemSettings.js
+++ b/server/models/systemSettings.js
@@ -354,6 +354,8 @@ const SystemSettings = {
// Gemini Keys
GeminiLLMApiKey: !!process.env.GEMINI_API_KEY,
GeminiLLMModelPref: process.env.GEMINI_LLM_MODEL_PREF || "gemini-pro",
+ GeminiSafetySetting:
+ process.env.GEMINI_SAFETY_SETTING || "BLOCK_MEDIUM_AND_ABOVE",
// LMStudio Keys
LMStudioBasePath: process.env.LMSTUDIO_BASE_PATH,
diff --git a/server/utils/AiProviders/gemini/index.js b/server/utils/AiProviders/gemini/index.js
index 3dd307af..0c2cc769 100644
--- a/server/utils/AiProviders/gemini/index.js
+++ b/server/utils/AiProviders/gemini/index.js
@@ -29,6 +29,7 @@ class GeminiLLM {
this.embedder = embedder ?? new NativeEmbedder();
this.defaultTemp = 0.7; // not used for Gemini
+ this.safetyThreshold = this.#fetchSafetyThreshold();
}
#appendContext(contextTexts = []) {
@@ -43,6 +44,41 @@ class GeminiLLM {
);
}
+ // BLOCK_NONE can be a special candidate for some fields
+ // https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes#how_to_remove_automated_response_blocking_for_select_safety_attributes
+ // so if you are wondering why BLOCK_NONE still failed, the link above will explain why.
+ #fetchSafetyThreshold() {
+ const threshold =
+ process.env.GEMINI_SAFETY_SETTING ?? "BLOCK_MEDIUM_AND_ABOVE";
+ const safetyThresholds = [
+ "BLOCK_NONE",
+ "BLOCK_ONLY_HIGH",
+ "BLOCK_MEDIUM_AND_ABOVE",
+ "BLOCK_LOW_AND_ABOVE",
+ ];
+ return safetyThresholds.includes(threshold)
+ ? threshold
+ : "BLOCK_MEDIUM_AND_ABOVE";
+ }
+
+ #safetySettings() {
+ return [
+ {
+ category: "HARM_CATEGORY_HATE_SPEECH",
+ threshold: this.safetyThreshold,
+ },
+ {
+ category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
+ threshold: this.safetyThreshold,
+ },
+ { category: "HARM_CATEGORY_HARASSMENT", threshold: this.safetyThreshold },
+ {
+ category: "HARM_CATEGORY_DANGEROUS_CONTENT",
+ threshold: this.safetyThreshold,
+ },
+ ];
+ }
+
streamingEnabled() {
return "streamGetChatCompletion" in this;
}
@@ -143,6 +179,7 @@ class GeminiLLM {
)?.content;
const chatThread = this.gemini.startChat({
history: this.formatMessages(messages),
+ safetySettings: this.#safetySettings(),
});
const result = await chatThread.sendMessage(prompt);
const response = result.response;
@@ -164,6 +201,7 @@ class GeminiLLM {
)?.content;
const chatThread = this.gemini.startChat({
history: this.formatMessages(messages),
+ safetySettings: this.#safetySettings(),
});
const responseStream = await chatThread.sendMessageStream(prompt);
if (!responseStream.stream)
diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js
index 40154163..c8811c9d 100644
--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -52,6 +52,10 @@ const KEY_MAPPING = {
envKey: "GEMINI_LLM_MODEL_PREF",
checks: [isNotEmpty, validGeminiModel],
},
+ GeminiSafetySetting: {
+ envKey: "GEMINI_SAFETY_SETTING",
+ checks: [validGeminiSafetySetting],
+ },
// LMStudio Settings
LMStudioBasePath: {
@@ -528,6 +532,18 @@ function validGeminiModel(input = "") {
: `Invalid Model type. Must be one of ${validModels.join(", ")}.`;
}
+function validGeminiSafetySetting(input = "") {
+ const validModes = [
+ "BLOCK_NONE",
+ "BLOCK_ONLY_HIGH",
+ "BLOCK_MEDIUM_AND_ABOVE",
+ "BLOCK_LOW_AND_ABOVE",
+ ];
+ return validModes.includes(input)
+ ? null
+ : `Invalid Safety setting. Must be one of ${validModes.join(", ")}.`;
+}
+
function validAnthropicModel(input = "") {
const validModels = [
"claude-instant-1.2",