Deprecate .isSafe moderation ()

Add type defs to helpers
This commit is contained in:
Timothy Carambat 2024-06-28 15:32:30 -07:00 committed by GitHub
parent 910eb36cfe
commit 0b845fbb1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 52 additions and 164 deletions
server/utils
AiProviders
anthropic
azureOpenAi
cohere
gemini
genericOpenAi
groq
huggingface
koboldCPP
liteLLM
lmStudio
localAi
mistral
native
ollama
openAi
openRouter
perplexity
textGenWebUI
togetherAi
chats
helpers

View file

@ -66,13 +66,6 @@ class AnthropicLLM {
return validModels.includes(modelName);
}
// Moderation can be done with Anthropic, but its not really "exact" so we skip it
// https://docs.anthropic.com/claude/docs/content-moderation
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
constructPrompt({
systemPrompt = "",
contextTexts = [],

View file

@ -72,11 +72,6 @@ class AzureOpenAiLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented by Azure OpenAI so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = [], { temperature = 0.7 }) {
if (!this.model)
throw new Error(

View file

@ -102,11 +102,6 @@ class CohereLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -112,12 +112,6 @@ class GeminiLLM {
return validModels.includes(modelName);
}
// Moderation cannot be done with Gemini.
// Not implemented so must be stubbed
async isSafe(_input = "") {
return { safe: true, reasons: [] };
}
constructPrompt({
systemPrompt = "",
contextTexts = [],

View file

@ -83,11 +83,6 @@ class GenericOpenAiLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const result = await this.openai.chat.completions
.create({

View file

@ -85,11 +85,6 @@ class GroqLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -79,11 +79,6 @@ class HuggingFaceLLM {
];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const result = await this.openai.createChatCompletion({
model: this.model,

View file

@ -79,11 +79,6 @@ class KoboldCPPLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const result = await this.openai.chat.completions
.create({

View file

@ -78,11 +78,6 @@ class LiteLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const result = await this.openai.chat.completions
.create({

View file

@ -76,11 +76,6 @@ class LMStudioLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!this.model)
throw new Error(

View file

@ -66,11 +66,6 @@ class LocalAiLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -62,10 +62,6 @@ class MistralLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_ = "") {
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -117,11 +117,6 @@ class NativeLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const model = await this.#llamaClient({ temperature });
const response = await model.call(messages);

View file

@ -99,11 +99,6 @@ class OllamaAILLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const model = this.#ollamaClient({ temperature });
const textResponse = await model

View file

@ -86,37 +86,6 @@ class OpenAiLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(input = "") {
const { flagged = false, categories = {} } = await this.openai.moderations
.create({ input })
.then((res) => {
if (!res.hasOwnProperty("results"))
throw new Error("OpenAI moderation: No results!");
if (res.results.length === 0)
throw new Error("OpenAI moderation: No results length!");
return res.results[0];
})
.catch((error) => {
throw new Error(
`OpenAI::CreateModeration failed with: ${error.message}`
);
});
if (!flagged) return { safe: true, reasons: [] };
const reasons = Object.keys(categories)
.map((category) => {
const value = categories[category];
if (value === true) {
return category.replace("/", " or ");
} else {
return null;
}
})
.filter((reason) => !!reason);
return { safe: false, reasons };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -124,11 +124,6 @@ class OpenRouterLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -75,11 +75,6 @@ class PerplexityLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -76,11 +76,6 @@ class TextGenWebUILLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
const result = await this.openai.chat.completions
.create({

View file

@ -73,11 +73,6 @@ class TogetherAiLLM {
return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
}
async isSafe(_input = "") {
// Not implemented so must be stubbed
return { safe: true, reasons: [] };
}
async getChatCompletion(messages = null, { temperature = 0.7 }) {
if (!(await this.isValidChatCompletionModel(this.model)))
throw new Error(

View file

@ -33,20 +33,6 @@ async function streamChatWithForEmbed(
model: chatModel ?? embed.workspace?.chatModel,
});
const VectorDb = getVectorDbClass();
const { safe, reasons = [] } = await LLMConnector.isSafe(message);
if (!safe) {
writeResponseChunk(response, {
id: uuid,
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `This message was moderated and will not be allowed. Violations for ${reasons.join(
", "
)} found.`,
});
return;
}
const messageLimit = 20;
const hasVectorizedSpace = await VectorDb.hasNamespace(embed.workspace.slug);

View file

@ -56,19 +56,6 @@ async function chatWithWorkspace(
model: workspace?.chatModel,
});
const VectorDb = getVectorDbClass();
const { safe, reasons = [] } = await LLMConnector.isSafe(message);
if (!safe) {
return {
id: uuid,
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `This message was moderated and will not be allowed. Violations for ${reasons.join(
", "
)} found.`,
};
}
const messageLimit = workspace?.openAiHistory || 20;
const hasVectorizedSpace = await VectorDb.hasNamespace(workspace.slug);

View file

@ -53,20 +53,6 @@ async function streamChatWithWorkspace(
model: workspace?.chatModel,
});
const VectorDb = getVectorDbClass();
const { safe, reasons = [] } = await LLMConnector.isSafe(message);
if (!safe) {
writeResponseChunk(response, {
id: uuid,
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `This message was moderated and will not be allowed. Violations for ${reasons.join(
", "
)} found.`,
});
return;
}
const messageLimit = workspace?.openAiHistory || 20;
const hasVectorizedSpace = await VectorDb.hasNamespace(workspace.slug);

View file

@ -1,3 +1,46 @@
/**
* @typedef {Object} BaseLLMProvider - A basic llm provider object
* @property {Function} streamingEnabled - Checks if streaming is enabled for chat completions.
* @property {Function} promptWindowLimit - Returns the token limit for the current model.
* @property {Function} isValidChatCompletionModel - Validates if the provided model is suitable for chat completion.
* @property {Function} constructPrompt - Constructs a formatted prompt for the chat completion request.
* @property {Function} getChatCompletion - Gets a chat completion response from OpenAI.
* @property {Function} streamGetChatCompletion - Streams a chat completion response from OpenAI.
* @property {Function} handleStream - Handles the streaming response.
* @property {Function} embedTextInput - Embeds the provided text input using the specified embedder.
* @property {Function} embedChunks - Embeds multiple chunks of text using the specified embedder.
* @property {Function} compressMessages - Compresses chat messages to fit within the token limit.
*/
/**
* @typedef {Object} BaseVectorDatabaseProvider
* @property {string} name - The name of the Vector Database instance.
* @property {Function} connect - Connects to the Vector Database client.
* @property {Function} totalVectors - Returns the total number of vectors in the database.
* @property {Function} namespaceCount - Returns the count of vectors in a given namespace.
* @property {Function} similarityResponse - Performs a similarity search on a given namespace.
* @property {Function} namespace - Retrieves the specified namespace collection.
* @property {Function} hasNamespace - Checks if a namespace exists.
* @property {Function} namespaceExists - Verifies if a namespace exists in the client.
* @property {Function} deleteVectorsInNamespace - Deletes all vectors in a specified namespace.
* @property {Function} deleteDocumentFromNamespace - Deletes a document from a specified namespace.
* @property {Function} addDocumentToNamespace - Adds a document to a specified namespace.
* @property {Function} performSimilaritySearch - Performs a similarity search in the namespace.
*/
/**
* @typedef {Object} BaseEmbedderProvider
* @property {string} model - The model used for embedding.
* @property {number} maxConcurrentChunks - The maximum number of chunks processed concurrently.
* @property {number} embeddingMaxChunkLength - The maximum length of each chunk for embedding.
* @property {Function} embedTextInput - Embeds a single text input.
* @property {Function} embedChunks - Embeds multiple chunks of text.
*/
/**
* Gets the systems current vector database provider.
* @returns { BaseVectorDatabaseProvider}
*/
function getVectorDbClass() {
const vectorSelection = process.env.VECTOR_DB || "lancedb";
switch (vectorSelection) {
@ -30,6 +73,11 @@ function getVectorDbClass() {
}
}
/**
* Returns the LLMProvider with its embedder attached via system or via defined provider.
* @param {{provider: string | null, model: string | null} | null} params - Initialize params for LLMs provider
* @returns {BaseLLMProvider}
*/
function getLLMProvider({ provider = null, model = null } = {}) {
const LLMSelection = provider ?? process.env.LLM_PROVIDER ?? "openai";
const embedder = getEmbeddingEngineSelection();
@ -99,6 +147,10 @@ function getLLMProvider({ provider = null, model = null } = {}) {
}
}
/**
* Returns the EmbedderProvider by itself to whatever is currently in the system settings.
* @returns {BaseEmbedderProvider}
*/
function getEmbeddingEngineSelection() {
const { NativeEmbedder } = require("../EmbeddingEngines/native");
const engineSelection = process.env.EMBEDDING_ENGINE;