new(llm.gblib): Added Claude.

This commit is contained in:
me@rodrigorodriguez.com 2024-11-08 06:49:30 -03:00
parent 94a7fa0267
commit 749d7e7bdb
6 changed files with 68 additions and 53 deletions

View file

@ -86,7 +86,9 @@
"@google-cloud/translate": "8.5.0", "@google-cloud/translate": "8.5.0",
"@hubspot/api-client": "11.2.0", "@hubspot/api-client": "11.2.0",
"@koa/cors": "5.0.0", "@koa/cors": "5.0.0",
"@langchain/anthropic": "^0.3.7",
"@langchain/community": "0.2.31", "@langchain/community": "0.2.31",
"@langchain/core": "^0.3.17",
"@langchain/openai": "0.2.8", "@langchain/openai": "0.2.8",
"@microsoft/microsoft-graph-client": "3.0.7", "@microsoft/microsoft-graph-client": "3.0.7",
"@nlpjs/basic": "4.27.0", "@nlpjs/basic": "4.27.0",

View file

@ -53,7 +53,6 @@ import fs from 'fs/promises';
import twilio from 'twilio'; import twilio from 'twilio';
import Nexmo from 'nexmo'; import Nexmo from 'nexmo';
import { join } from 'path'; import { join } from 'path';
import path from 'path';
import shell from 'any-shell-escape'; import shell from 'any-shell-escape';
import { exec } from 'child_process'; import { exec } from 'child_process';
import prism from 'prism-media'; import prism from 'prism-media';
@ -66,7 +65,6 @@ import * as marked from 'marked';
import Translate from '@google-cloud/translate'; import Translate from '@google-cloud/translate';
import { GBUtil } from '../../../src/util.js'; import { GBUtil } from '../../../src/util.js';
import { GBLogEx } from './GBLogEx.js'; import { GBLogEx } from './GBLogEx.js';
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
/** /**
* Provides basic services for handling messages and dispatching to back-end * Provides basic services for handling messages and dispatching to back-end

View file

@ -353,6 +353,7 @@ export class GBDeployer implements IGBDeployer {
try { try {
vectorStore = await HNSWLib.load(min['vectorStorePath'], embedding); vectorStore = await HNSWLib.load(min['vectorStorePath'], embedding);
} catch { } catch {
GBLogEx.info(min, 'Creating new store...');
vectorStore = new HNSWLib(embedding, { vectorStore = new HNSWLib(embedding, {
space: 'cosine' space: 'cosine'
}); });

View file

@ -47,6 +47,7 @@ import { CSVLoader } from '@langchain/community/document_loaders/fs/csv';
import { DocxLoader } from '@langchain/community/document_loaders/fs/docx'; import { DocxLoader } from '@langchain/community/document_loaders/fs/docx';
import { EPubLoader } from '@langchain/community/document_loaders/fs/epub'; import { EPubLoader } from '@langchain/community/document_loaders/fs/epub';
import { PDFLoader } from '@langchain/community/document_loaders/fs/pdf'; import { PDFLoader } from '@langchain/community/document_loaders/fs/pdf';
import { rimraf } from 'rimraf';
import getColors from 'get-image-colors'; import getColors from 'get-image-colors';
import { Document } from 'langchain/document'; import { Document } from 'langchain/document';
@ -651,8 +652,8 @@ export class KBService implements IGBKBService {
await min.conversationalService['playMarkdown'](min, answer, channel, step, GBMinService.userMobile(step)); await min.conversationalService['playMarkdown'](min, answer, channel, step, GBMinService.userMobile(step));
} else if (answer.endsWith('.ogg') && process.env.AUDIO_DISABLED !== 'true') { } else if (answer.endsWith('.ogg') && process.env.AUDIO_DISABLED !== 'true') {
await this.playAudio(min, answer, channel, step, min.conversationalService); await this.playAudio(min, answer, channel, step, min.conversationalService);
} else if(answer.startsWith('![')){ } else if (answer.startsWith('![')) {
const url = answer.match(/\((.*?)\)/)[1]; const url = answer.match(/\((.*?)\)/)[1];
await this.showImage(min, min.conversationalService, step, url, channel) await this.showImage(min, min.conversationalService, step, url, channel)
} else { } else {
@ -885,7 +886,7 @@ export class KBService implements IGBKBService {
): Promise<string[]> { ): Promise<string[]> {
try { try {
if ( if (
depth > maxDepth || (depth > maxDepth && !url.endsWith('pdf')) ||
visited.has(url) || visited.has(url) ||
url.endsWith('.jpg') || url.endsWith('.jpg') ||
url.endsWith('.png') || url.endsWith('.png') ||
@ -1029,6 +1030,14 @@ export class KBService implements IGBKBService {
const websiteIgnoreUrls = min.core.getParam<[]>(min.instance, 'Website Ignore URLs', null); const websiteIgnoreUrls = min.core.getParam<[]>(min.instance, 'Website Ignore URLs', null);
GBLogEx.info(min, `Website: ${website}, Max Depth: ${maxDepth}, Ignore URLs: ${websiteIgnoreUrls}`); GBLogEx.info(min, `Website: ${website}, Max Depth: ${maxDepth}, Ignore URLs: ${websiteIgnoreUrls}`);
let vectorStore = min['vectorStore'];
if (vectorStore) {
rimraf.sync(min['vectorStorePath'])
vectorStore = await min.deployService['loadOrCreateEmptyVectorStore'](min);
min['vectorStore'] = vectorStore;
}
if (website) { if (website) {
// Removes last slash if any. // Removes last slash if any.
@ -1099,19 +1108,20 @@ export class KBService implements IGBKBService {
GBLogEx.info(min, `Vectorizing ${files.length} file(s)...`); GBLogEx.info(min, `Vectorizing ${files.length} file(s)...`);
await CollectionUtil.asyncForEach(files, async file => { await CollectionUtil.asyncForEach(files, async file => {
let content = null; let content = null;
try { try {
const document = await this.loadAndSplitFile(file); const document = await this.loadAndSplitFile(file);
const flattenedDocuments = document.reduce((acc, val) => acc.concat(val), []); const flattenedDocuments = document.reduce((acc, val) => acc.concat(val), []);
const vectorStore = min['vectorStore'];
await vectorStore.addDocuments(flattenedDocuments); await vectorStore.addDocuments(flattenedDocuments);
await vectorStore.save(min['vectorStorePath']);
} catch (error) { } catch (error) {
GBLogEx.info(min, `Ignore processing of ${file}. ${GBUtil.toYAML(error)}`); GBLogEx.info(min, `Ignore processing of ${file}. ${GBUtil.toYAML(error)}`);
} }
}); });
} }
files = await walkPromise(urlJoin(localPath, 'docs')); files = await walkPromise(urlJoin(localPath, 'docs'));
@ -1123,13 +1133,16 @@ export class KBService implements IGBKBService {
const document = await this.loadAndSplitFile(filePath); const document = await this.loadAndSplitFile(filePath);
const flattenedDocuments = document.reduce((acc, val) => acc.concat(val), []); const flattenedDocuments = document.reduce((acc, val) => acc.concat(val), []);
const vectorStore = min['vectorStore'];
await vectorStore.addDocuments(flattenedDocuments); await vectorStore.addDocuments(flattenedDocuments);
await vectorStore.save(min['vectorStorePath']);
}); });
} }
await vectorStore.save(min['vectorStorePath']);
min['vectorStore'] = vectorStore;
} }
defaultRecursiveCharacterTextSplitter = new RecursiveCharacterTextSplitter({ defaultRecursiveCharacterTextSplitter = new RecursiveCharacterTextSplitter({
chunkSize: 700, chunkSize: 700,
chunkOverlap: 50 chunkOverlap: 50
@ -1496,7 +1509,11 @@ export class KBService implements IGBKBService {
return filePath; // Return the saved file path return filePath; // Return the saved file path
} else { } else {
await page.goto(url, { waitUntil: 'networkidle2' }); await page.goto(url, {
waitUntil: 'networkidle2',
timeout: 60000 // Timeout after 1 minute (60,000 ms)
});
const parsedUrl = new URL(url); const parsedUrl = new URL(url);

View file

@ -29,6 +29,7 @@
\*****************************************************************************/ \*****************************************************************************/
'use strict'; 'use strict';
import { ChatAnthropic } from "@langchain/anthropic";
import { PromptTemplate } from '@langchain/core/prompts'; import { PromptTemplate } from '@langchain/core/prompts';
import { WikipediaQueryRun } from '@langchain/community/tools/wikipedia_query_run'; import { WikipediaQueryRun } from '@langchain/community/tools/wikipedia_query_run';
import { HNSWLib } from '@langchain/community/vectorstores/hnswlib'; import { HNSWLib } from '@langchain/community/vectorstores/hnswlib';
@ -244,6 +245,16 @@ export class ChatServices {
public static async invokeLLM(min: GBMinInstance, text: string) { public static async invokeLLM(min: GBMinInstance, text: string) {
let model; let model;
model = await ChatServices.getModel(min);
return await model.invoke(text);
}
public static memoryMap = {};
public static userSystemPrompt = {};
public static usersMode = {};
private static async getModel(min: GBMinInstance) {
const azureOpenAIKey = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Key', null, true); const azureOpenAIKey = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Key', null, true);
const azureOpenAILLMModel = await (min.core as any)['getParam']( const azureOpenAILLMModel = await (min.core as any)['getParam'](
min.instance, min.instance,
@ -259,23 +270,33 @@ export class ChatServices {
true true
); );
model = new ChatOpenAI({ const provider = await (min.core as any)['getParam'](
azureOpenAIApiKey: azureOpenAIKey, min.instance,
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName, 'LLM Provider',
null,
azureOpenAIApiDeploymentName: azureOpenAILLMModel, 'openai'
azureOpenAIApiVersion: azureOpenAIVersion, );
temperature: 0, let model;
callbacks: [logHandler] if (provider === 'claude') {
}); model = new ChatAnthropic({
model: "claude-3-haiku-20240307",
return await model.invoke(text); temperature: 0,
maxTokens: undefined,
maxRetries: 2,
});
} else {
model = new ChatOpenAI({
azureOpenAIApiKey: azureOpenAIKey,
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
azureOpenAIApiVersion: azureOpenAIVersion,
temperature: 0,
callbacks: [logHandler]
});
}
return model;
} }
public static memoryMap = {};
public static userSystemPrompt = {};
public static usersMode = {};
public static async answerByLLM(pid: number, min: GBMinInstance, user, question: string, mode = null) { public static async answerByLLM(pid: number, min: GBMinInstance, user, question: string, mode = null) {
const answerMode = this.usersMode[user.userSystemId] const answerMode = this.usersMode[user.userSystemId]
? this.usersMode[user.userSystemId] ? this.usersMode[user.userSystemId]
@ -308,32 +329,7 @@ export class ChatServices {
const systemPrompt = securityPrompt + (user ? this.userSystemPrompt[user.userSystemId] : ''); const systemPrompt = securityPrompt + (user ? this.userSystemPrompt[user.userSystemId] : '');
let model; let model = await ChatServices.getModel(min);
const azureOpenAIKey = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Key', null, true);
const azureOpenAILLMModel = await (min.core as any)['getParam'](
min.instance,
'Azure Open AI LLM Model',
null,
true
);
const azureOpenAIVersion = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Version', null, true);
const azureOpenAIApiInstanceName = await (min.core as any)['getParam'](
min.instance,
'Azure Open AI Instance',
null,
true
);
model = new ChatOpenAI({
azureOpenAIApiKey: azureOpenAIKey,
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
azureOpenAIApiVersion: azureOpenAIVersion,
temperature: 0,
callbacks: [logHandler]
});
let tools = await ChatServices.getTools(min); let tools = await ChatServices.getTools(min);
let toolsAsText = ChatServices.getToolsAsText(tools); let toolsAsText = ChatServices.getToolsAsText(tools);

View file

@ -1,4 +1,5 @@
name,value name,value
Website,https://www.dgti.uerj.br/ Website,https://www.oabgo.org.br/
Answer Mode,document Answer Mode,document
Theme Color,purple Theme Color,purple
LLM Provider,claude
1 name value
2 Website https://www.dgti.uerj.br/ https://www.oabgo.org.br/
3 Answer Mode document
4 Theme Color purple purple
5 LLM Provider claude