new(basic.gblib): GPT replacing ALLEN NLP Reading Comp.
This commit is contained in:
parent
218bcd1b3e
commit
681d20c5fe
10 changed files with 138 additions and 103 deletions
|
@ -327,7 +327,7 @@ export class AdminDialog extends IGBDialog {
|
|||
let sec = new SecService();
|
||||
const member = step.context.activity.from;
|
||||
const user = await sec.ensureUser(
|
||||
min.instance.instanceId,
|
||||
min,
|
||||
member.id,
|
||||
member.name,
|
||||
'',
|
||||
|
|
|
@ -1220,7 +1220,7 @@ export class DialogKeywords {
|
|||
let user = await sec.getUserFromSystemId(fromOrDialogName);
|
||||
if (!user) {
|
||||
user = await sec.ensureUser(
|
||||
min.instance.instanceId,
|
||||
min,
|
||||
fromOrDialogName,
|
||||
fromOrDialogName,
|
||||
null,
|
||||
|
|
|
@ -328,6 +328,10 @@ export class GBMinService {
|
|||
if (!Fs.existsSync(dir)) {
|
||||
mkdirp.sync(dir);
|
||||
}
|
||||
dir = `work/${gbai}/users`;
|
||||
if (!Fs.existsSync(dir)) {
|
||||
mkdirp.sync(dir);
|
||||
}
|
||||
|
||||
// Loads Named Entity data for this bot.
|
||||
|
||||
|
@ -956,7 +960,7 @@ export class GBMinService {
|
|||
|
||||
const member = context.activity.from;
|
||||
const sec = new SecService();
|
||||
const user = await sec.ensureUser(instance.instanceId, member.id, member.name, '', 'web', member.name, null);
|
||||
const user = await sec.ensureUser(min, member.id, member.name, '', 'web', member.name, null);
|
||||
const userId = user.userId;
|
||||
const params = user.params ? JSON.parse(user.params) : {};
|
||||
|
||||
|
@ -1351,7 +1355,7 @@ export class GBMinService {
|
|||
memberId = member.id;
|
||||
}
|
||||
|
||||
let user = await sec.ensureUser(min.instance.instanceId, memberId, member.name, '', 'web', member.name, email);
|
||||
let user = await sec.ensureUser(min, memberId, member.name, '', 'web', member.name, email);
|
||||
|
||||
const userId = user.userId;
|
||||
const params = user.params ? JSON.parse(user.params) : {};
|
||||
|
|
|
@ -88,7 +88,7 @@ export class FeedbackDialog extends IGBDialog {
|
|||
if (args && args.to) {
|
||||
// An user from Teams willing to transfer to a WhatsApp user.
|
||||
|
||||
await sec.ensureUser(min.instance.instanceId, args.to, 'Name', '', 'whatsapp', 'Name', null);
|
||||
await sec.ensureUser(min, args.to, 'Name', '', 'whatsapp', 'Name', null);
|
||||
|
||||
await sec.assignHumanAgent(min, args.to, profile.userSystemId);
|
||||
await min.conversationalService.sendText(
|
||||
|
|
|
@ -137,7 +137,7 @@ export class GoogleChatDirectLine extends GBService {
|
|||
message.ack();
|
||||
|
||||
const sec = new SecService();
|
||||
const user = await sec.ensureUser(this.min.instance.instanceId, from, from, '', 'googlechat', fromName, from);
|
||||
const user = await sec.ensureUser(this.min, from, from, '', 'googlechat', fromName, from);
|
||||
|
||||
await sec.updateConversationReferenceById(user.userId, threadName);
|
||||
|
||||
|
|
|
@ -32,14 +32,35 @@
|
|||
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import OpenAI from "openai";
|
||||
import { ChatGPTAPIBrowser, getOpenAIAuth } from 'chatgpt'
|
||||
import { OpenAIChat } from 'langchain/llms/openai';
|
||||
import { CallbackManager } from 'langchain/callbacks';
|
||||
import { ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts';
|
||||
import { LLMChain } from 'langchain/chains';
|
||||
import { BufferWindowMemory } from 'langchain/memory';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||
import Path from 'path';
|
||||
import * as Fs from 'fs';
|
||||
import { HNSWLib } from 'langchain/vectorstores/hnswlib';
|
||||
import { GuaribasSubject } from '../../kb.gbapp/models/index.js';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js';
|
||||
|
||||
export class ChatServices {
|
||||
|
||||
private static async getRelevantContext(
|
||||
vectorStore: HNSWLib,
|
||||
sanitizedQuestion: string,
|
||||
numDocuments: number
|
||||
): Promise<string> {
|
||||
const documents = await vectorStore.similaritySearch(sanitizedQuestion, numDocuments);
|
||||
return documents
|
||||
.map((doc) => doc.pageContent)
|
||||
.join(', ')
|
||||
.trim()
|
||||
.replaceAll('\n', ' ');
|
||||
}
|
||||
|
||||
|
||||
public static async sendMessage(min: GBMinInstance, text: string) {
|
||||
let key;
|
||||
if (process.env.OPENAI_KEY) {
|
||||
|
@ -112,4 +133,85 @@ export class ChatServices {
|
|||
// });
|
||||
// return chatCompletion.choices[0].message.content;
|
||||
}
|
||||
|
||||
public static async answerByGPT(min: GBMinInstance,
|
||||
query: string,
|
||||
searchScore: number,
|
||||
subjects: GuaribasSubject[]
|
||||
) {
|
||||
|
||||
if (!process.env.OPENAI_KEY) {
|
||||
return { answer: undefined, questionId: 0 };
|
||||
}
|
||||
|
||||
|
||||
const contextVectorStore = min['vectorStore'];
|
||||
const question = query.trim().replaceAll('\n', ' ');
|
||||
const context = await this.getRelevantContext(contextVectorStore, question, 1);
|
||||
|
||||
const systemPrompt = SystemMessagePromptTemplate.fromTemplate(
|
||||
`You are $${min.botId}`);
|
||||
|
||||
const contentLocale = min.core.getParam(
|
||||
min.instance,
|
||||
'Default Content Language',
|
||||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||
);
|
||||
|
||||
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
|
||||
systemPrompt,
|
||||
HumanMessagePromptTemplate.fromTemplate(`Answer in ${contentLocale}.
|
||||
You have access to the context (RELEVANTDOCS) provided by the user.
|
||||
|
||||
When answering think about whether the question in RELEVANTDOCS, but never mention
|
||||
to user about the source.
|
||||
Don’t justify your answers. Don't refer to yourself in any of the created content.
|
||||
Don´t prefix RESPONSE: when answering the user.
|
||||
RELEVANTDOCS: {context}
|
||||
|
||||
QUESTION: """{input}"""
|
||||
|
||||
`),
|
||||
]);
|
||||
const windowMemory = new BufferWindowMemory({
|
||||
returnMessages: false,
|
||||
memoryKey: 'immediate_history',
|
||||
inputKey: 'input',
|
||||
k: 2,
|
||||
});
|
||||
|
||||
const callbackManager = CallbackManager.fromHandlers({
|
||||
// This function is called when the LLM generates a new token (i.e., a prediction for the next word)
|
||||
async handleLLMNewToken(token: string) {
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
const llm = new OpenAIChat({
|
||||
streaming: true,
|
||||
callbackManager,
|
||||
modelName: 'gpt-3.5-turbo',
|
||||
});
|
||||
|
||||
const chain = new LLMChain({
|
||||
prompt: chatPrompt,
|
||||
memory: windowMemory,
|
||||
llm,
|
||||
});
|
||||
|
||||
const response = await chain.call({
|
||||
input: question,
|
||||
context,
|
||||
history: '',
|
||||
immediate_history: '',
|
||||
});
|
||||
if (response) {
|
||||
|
||||
return { answer: response.text, questionId: 0 };
|
||||
}
|
||||
|
||||
return { answer: undefined, questionId: 0 };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ export class AskDialog extends IGBDialog {
|
|||
let sec = new SecService();
|
||||
const member = step.context.activity.from;
|
||||
const user = await sec.ensureUser(
|
||||
min.instance.instanceId,
|
||||
min,
|
||||
member.id,
|
||||
member.name,
|
||||
'',
|
||||
|
@ -187,7 +187,7 @@ export class AskDialog extends IGBDialog {
|
|||
let answer: GuaribasAnswer = null;
|
||||
const member = step.context.activity.from;
|
||||
const sec = new SecService();
|
||||
let user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name, null);
|
||||
let user = await sec.ensureUser(min, member.id, member.name, '', 'web', member.name, null);
|
||||
|
||||
const minBoot = GBServer.globals.minBoot as any;
|
||||
|
||||
|
@ -436,7 +436,7 @@ export class AskDialog extends IGBDialog {
|
|||
let sec = new SecService();
|
||||
const member = step.context.activity.from;
|
||||
const user = await sec.ensureUser(
|
||||
min.instance.instanceId,
|
||||
min,
|
||||
member.id,
|
||||
member.name,
|
||||
'',
|
||||
|
|
|
@ -34,28 +34,22 @@
|
|||
|
||||
import Path from 'path';
|
||||
import Fs from 'fs';
|
||||
import { OpenAIChat } from 'langchain/llms/openai';
|
||||
import { CallbackManager } from 'langchain/callbacks';
|
||||
import urlJoin from 'url-join';
|
||||
import asyncPromise from 'async-promises';
|
||||
import walkPromise from 'walk-promise';
|
||||
import { SearchClient } from '@azure/search-documents';
|
||||
import Excel from 'exceljs';
|
||||
import getSlug from 'speakingurl';
|
||||
import { ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts';
|
||||
import { LLMChain } from 'langchain/chains';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { HNSWLib } from 'langchain/vectorstores/hnswlib';
|
||||
import { JSONLoader } from 'langchain/document_loaders/fs/json';
|
||||
import { TextLoader } from 'langchain/document_loaders/fs/text';
|
||||
import { PDFLoader } from 'langchain/document_loaders/fs/pdf';
|
||||
import { DocxLoader } from 'langchain/document_loaders/fs/docx';
|
||||
import { EPubLoader } from 'langchain/document_loaders/fs/epub';
|
||||
import { CSVLoader } from 'langchain/document_loaders/fs/csv';
|
||||
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
|
||||
import { BufferWindowMemory } from 'langchain/memory';
|
||||
import { Document } from 'langchain/document';
|
||||
import path from 'path';
|
||||
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
|
||||
import { Document } from 'langchain/document';
|
||||
|
||||
import {
|
||||
GBDialogStep,
|
||||
|
@ -85,6 +79,8 @@ import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
|||
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||
import { GBMinService } from '../../core.gbapp/services/GBMinService.js';
|
||||
import { ChatServices } from '../../gpt.gblib/services/ChatServices.js';
|
||||
|
||||
|
||||
/**
|
||||
* Result for quey on KB data.
|
||||
|
@ -365,7 +361,7 @@ export class KBService implements IGBKBService {
|
|||
returnedScore: ${returnedScore} < required (searchScore): ${searchScore}`
|
||||
);
|
||||
|
||||
return await this.answerByGPT(min,
|
||||
return await ChatServices.answerByGPT(min,
|
||||
query,
|
||||
searchScore,
|
||||
subjects
|
||||
|
@ -374,86 +370,8 @@ export class KBService implements IGBKBService {
|
|||
}
|
||||
}
|
||||
|
||||
private async getRelevantContext(
|
||||
vectorStore: HNSWLib,
|
||||
sanitizedQuestion: string,
|
||||
numDocuments: number
|
||||
): Promise<string> {
|
||||
const documents = await vectorStore.similaritySearch(sanitizedQuestion, numDocuments);
|
||||
return documents
|
||||
.map((doc) => doc.pageContent)
|
||||
.join(', ')
|
||||
.trim()
|
||||
.replaceAll('\n', ' ');
|
||||
}
|
||||
|
||||
|
||||
public async answerByGPT(min: GBMinInstance,
|
||||
query: string,
|
||||
searchScore: number,
|
||||
subjects: GuaribasSubject[]
|
||||
) {
|
||||
const contextVectorStore = min['vectorStore'];
|
||||
const question = query.trim().replaceAll('\n', ' ');
|
||||
const context = await this.getRelevantContext(contextVectorStore, question, 1);
|
||||
|
||||
const systemPrompt = SystemMessagePromptTemplate.fromTemplate(
|
||||
"You are General Bots");
|
||||
|
||||
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
|
||||
systemPrompt,
|
||||
HumanMessagePromptTemplate.fromTemplate(`Answer in pt-br.
|
||||
You have access to the context (RELEVANTDOCS) provided by the user.
|
||||
|
||||
When answering think about whether the question in RELEVANTDOCS, but never mention
|
||||
to user about the source.
|
||||
Don’t justify your answers. Don't refer to yourself in any of the created content.
|
||||
Don´t prefix RESPONSE: when answering the user.
|
||||
RELEVANTDOCS: {context}
|
||||
|
||||
QUESTION: """{input}"""
|
||||
|
||||
`),
|
||||
]);
|
||||
const windowMemory = new BufferWindowMemory({
|
||||
returnMessages: false,
|
||||
memoryKey: 'immediate_history',
|
||||
inputKey: 'input',
|
||||
k: 2,
|
||||
});
|
||||
|
||||
const callbackManager = CallbackManager.fromHandlers({
|
||||
// This function is called when the LLM generates a new token (i.e., a prediction for the next word)
|
||||
async handleLLMNewToken(token: string) {
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
const llm = new OpenAIChat({
|
||||
streaming: true,
|
||||
callbackManager,
|
||||
modelName: 'gpt-3.5-turbo',
|
||||
});
|
||||
|
||||
const chain = new LLMChain({
|
||||
prompt: chatPrompt,
|
||||
memory: windowMemory,
|
||||
llm,
|
||||
});
|
||||
|
||||
const response = await chain.call({
|
||||
input: question,
|
||||
context,
|
||||
history: '',
|
||||
immediate_history: '',
|
||||
});
|
||||
if (response) {
|
||||
|
||||
return { answer: response.text, questionId: 0 };
|
||||
}
|
||||
|
||||
return { answer: undefined, questionId: 0 };
|
||||
}
|
||||
|
||||
|
||||
public async getSubjectItems(instanceId: number, parentId: number): Promise<GuaribasSubject[]> {
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import { GBServer } from '../../../src/app.js';
|
||||
import { ConversationReference } from 'botbuilder';
|
||||
import { GBLog, GBMinInstance, GBService, IGBInstance } from 'botlib';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { GuaribasUser } from '../models/index.js';
|
||||
import { FindOptions } from 'sequelize';
|
||||
import { DialogKeywords } from '../../../packages/basic.gblib/services/DialogKeywords.js';
|
||||
import * as Fs from 'fs';
|
||||
import mkdirp from 'mkdirp';
|
||||
|
||||
/**
|
||||
* Security service layer.
|
||||
*/
|
||||
export class SecService extends GBService {
|
||||
public async ensureUser(
|
||||
instanceId: number,
|
||||
min: GBMinInstance,
|
||||
userSystemId: string,
|
||||
userName: string,
|
||||
address: string,
|
||||
|
@ -26,9 +28,18 @@ export class SecService extends GBService {
|
|||
|
||||
if (!user) {
|
||||
user = GuaribasUser.build();
|
||||
const gbaiPath = DialogKeywords.getGBAIPath(min.botId);
|
||||
|
||||
const dir = `work/${gbaiPath}/users/${userSystemId}`;
|
||||
if (!Fs.existsSync(dir)) {
|
||||
mkdirp.sync(dir);
|
||||
}
|
||||
|
||||
user.instanceId = instanceId;
|
||||
|
||||
|
||||
}
|
||||
|
||||
user.instanceId = min.instance.instanceId;
|
||||
user.userSystemId = userSystemId;
|
||||
user.userName = userName;
|
||||
user.displayName = displayName;
|
||||
|
|
|
@ -472,7 +472,7 @@ export class WhatsappDirectLine extends GBService {
|
|||
});
|
||||
|
||||
const sec = new SecService();
|
||||
const user = await sec.ensureUser(this.min.instance.instanceId, from, fromName, '', 'whatsapp', fromName, null);
|
||||
const user = await sec.ensureUser(this.min, from, fromName, '', 'whatsapp', fromName, null);
|
||||
const locale = user.locale ? user.locale : 'pt';
|
||||
|
||||
if (answerText) {
|
||||
|
@ -1083,7 +1083,7 @@ export class WhatsappDirectLine extends GBService {
|
|||
}
|
||||
const botId = getKeyByValue(WhatsappDirectLine.botGroups, group);
|
||||
if ((botId && user.instanceId !== this.min.instance.instanceId) || !user) {
|
||||
user = await sec.ensureUser(this.min.instance.instanceId, id, senderName, '', 'whatsApp', senderName, null);
|
||||
user = await sec.ensureUser(this.min, id, senderName, '', 'whatsApp', senderName, null);
|
||||
}
|
||||
if (botId) {
|
||||
activeMin = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||
|
@ -1122,7 +1122,7 @@ export class WhatsappDirectLine extends GBService {
|
|||
// start dialog if any is specified in Config.xlsx.
|
||||
|
||||
if (user === null || user.hearOnDialog) {
|
||||
user = await sec.ensureUser(activeMin.instance.instanceId, id, senderName, '', 'whatsapp', senderName, null);
|
||||
user = await sec.ensureUser(activeMin, id, senderName, '', 'whatsapp', senderName, null);
|
||||
|
||||
const startDialog = user.hearOnDialog
|
||||
? user.hearOnDialog
|
||||
|
|
Loading…
Add table
Reference in a new issue