@cobrowser/chatgpt 0.7.31-beta.4 → 0.7.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/models/ChatGPTMessage.d.ts +17 -0
- package/dist/models/ChatGPTMessage.js +9 -0
- package/dist/models/ChatGPTResponse.d.ts +1 -1
- package/dist/models/ConversationHistory.d.ts +3 -3
- package/dist/models/Item.d.ts +2 -2
- package/dist/models/Response.d.ts +3 -0
- package/dist/models/Response.js +2 -0
- package/dist/services/AssistantService/AssistantService.d.ts +1 -1
- package/dist/services/AssistantService/AssistantService.js +11 -9
- package/dist/services/BaseService/BaseService.d.ts +5 -8
- package/dist/services/BaseService/BaseService.js +15 -34
- package/dist/services/ChatService/ChatService.d.ts +2 -1
- package/dist/services/ChatService/ChatService.js +14 -9
- package/dist/services/CopilotService/CopilotService.d.ts +6 -15
- package/dist/services/CopilotService/CopilotService.js +29 -53
- package/dist/services/TranslationService/TranslationService.js +8 -9
- package/dist/utils/Response.d.ts +4 -0
- package/dist/utils/Response.js +11 -0
- package/dist/utils/constants.d.ts +13 -0
- package/dist/utils/constants.js +66 -0
- package/package.json +2 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare enum ChatGPTRole {
|
|
2
|
+
USER = "user",
|
|
3
|
+
SYSTEM = "system",
|
|
4
|
+
ASSISTANT = "assistant"
|
|
5
|
+
}
|
|
6
|
+
export interface ChatGPTRequestBody {
|
|
7
|
+
model: string;
|
|
8
|
+
response_format?: {
|
|
9
|
+
type: string;
|
|
10
|
+
};
|
|
11
|
+
messages: ChatGPTMessage[];
|
|
12
|
+
}
|
|
13
|
+
interface ChatGPTMessage {
|
|
14
|
+
role: ChatGPTRole;
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
export default ChatGPTMessage;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatGPTRole = void 0;
|
|
4
|
+
var ChatGPTRole;
|
|
5
|
+
(function (ChatGPTRole) {
|
|
6
|
+
ChatGPTRole["USER"] = "user";
|
|
7
|
+
ChatGPTRole["SYSTEM"] = "system";
|
|
8
|
+
ChatGPTRole["ASSISTANT"] = "assistant";
|
|
9
|
+
})(ChatGPTRole = exports.ChatGPTRole || (exports.ChatGPTRole = {}));
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
interface ConversationHistory {
|
|
2
|
-
from: string;
|
|
3
2
|
to: string;
|
|
4
|
-
|
|
3
|
+
from: string;
|
|
5
4
|
body: MessageBody[];
|
|
5
|
+
datetime: number;
|
|
6
6
|
}
|
|
7
7
|
interface MessageBody {
|
|
8
|
+
id?: string;
|
|
8
9
|
type: string;
|
|
9
10
|
text?: string;
|
|
10
|
-
id?: string;
|
|
11
11
|
label?: string;
|
|
12
12
|
}
|
|
13
13
|
export default ConversationHistory;
|
package/dist/models/Item.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AssistantResponseFormatOption } from 'openai/resources/beta/threads/threads';
|
|
2
|
-
import ChatGPTResponse from '../../models/ChatGPTResponse';
|
|
3
2
|
import BaseService from '../BaseService/BaseService';
|
|
3
|
+
import ChatGPTResponse from '../../models/ChatGPTResponse';
|
|
4
4
|
export declare class AssistantService extends BaseService {
|
|
5
5
|
assistantId: string | undefined;
|
|
6
6
|
threadId: string | undefined;
|
|
@@ -71,14 +71,16 @@ class AssistantService extends BaseService_1.default {
|
|
|
71
71
|
run = yield openai.beta.threads.runs.submitToolOutputsAndPoll(this.threadId, this.runId, { tool_outputs: JSON.parse(runOptions.functionOutputs) });
|
|
72
72
|
}
|
|
73
73
|
else {
|
|
74
|
-
const lastThreadMessasges = yield openai.beta.threads.messages.list(this.threadId, { order: "desc", limit: 2 });
|
|
75
|
-
const isRepeatedMessage = lastThreadMessasges.data.find(msg => msg.content[0].type === 'text' && msg.content[0].text.value === message);
|
|
74
|
+
const lastThreadMessasges = yield openai.beta.threads.messages.list(this.threadId, { order: "desc", limit: 2 }), isRepeatedMessage = lastThreadMessasges.data.find(msg => msg.content[0].type === 'text' && msg.content[0].text.value === message);
|
|
76
75
|
if (isRepeatedMessage) {
|
|
77
76
|
const runs = yield openai.beta.threads.runs.list(this.threadId, { order: "desc", limit: 1 });
|
|
78
77
|
run = runs.data[0];
|
|
79
78
|
}
|
|
80
79
|
else {
|
|
81
|
-
yield openai.beta.threads.messages.create(this.threadId, {
|
|
80
|
+
yield openai.beta.threads.messages.create(this.threadId, {
|
|
81
|
+
role: "user",
|
|
82
|
+
content: message
|
|
83
|
+
});
|
|
82
84
|
run = yield openai.beta.threads.runs.create(this.threadId, {
|
|
83
85
|
assistant_id: (_a = this.assistantId) !== null && _a !== void 0 ? _a : '',
|
|
84
86
|
additional_instructions: runOptions.instructions,
|
|
@@ -95,13 +97,13 @@ class AssistantService extends BaseService_1.default {
|
|
|
95
97
|
run = yield openai.beta.threads.runs.retrieve(run.thread_id, run.id);
|
|
96
98
|
}
|
|
97
99
|
if (run.status === 'completed') {
|
|
98
|
-
const { data } = yield openai.beta.threads.messages.list(run.thread_id, { order: 'desc', limit: 1 });
|
|
99
|
-
const messages = data.flatMap((message) => message === null || message === void 0 ? void 0 : message.content.map((content) => ((content.type === 'text' && message.role === 'assistant') ? content.text : '')));
|
|
100
|
-
const assistantMessages = messages.filter(message => typeof message === 'object' && 'value' in message && typeof message.value === 'string');
|
|
100
|
+
const { data } = yield openai.beta.threads.messages.list(run.thread_id, { order: 'desc', limit: 1 }), messages = data.flatMap((message) => message === null || message === void 0 ? void 0 : message.content.map((content) => ((content.type === 'text' && message.role === 'assistant') ? content.text : ''))), assistantMessages = messages.filter(message => typeof message === 'object' && 'value' in message && typeof message.value === 'string');
|
|
101
101
|
if (assistantMessages.length) {
|
|
102
|
-
|
|
102
|
+
// as we will always get one message (limit = 1 from desc order),
|
|
103
|
+
// we can just directly access the message here
|
|
104
|
+
const answer = assistantMessages[0].value, replaced = answer.replace(/【.*?】/g, ''), parsed = JSON.parse(replaced);
|
|
103
105
|
return {
|
|
104
|
-
data:
|
|
106
|
+
data: parsed,
|
|
105
107
|
threadId: run.thread_id,
|
|
106
108
|
usageTokens: run.usage,
|
|
107
109
|
};
|
|
@@ -109,7 +111,7 @@ class AssistantService extends BaseService_1.default {
|
|
|
109
111
|
}
|
|
110
112
|
if (run.status === 'requires_action') {
|
|
111
113
|
return {
|
|
112
|
-
requiredActions:
|
|
114
|
+
requiredActions: run.required_action,
|
|
113
115
|
threadId: run.thread_id,
|
|
114
116
|
usageTokens: run.usage,
|
|
115
117
|
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
|
2
2
|
import ChatGPTUsageTokens from '../../models/ChatGPTUsageTokens';
|
|
3
|
-
interface Response<Data = any> {
|
|
4
|
-
result: Data;
|
|
5
|
-
}
|
|
6
3
|
declare class BaseService {
|
|
7
4
|
readonly BASE_CHAT_COMPLETION_URL = "https://api.openai.com/v1/chat/completions";
|
|
8
5
|
request: AxiosInstance;
|
|
@@ -17,19 +14,20 @@ declare class BaseService {
|
|
|
17
14
|
*/
|
|
18
15
|
constructor(apiKey?: string | undefined, model?: string, apiUrl?: string, maxNumberOfChoices?: number);
|
|
19
16
|
/**
|
|
20
|
-
* Automatically wraps
|
|
21
|
-
*
|
|
17
|
+
* Automatically wraps some specific async methods to return a specific sanitized
|
|
18
|
+
* and encoded JSON without any developer intervention.
|
|
22
19
|
*/
|
|
23
20
|
private processAsyncMethods;
|
|
24
21
|
/**
|
|
25
22
|
* Recursively sanitizes any value
|
|
26
23
|
*/
|
|
27
|
-
private
|
|
24
|
+
private sanitize;
|
|
28
25
|
/**
|
|
29
26
|
* Filter the response from chatGpt API and only get the first choice
|
|
27
|
+
*
|
|
30
28
|
* @param response
|
|
31
29
|
*/
|
|
32
|
-
getResponseFirstChoice(response: AxiosResponse):
|
|
30
|
+
getResponseFirstChoice(response: AxiosResponse): any;
|
|
33
31
|
/**
|
|
34
32
|
* Filter the response from chatGpt API and get the usage tokens
|
|
35
33
|
* @param response
|
|
@@ -40,6 +38,5 @@ declare class BaseService {
|
|
|
40
38
|
* @param error
|
|
41
39
|
*/
|
|
42
40
|
handleErrors(error: AxiosError): void;
|
|
43
|
-
protected response<Data>(data: Data): Response<Data>;
|
|
44
41
|
}
|
|
45
42
|
export default BaseService;
|
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const axios_1 = __importDefault(require("axios"));
|
|
16
|
+
const Response_1 = require("../../utils/Response");
|
|
16
17
|
const xss_validation_1 = require("@cobrowser/xss-validation");
|
|
17
18
|
const logger_1 = __importDefault(require("../logger"));
|
|
18
19
|
class BaseService {
|
|
@@ -63,42 +64,37 @@ class BaseService {
|
|
|
63
64
|
this.openaiApiKey = apiKey;
|
|
64
65
|
this.chatGptModel = model;
|
|
65
66
|
this.maxNumberOfChatCompletionResult = maxNumberOfChoices;
|
|
66
|
-
// Automatically wrap all async methods that return ChatGpt responses
|
|
67
67
|
this.processAsyncMethods();
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* Automatically wraps
|
|
71
|
-
*
|
|
70
|
+
* Automatically wraps some specific async methods to return a specific sanitized
|
|
71
|
+
* and encoded JSON without any developer intervention.
|
|
72
72
|
*/
|
|
73
73
|
processAsyncMethods() {
|
|
74
74
|
const proto = Object.getPrototypeOf(this), methodNames = Object.getOwnPropertyNames(proto);
|
|
75
|
-
console.log('BASE SERVICE processAsyncMethods methodNames: ', methodNames);
|
|
76
75
|
for (const methodName of methodNames) {
|
|
77
76
|
const method = proto[methodName];
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
//
|
|
77
|
+
// Skip constructor, non-functions, and utility methods But include service methods
|
|
78
|
+
// like getReply, getAssistant, etc. Please note that new methods that are not final
|
|
79
|
+
// output should be skipped here.
|
|
81
80
|
if (methodName === 'constructor' ||
|
|
82
81
|
methodName === 'suggest' ||
|
|
83
82
|
typeof method !== 'function' ||
|
|
84
83
|
(methodName.startsWith('get') &&
|
|
85
84
|
!methodName.startsWith('getReply') &&
|
|
86
85
|
!methodName.startsWith('getAssist') &&
|
|
87
|
-
!methodName.startsWith('
|
|
86
|
+
!methodName.startsWith('getChat')) ||
|
|
88
87
|
methodName.startsWith('handle') ||
|
|
89
88
|
methodName.includes('Sanitize') ||
|
|
90
89
|
methodName.includes('sanitize')) {
|
|
91
90
|
continue;
|
|
92
91
|
}
|
|
93
92
|
const originalMethod = method.bind(this);
|
|
94
|
-
|
|
95
|
-
// Replace the method with a sanitizing wrapper
|
|
93
|
+
// Replace the method with a wrapper
|
|
96
94
|
this[methodName] = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
97
|
-
console.log('WRAPPER args: ', args);
|
|
98
95
|
try {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
return sanitizedResult;
|
|
96
|
+
const response = Response_1.ResponseBuilder.build(yield originalMethod(...args)), sanitized = this.sanitize(response);
|
|
97
|
+
return sanitized;
|
|
102
98
|
}
|
|
103
99
|
catch (error) {
|
|
104
100
|
throw error;
|
|
@@ -109,27 +105,17 @@ class BaseService {
|
|
|
109
105
|
/**
|
|
110
106
|
* Recursively sanitizes any value
|
|
111
107
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!value) {
|
|
108
|
+
sanitize(data) {
|
|
109
|
+
if (!data) {
|
|
115
110
|
return;
|
|
116
111
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
value = JSON.parse(value);
|
|
121
|
-
}
|
|
122
|
-
catch (error) { }
|
|
123
|
-
}
|
|
124
|
-
const sanitized = xss_validation_1.XSSProtector.sanitize(value), encoded = xss_validation_1.XSSProtector.encode(sanitized);
|
|
125
|
-
console.log('BASE SERVICE clean sanitized aaaaa: ', sanitized);
|
|
126
|
-
console.log('BASE SERVICE clean encoded: ', encoded);
|
|
127
|
-
console.log('BASE SERVICE clean encoded data: ', encoded.result.data);
|
|
128
|
-
logger_1.default.info({ value, sanitized, encoded }, ':: Sanitized Response ::');
|
|
112
|
+
const sanitized = xss_validation_1.XSSProtector.sanitize(data), encoded = xss_validation_1.XSSProtector.encode(sanitized);
|
|
113
|
+
logger_1.default.info({ data, sanitized, encoded }, ':: Sanitized Response ::');
|
|
129
114
|
return encoded;
|
|
130
115
|
}
|
|
131
116
|
/**
|
|
132
117
|
* Filter the response from chatGpt API and only get the first choice
|
|
118
|
+
*
|
|
133
119
|
* @param response
|
|
134
120
|
*/
|
|
135
121
|
getResponseFirstChoice(response) {
|
|
@@ -171,10 +157,5 @@ class BaseService {
|
|
|
171
157
|
}
|
|
172
158
|
logger_1.default.error(`error message ${error.message}`);
|
|
173
159
|
}
|
|
174
|
-
response(data) {
|
|
175
|
-
return {
|
|
176
|
-
result: data,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
160
|
}
|
|
180
161
|
exports.default = BaseService;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import BaseService from '../BaseService/BaseService';
|
|
2
|
+
import ChatGPTResponse from 'src/models/ChatGPTResponse';
|
|
2
3
|
import ConversationHistory from 'src/models/ConversationHistory';
|
|
3
4
|
export declare class ChatService extends BaseService {
|
|
4
5
|
#private;
|
|
5
6
|
model: string | undefined;
|
|
6
7
|
constructor(apiKey?: string, model?: string, apiUrl?: string, maxNumberOfChoices?: number);
|
|
7
|
-
ask(context: string | undefined, conversationHistory: ConversationHistory[]): Promise<
|
|
8
|
+
ask(context: string | undefined, conversationHistory: ConversationHistory[]): Promise<ChatGPTResponse | undefined>;
|
|
8
9
|
}
|
|
@@ -19,10 +19,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
var _ChatService_instances, _ChatService_formatConversationHistory;
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.ChatService = void 0;
|
|
22
|
-
const
|
|
23
|
-
const
|
|
22
|
+
const ChatGPTMessage_1 = require("../../models/ChatGPTMessage");
|
|
23
|
+
const constants_1 = require("../../utils/constants");
|
|
24
24
|
const logger_1 = __importDefault(require("../logger"));
|
|
25
|
-
const
|
|
25
|
+
const BaseService_1 = __importDefault(require("../BaseService/BaseService"));
|
|
26
26
|
class ChatService extends BaseService_1.default {
|
|
27
27
|
constructor(apiKey, model, apiUrl, maxNumberOfChoices) {
|
|
28
28
|
super(apiKey, model, apiUrl, maxNumberOfChoices);
|
|
@@ -45,10 +45,15 @@ class ChatService extends BaseService_1.default {
|
|
|
45
45
|
model: this.model,
|
|
46
46
|
messages: __classPrivateFieldGet(this, _ChatService_instances, "m", _ChatService_formatConversationHistory).call(this, context, conversationHistory),
|
|
47
47
|
};
|
|
48
|
-
logger_1.default.info(
|
|
48
|
+
logger_1.default.info({
|
|
49
|
+
requestBody: JSON.stringify(requestBody)
|
|
50
|
+
}, ':: ChatService.ask :: Request Body');
|
|
49
51
|
try {
|
|
50
52
|
const response = yield this.request.post('', requestBody);
|
|
51
|
-
return
|
|
53
|
+
return {
|
|
54
|
+
data: this.getResponseFirstChoice(response),
|
|
55
|
+
usageTokens: this.getResponseUsageTokens(response),
|
|
56
|
+
};
|
|
52
57
|
}
|
|
53
58
|
catch (e) {
|
|
54
59
|
this.handleErrors(e);
|
|
@@ -61,7 +66,7 @@ exports.ChatService = ChatService;
|
|
|
61
66
|
_ChatService_instances = new WeakSet(), _ChatService_formatConversationHistory = function _ChatService_formatConversationHistory(context, conversationHistory) {
|
|
62
67
|
const formatted = [
|
|
63
68
|
{
|
|
64
|
-
role:
|
|
69
|
+
role: ChatGPTMessage_1.ChatGPTRole.SYSTEM,
|
|
65
70
|
content: context || constants_1.DEFAULT_PROMPT,
|
|
66
71
|
}
|
|
67
72
|
];
|
|
@@ -71,19 +76,19 @@ _ChatService_instances = new WeakSet(), _ChatService_formatConversationHistory =
|
|
|
71
76
|
for (const body of messageBody) {
|
|
72
77
|
if (body.type === constants_1.MESSAGE_TYPES.text && message.from === constants_1.MESSAGE_SENDER.visitor) {
|
|
73
78
|
formatted.push({
|
|
74
|
-
role:
|
|
79
|
+
role: ChatGPTMessage_1.ChatGPTRole.USER,
|
|
75
80
|
content: body.text
|
|
76
81
|
});
|
|
77
82
|
}
|
|
78
83
|
else if (body.type === constants_1.MESSAGE_TYPES.text && message.from === constants_1.MESSAGE_SENDER.chatbot) {
|
|
79
84
|
formatted.push({
|
|
80
|
-
role:
|
|
85
|
+
role: ChatGPTMessage_1.ChatGPTRole.ASSISTANT,
|
|
81
86
|
content: body.text
|
|
82
87
|
});
|
|
83
88
|
}
|
|
84
89
|
else if (body.type === constants_1.MESSAGE_TYPES.button && message.from === constants_1.MESSAGE_SENDER.chatbot) {
|
|
85
90
|
formatted.push({
|
|
86
|
-
role:
|
|
91
|
+
role: ChatGPTMessage_1.ChatGPTRole.ASSISTANT,
|
|
87
92
|
content: body.label
|
|
88
93
|
});
|
|
89
94
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import ChatGptMessage from '../../models/ChatGptMessage';
|
|
2
|
-
import Item from '../../models/Item';
|
|
3
1
|
import BaseService from '../BaseService/BaseService';
|
|
4
2
|
import ChatGPTResponse from '../../models/ChatGPTResponse';
|
|
5
|
-
import ChatGPTUsageTokens from 'src/models/ChatGPTUsageTokens';
|
|
6
3
|
export declare class CopilotService extends BaseService {
|
|
4
|
+
#private;
|
|
7
5
|
assistantId: string | undefined;
|
|
8
6
|
threadId: string | undefined;
|
|
9
7
|
constructor(apiKey?: string, model?: string, assistantId?: string, threadId?: string, apiUrl?: string, maxNumberOfChoices?: number);
|
|
@@ -21,22 +19,15 @@ export declare class CopilotService extends BaseService {
|
|
|
21
19
|
*/
|
|
22
20
|
suggest(conversation: string): Promise<ChatGPTResponse | undefined>;
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
22
|
+
* Get suggestions from Chat Completion API.
|
|
23
|
+
*
|
|
24
|
+
* @param message
|
|
27
25
|
*/
|
|
28
|
-
|
|
29
|
-
data: string | undefined;
|
|
30
|
-
usageTokens: ChatGPTUsageTokens | undefined;
|
|
31
|
-
}>;
|
|
32
|
-
getChatGPTQuickReplies(conversation: string): Promise<{
|
|
33
|
-
data: string | undefined;
|
|
34
|
-
usageTokens: ChatGPTUsageTokens | undefined;
|
|
35
|
-
}>;
|
|
26
|
+
getChatCompletionSuggestions(conversation: string): Promise<ChatGPTResponse | undefined>;
|
|
36
27
|
/**
|
|
37
28
|
* Get the reply of the assistant if the assistant_id is available
|
|
38
29
|
*
|
|
39
30
|
* @param message
|
|
40
31
|
*/
|
|
41
|
-
|
|
32
|
+
getAssistantSuggestions(conversation: string): Promise<ChatGPTResponse | undefined>;
|
|
42
33
|
}
|
|
@@ -8,18 +8,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
13
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
14
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
15
|
+
};
|
|
11
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
18
|
};
|
|
19
|
+
var _CopilotService_instances, _CopilotService_processSuggestions;
|
|
14
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
21
|
exports.CopilotService = void 0;
|
|
16
|
-
const
|
|
22
|
+
const ChatGPTMessage_1 = require("../../models/ChatGPTMessage");
|
|
17
23
|
const logger_1 = __importDefault(require("../logger"));
|
|
18
24
|
const openai_1 = __importDefault(require("openai"));
|
|
19
25
|
const BaseService_1 = __importDefault(require("../BaseService/BaseService"));
|
|
20
26
|
class CopilotService extends BaseService_1.default {
|
|
21
27
|
constructor(apiKey, model, assistantId, threadId, apiUrl, maxNumberOfChoices) {
|
|
22
28
|
super(apiKey, model, apiUrl, maxNumberOfChoices);
|
|
29
|
+
_CopilotService_instances.add(this);
|
|
23
30
|
Object.defineProperty(this, "assistantId", {
|
|
24
31
|
enumerable: true,
|
|
25
32
|
configurable: true,
|
|
@@ -34,7 +41,6 @@ class CopilotService extends BaseService_1.default {
|
|
|
34
41
|
});
|
|
35
42
|
this.assistantId = assistantId;
|
|
36
43
|
this.threadId = threadId;
|
|
37
|
-
console.log('API URL: ', apiUrl);
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
46
|
* a method to be used to suggest some quick replies for the agent based on the conversation
|
|
@@ -50,17 +56,15 @@ class CopilotService extends BaseService_1.default {
|
|
|
50
56
|
*/
|
|
51
57
|
suggest(conversation) {
|
|
52
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
console.log('SUGGEST conversation: ', conversation);
|
|
54
59
|
if (!(conversation === null || conversation === void 0 ? void 0 : conversation.length)) {
|
|
55
60
|
logger_1.default.error('Conversation must be provided');
|
|
56
61
|
return Promise.reject(new Error('Conversation must be provided'));
|
|
57
62
|
}
|
|
58
63
|
try {
|
|
59
64
|
if (this.assistantId) {
|
|
60
|
-
return yield this.
|
|
65
|
+
return yield this.getAssistantSuggestions(conversation);
|
|
61
66
|
}
|
|
62
|
-
|
|
63
|
-
return yield this.getChatGPTQuickReplies(conversation);
|
|
67
|
+
return yield this.getChatCompletionSuggestions(conversation);
|
|
64
68
|
}
|
|
65
69
|
catch (e) {
|
|
66
70
|
this.handleErrors(e);
|
|
@@ -69,49 +73,19 @@ class CopilotService extends BaseService_1.default {
|
|
|
69
73
|
});
|
|
70
74
|
}
|
|
71
75
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* @param
|
|
76
|
+
* Get suggestions from Chat Completion API.
|
|
77
|
+
*
|
|
78
|
+
* @param message
|
|
75
79
|
*/
|
|
76
|
-
|
|
77
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
-
if (!(items === null || items === void 0 ? void 0 : items.length) || !(conversation === null || conversation === void 0 ? void 0 : conversation.length)) {
|
|
79
|
-
logger_1.default.error('conversation or items not found');
|
|
80
|
-
return Promise.reject(new Error('conversation and items must be provided'));
|
|
81
|
-
}
|
|
82
|
-
try {
|
|
83
|
-
// main prompt used to instruct chatGPT to recommend products
|
|
84
|
-
const mainPrompt = `we have this list of Items: ${JSON.stringify(items)}, what to recommend for you`,
|
|
85
|
-
// main prompt will be the first message of the whole conversation
|
|
86
|
-
firstMessage = {
|
|
87
|
-
role: ChatGptMessage_1.ChatGptRole.ASSISTANT,
|
|
88
|
-
content: mainPrompt,
|
|
89
|
-
},
|
|
90
|
-
// the body we need to send to the request
|
|
91
|
-
requestBody = {
|
|
92
|
-
model: this.chatGptModel,
|
|
93
|
-
messages: [firstMessage, ...conversation],
|
|
94
|
-
}, response = yield this.request.post('', requestBody);
|
|
95
|
-
return {
|
|
96
|
-
data: this.getResponseFirstChoice(response),
|
|
97
|
-
usageTokens: this.getResponseUsageTokens(response),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
this.handleErrors(e);
|
|
102
|
-
return Promise.reject(e);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
getChatGPTQuickReplies(conversation) {
|
|
80
|
+
getChatCompletionSuggestions(conversation) {
|
|
107
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
108
82
|
// main prompt used to instruct chatGPT to suggest some quick replies
|
|
109
83
|
const mainPrompt = `Propose some quick replies for the agent to be used on the following conversation
|
|
110
|
-
|
|
111
|
-
|
|
84
|
+
Your response must only contains a valid JSON array of strings like this:
|
|
85
|
+
["Reply 1", "Reply 2", "Reply 3"]. the conversation is:-\n${conversation}`,
|
|
112
86
|
// main prompt will be the whole conversation as string
|
|
113
87
|
mainPromptMessage = {
|
|
114
|
-
role:
|
|
88
|
+
role: ChatGPTMessage_1.ChatGPTRole.USER,
|
|
115
89
|
content: mainPrompt,
|
|
116
90
|
},
|
|
117
91
|
// the body we need to send to the request
|
|
@@ -120,7 +94,7 @@ class CopilotService extends BaseService_1.default {
|
|
|
120
94
|
messages: [mainPromptMessage],
|
|
121
95
|
}, response = yield this.request.post('', requestBody);
|
|
122
96
|
return {
|
|
123
|
-
data: this.getResponseFirstChoice(response),
|
|
97
|
+
data: __classPrivateFieldGet(this, _CopilotService_instances, "m", _CopilotService_processSuggestions).call(this, this.getResponseFirstChoice(response)),
|
|
124
98
|
usageTokens: this.getResponseUsageTokens(response),
|
|
125
99
|
};
|
|
126
100
|
});
|
|
@@ -130,16 +104,15 @@ class CopilotService extends BaseService_1.default {
|
|
|
130
104
|
*
|
|
131
105
|
* @param message
|
|
132
106
|
*/
|
|
133
|
-
|
|
107
|
+
getAssistantSuggestions(conversation) {
|
|
134
108
|
var _a;
|
|
135
109
|
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
-
console.log('getAssistantReply conversation: ', conversation);
|
|
137
110
|
// Here we get the last customer message as we dont need the whole conversation
|
|
138
|
-
// as we are doing with the other approach
|
|
111
|
+
// as we are doing with the other approach.
|
|
139
112
|
const conversationArray = conversation.split('\n'), lastCustomerMessage = conversationArray.reverse().find(e => e.includes('customer:'));
|
|
140
113
|
if (!lastCustomerMessage) {
|
|
141
|
-
logger_1.default.error('
|
|
142
|
-
return Promise.reject(new Error('
|
|
114
|
+
logger_1.default.error('Last customer message not found');
|
|
115
|
+
return Promise.reject(new Error('Last customer message not found'));
|
|
143
116
|
}
|
|
144
117
|
const openai = new openai_1.default({ apiKey: this.openaiApiKey });
|
|
145
118
|
let run;
|
|
@@ -163,12 +136,10 @@ class CopilotService extends BaseService_1.default {
|
|
|
163
136
|
}
|
|
164
137
|
if (run.status === 'completed') {
|
|
165
138
|
const { data } = yield openai.beta.threads.messages.list(run.thread_id, { order: 'desc', limit: 1 }), messages = data.flatMap((message) => message === null || message === void 0 ? void 0 : message.content.map((content) => ((content.type === 'text' && message.role === 'assistant') ? content.text : ''))), assistantMessages = messages.filter(message => typeof message === 'object' && 'value' in message && typeof message.value === 'string');
|
|
166
|
-
console.log('GET ASSISTANT REPLY assistantMessages: ', assistantMessages);
|
|
167
139
|
if (assistantMessages.length) {
|
|
168
|
-
|
|
169
|
-
console.log('GET ASSISTANT REPLY answers: ', answers);
|
|
140
|
+
const answers = assistantMessages.map(message => message.value);
|
|
170
141
|
return {
|
|
171
|
-
data: answers,
|
|
142
|
+
data: __classPrivateFieldGet(this, _CopilotService_instances, "m", _CopilotService_processSuggestions).call(this, answers),
|
|
172
143
|
threadId: run.thread_id,
|
|
173
144
|
usageTokens: run.usage,
|
|
174
145
|
};
|
|
@@ -179,3 +150,8 @@ class CopilotService extends BaseService_1.default {
|
|
|
179
150
|
}
|
|
180
151
|
}
|
|
181
152
|
exports.CopilotService = CopilotService;
|
|
153
|
+
_CopilotService_instances = new WeakSet(), _CopilotService_processSuggestions = function _CopilotService_processSuggestions(suggestions) {
|
|
154
|
+
suggestions = suggestions ? suggestions : [];
|
|
155
|
+
suggestions = suggestions.filter(suggestion => !!suggestion.trim());
|
|
156
|
+
return suggestions;
|
|
157
|
+
};
|
|
@@ -13,8 +13,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.TranslationService = void 0;
|
|
16
|
-
const constants_1 = require("../../constants");
|
|
17
|
-
const
|
|
16
|
+
const constants_1 = require("../../utils/constants");
|
|
17
|
+
const ChatGPTMessage_1 = require("../../models/ChatGPTMessage");
|
|
18
18
|
const logger_1 = __importDefault(require("../logger"));
|
|
19
19
|
const BaseService_1 = __importDefault(require("../BaseService/BaseService"));
|
|
20
20
|
class TranslationService extends BaseService_1.default {
|
|
@@ -42,11 +42,11 @@ class TranslationService extends BaseService_1.default {
|
|
|
42
42
|
response_format: { type: 'json_object' },
|
|
43
43
|
messages: [
|
|
44
44
|
{
|
|
45
|
-
role:
|
|
45
|
+
role: ChatGPTMessage_1.ChatGPTRole.SYSTEM,
|
|
46
46
|
content: constants_1.TRANSLATION_SYSTEM_ROLE,
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
role:
|
|
49
|
+
role: ChatGPTMessage_1.ChatGPTRole.USER,
|
|
50
50
|
content: translateText,
|
|
51
51
|
},
|
|
52
52
|
],
|
|
@@ -58,7 +58,6 @@ class TranslationService extends BaseService_1.default {
|
|
|
58
58
|
data: this.getResponseFirstChoice(response),
|
|
59
59
|
usageTokens: this.getResponseUsageTokens(response),
|
|
60
60
|
};
|
|
61
|
-
// return response.data;
|
|
62
61
|
}
|
|
63
62
|
catch (e) {
|
|
64
63
|
this.handleErrors(e);
|
|
@@ -82,11 +81,11 @@ class TranslationService extends BaseService_1.default {
|
|
|
82
81
|
response_format: { type: 'json_object' },
|
|
83
82
|
messages: [
|
|
84
83
|
{
|
|
85
|
-
role:
|
|
84
|
+
role: ChatGPTMessage_1.ChatGPTRole.SYSTEM,
|
|
86
85
|
content: constants_1.LANGUAGE_DETECTION_SYSTEM_ROLE,
|
|
87
86
|
},
|
|
88
87
|
{
|
|
89
|
-
role:
|
|
88
|
+
role: ChatGPTMessage_1.ChatGPTRole.USER,
|
|
90
89
|
content: translateText,
|
|
91
90
|
}
|
|
92
91
|
],
|
|
@@ -121,11 +120,11 @@ class TranslationService extends BaseService_1.default {
|
|
|
121
120
|
response_format: { type: 'json_object' },
|
|
122
121
|
messages: [
|
|
123
122
|
{
|
|
124
|
-
role:
|
|
123
|
+
role: ChatGPTMessage_1.ChatGPTRole.SYSTEM,
|
|
125
124
|
content: constants_1.WORD_FREQUENCY_LANGUAGE_DETECTION_SYSTEM_ROLE,
|
|
126
125
|
},
|
|
127
126
|
{
|
|
128
|
-
role:
|
|
127
|
+
role: ChatGPTMessage_1.ChatGPTRole.USER,
|
|
129
128
|
content: translateText,
|
|
130
129
|
}
|
|
131
130
|
],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const MESSAGE_SENDER: {
|
|
2
|
+
visitor: string;
|
|
3
|
+
chatbot: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const MESSAGE_TYPES: {
|
|
6
|
+
text: string;
|
|
7
|
+
button: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const DEFAULT_PROMPT = "\n You are a helpful assistant. Your role is to address visitor \n queries related to the ongoing conversation and the last message received. Please ensure \n that responses remain within the ongoing conversation. Politely decline any user queries \n that is not present in the ongoing conversation. \n\n You will always respond with a JSON. It will be in the format: \n\n { answer: '', suggestions: [], connectWithAgent: true or false }\n\n Fields in the JSON:\n\n Answer: It will consist of the user's query answer based on the ongoing conversation. \n Restrict this field to 100 characters.\n\n Suggestions: Request 2 suggestions from user's perspective that he can ask. \n It should be an array of strings. Restrict each suggestion to 50 characters.\n \n ConnectWithAgent: It is a boolean. It should be set to true if the user's query is \n not found in the ongoing conversation. Politely tell the user to talk to a real agent. \n Also when it is true, do not provide any suggestions.\n";
|
|
10
|
+
export declare const DESTINATION_LANGUAGE = "English";
|
|
11
|
+
export declare const LANGUAGE_DETECTION_SYSTEM_ROLE = "\n You are a language detection assistant. Your task is to analyze short text input and determine \n its language using ISO language code. Respond only in JSON format with two key-value pairs: \n - 'languageCode': the detected language's ISO code (or undefined if detection fails).\n - 'isError': a boolean value (true if detection fails, false otherwise).\n";
|
|
12
|
+
export declare const WORD_FREQUENCY_LANGUAGE_DETECTION_SYSTEM_ROLE = "\n You are a language detection assistant. Your task is to analyze the most frequently occurring words in the given text \n and determine the language based on those words. Respond only in JSON format with two key-value pairs: \n - 'languageCode': the detected language's ISO code (or undefined if detection fails).\n - 'isError': a boolean value (true if detection fails, false otherwise).\n";
|
|
13
|
+
export declare const TRANSLATION_SYSTEM_ROLE = "\n You are a translator that responds exclusively in JSON format. Your response must be a JSON object containing:\n - 'translations': it is an array of objects. Each object in the array must contain:\n - 'original': The original input message before translation.\n - 'translation: The translated version of 'original', ensuring it is natural, culturally appropriate, and commonly used by native speakers.\n - 'isError': a boolean value (true if translation fails, false otherwise).\n\n **You MUST return the JSON format even if you fail to translate the text. In this case, translations field will be empty array and isError should be true.** \n\n Ensure that 'translation' accurately represents the meaning of 'original' while considering cultural nuances, usual expressions, and natural phrasing in the target language.\n\n Your response must follow this structure strictly.\n";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TRANSLATION_SYSTEM_ROLE = exports.WORD_FREQUENCY_LANGUAGE_DETECTION_SYSTEM_ROLE = exports.LANGUAGE_DETECTION_SYSTEM_ROLE = exports.DESTINATION_LANGUAGE = exports.DEFAULT_PROMPT = exports.MESSAGE_TYPES = exports.MESSAGE_SENDER = void 0;
|
|
4
|
+
// Message sender in conversation history
|
|
5
|
+
exports.MESSAGE_SENDER = {
|
|
6
|
+
visitor: 'visitor',
|
|
7
|
+
chatbot: 'chatbot'
|
|
8
|
+
};
|
|
9
|
+
// Message types in conversation history
|
|
10
|
+
exports.MESSAGE_TYPES = {
|
|
11
|
+
text: 'text',
|
|
12
|
+
button: 'button'
|
|
13
|
+
};
|
|
14
|
+
// Default prompt for ChatGPT
|
|
15
|
+
exports.DEFAULT_PROMPT = `
|
|
16
|
+
You are a helpful assistant. Your role is to address visitor
|
|
17
|
+
queries related to the ongoing conversation and the last message received. Please ensure
|
|
18
|
+
that responses remain within the ongoing conversation. Politely decline any user queries
|
|
19
|
+
that is not present in the ongoing conversation.
|
|
20
|
+
|
|
21
|
+
You will always respond with a JSON. It will be in the format:
|
|
22
|
+
|
|
23
|
+
{ answer: '', suggestions: [], connectWithAgent: true or false }
|
|
24
|
+
|
|
25
|
+
Fields in the JSON:
|
|
26
|
+
|
|
27
|
+
Answer: It will consist of the user's query answer based on the ongoing conversation.
|
|
28
|
+
Restrict this field to 100 characters.
|
|
29
|
+
|
|
30
|
+
Suggestions: Request 2 suggestions from user's perspective that he can ask.
|
|
31
|
+
It should be an array of strings. Restrict each suggestion to 50 characters.
|
|
32
|
+
|
|
33
|
+
ConnectWithAgent: It is a boolean. It should be set to true if the user's query is
|
|
34
|
+
not found in the ongoing conversation. Politely tell the user to talk to a real agent.
|
|
35
|
+
Also when it is true, do not provide any suggestions.
|
|
36
|
+
`;
|
|
37
|
+
// Default destination language
|
|
38
|
+
exports.DESTINATION_LANGUAGE = 'English';
|
|
39
|
+
// Language detection system role
|
|
40
|
+
exports.LANGUAGE_DETECTION_SYSTEM_ROLE = `
|
|
41
|
+
You are a language detection assistant. Your task is to analyze short text input and determine
|
|
42
|
+
its language using ISO language code. Respond only in JSON format with two key-value pairs:
|
|
43
|
+
- 'languageCode': the detected language's ISO code (or undefined if detection fails).
|
|
44
|
+
- 'isError': a boolean value (true if detection fails, false otherwise).
|
|
45
|
+
`;
|
|
46
|
+
// Word frequency language detection system role
|
|
47
|
+
exports.WORD_FREQUENCY_LANGUAGE_DETECTION_SYSTEM_ROLE = `
|
|
48
|
+
You are a language detection assistant. Your task is to analyze the most frequently occurring words in the given text
|
|
49
|
+
and determine the language based on those words. Respond only in JSON format with two key-value pairs:
|
|
50
|
+
- 'languageCode': the detected language's ISO code (or undefined if detection fails).
|
|
51
|
+
- 'isError': a boolean value (true if detection fails, false otherwise).
|
|
52
|
+
`;
|
|
53
|
+
// Message translation system role
|
|
54
|
+
exports.TRANSLATION_SYSTEM_ROLE = `
|
|
55
|
+
You are a translator that responds exclusively in JSON format. Your response must be a JSON object containing:
|
|
56
|
+
- 'translations': it is an array of objects. Each object in the array must contain:
|
|
57
|
+
- 'original': The original input message before translation.
|
|
58
|
+
- 'translation: The translated version of 'original', ensuring it is natural, culturally appropriate, and commonly used by native speakers.
|
|
59
|
+
- 'isError': a boolean value (true if translation fails, false otherwise).
|
|
60
|
+
|
|
61
|
+
**You MUST return the JSON format even if you fail to translate the text. In this case, translations field will be empty array and isError should be true.**
|
|
62
|
+
|
|
63
|
+
Ensure that 'translation' accurately represents the meaning of 'original' while considering cultural nuances, usual expressions, and natural phrasing in the target language.
|
|
64
|
+
|
|
65
|
+
Your response must follow this structure strictly.
|
|
66
|
+
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cobrowser/chatgpt",
|
|
3
|
-
"version": "0.7.31
|
|
3
|
+
"version": "0.7.31",
|
|
4
4
|
"description": "chatgpt services to connect our projects with chatgpt api",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatgpt",
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"bugs": {
|
|
41
41
|
"url": "https://bitbucket.org/cobrowser/cb_utils/issues"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "c2ef648926a3c8ba2325c3964079abc2694af5ea"
|
|
44
44
|
}
|