2023-05-31 16:10:53 +08:00
|
|
|
import DevChat, { ChatResponse } from '../toolwrapper/devchat';
|
|
|
|
import CommandManager from '../command/commandManager';
|
|
|
|
import { logger } from '../util/logger';
|
|
|
|
import messageHistory from '../util/messageHistory';
|
|
|
|
import { TopicManager } from '../topic/topicManager';
|
|
|
|
import CustomCommands from '../command/customCommand';
|
|
|
|
|
2023-07-24 00:11:56 +08:00
|
|
|
|
|
|
|
let waitCreateTopic = false;
|
2023-06-05 11:36:45 +08:00
|
|
|
|
2023-06-06 10:35:32 +08:00
|
|
|
|
|
|
|
function parseDateStringToTimestamp(dateString: string): number {
|
|
|
|
const dateS = Date.parse(dateString);
|
|
|
|
if (!isNaN(dateS)) {
|
|
|
|
return dateS;
|
|
|
|
}
|
|
|
|
|
|
|
|
const formattedDateString = dateString
|
|
|
|
.replace(/^[A-Za-z]{3} /, '')
|
|
|
|
.replace(/ /, 'T')
|
|
|
|
.replace(/(\d{4}) (\+\d{4})$/, '$1$2');
|
|
|
|
|
|
|
|
const date = new Date(formattedDateString);
|
|
|
|
return date.getTime();
|
|
|
|
}
|
|
|
|
|
2023-06-05 11:36:45 +08:00
|
|
|
export function getWaitCreateTopic(): boolean {
|
2023-07-24 00:11:56 +08:00
|
|
|
return waitCreateTopic;
|
2023-06-05 11:36:45 +08:00
|
|
|
}
|
2023-05-31 16:10:53 +08:00
|
|
|
|
|
|
|
// Add this function to messageHandler.ts
|
2023-05-31 16:10:53 +08:00
|
|
|
export function parseMessage(message: string): { context: string[]; instruction: string[]; reference: string[]; text: string } {
|
2023-05-31 16:10:53 +08:00
|
|
|
const contextRegex = /\[context\|(.*?)\]/g;
|
|
|
|
const instructionRegex = /\[instruction\|(.*?)\]/g;
|
|
|
|
const referenceRegex = /\[reference\|(.*?)\]/g;
|
|
|
|
|
2023-06-09 10:45:17 +08:00
|
|
|
const contextPaths: string[] = [];
|
|
|
|
const instructionPaths: string[] = [];
|
|
|
|
const referencePaths: string[] = [];
|
2023-05-31 16:10:53 +08:00
|
|
|
|
|
|
|
let match;
|
|
|
|
|
|
|
|
// 提取 context
|
|
|
|
while ((match = contextRegex.exec(message)) !== null) {
|
|
|
|
contextPaths.push(match[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 提取 instruction
|
|
|
|
while ((match = instructionRegex.exec(message)) !== null) {
|
|
|
|
instructionPaths.push(match[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 提取 reference
|
|
|
|
while ((match = referenceRegex.exec(message)) !== null) {
|
|
|
|
referencePaths.push(match[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 移除标签,保留纯文本
|
|
|
|
const text = message
|
|
|
|
.replace(contextRegex, '')
|
|
|
|
.replace(instructionRegex, '')
|
|
|
|
.replace(referenceRegex, '')
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
return { context: contextPaths, instruction: instructionPaths, reference: referencePaths, text };
|
|
|
|
}
|
|
|
|
|
2023-05-31 16:10:53 +08:00
|
|
|
export function getInstructionFiles(): string[] {
|
2023-05-31 16:10:53 +08:00
|
|
|
const instructionFiles: string[] = [];
|
|
|
|
|
|
|
|
const customCommands = CustomCommands.getInstance().getCommands();
|
|
|
|
// visit customCommands, get default command
|
|
|
|
for (const command of customCommands) {
|
|
|
|
if (command.default) {
|
|
|
|
for (const instruction of command.instructions) {
|
2023-06-02 09:58:44 +08:00
|
|
|
instructionFiles.push(`${instruction}`);
|
2023-05-31 16:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return instructionFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
const devChat = new DevChat();
|
|
|
|
let userStop = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 将解析消息的部分提取到一个单独的函数中
|
2023-05-31 16:10:53 +08:00
|
|
|
export async function parseMessageAndSetOptions(message: any, chatOptions: any): Promise<{ context: string[]; instruction: string[]; reference: string[]; text: string }> {
|
2023-05-31 16:10:53 +08:00
|
|
|
const newText2 = await CommandManager.getInstance().processText(message.text);
|
|
|
|
const parsedMessage = parseMessage(newText2);
|
|
|
|
|
|
|
|
if (parsedMessage.context.length > 0) {
|
|
|
|
chatOptions.context = parsedMessage.context;
|
|
|
|
}
|
|
|
|
|
|
|
|
chatOptions.header = getInstructionFiles();
|
2023-07-24 00:11:56 +08:00
|
|
|
if ((parsedMessage.instruction && parsedMessage.instruction.length > 0) || newText2 !== message.text) {
|
2023-05-31 16:10:53 +08:00
|
|
|
chatOptions.header = parsedMessage.instruction;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parsedMessage.reference.length > 0) {
|
|
|
|
chatOptions.reference = parsedMessage.reference;
|
|
|
|
}
|
2023-07-24 00:11:56 +08:00
|
|
|
|
2023-05-31 16:10:53 +08:00
|
|
|
return parsedMessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-17 20:31:01 +08:00
|
|
|
export async function handleTopic(parentHash:string | undefined, message: any, chatResponse: ChatResponse) {
|
2023-07-24 08:18:48 +08:00
|
|
|
waitCreateTopic = true;
|
2023-06-05 11:36:45 +08:00
|
|
|
try {
|
|
|
|
if (!chatResponse.isError) {
|
|
|
|
messageHistory.add({ request: message.text, text: chatResponse.response, parentHash, hash: chatResponse['prompt-hash'], user: chatResponse.user, date: chatResponse.date });
|
|
|
|
|
|
|
|
let topicId = TopicManager.getInstance().currentTopicId;
|
|
|
|
if (!topicId) {
|
|
|
|
// create new topic
|
|
|
|
const topic = TopicManager.getInstance().createTopic();
|
|
|
|
topicId = topic.topicId;
|
|
|
|
}
|
|
|
|
|
2023-06-06 10:35:32 +08:00
|
|
|
TopicManager.getInstance().updateTopic(topicId!, chatResponse['prompt-hash'], parseDateStringToTimestamp(chatResponse.date), message.text, chatResponse.response);
|
2023-05-31 16:10:53 +08:00
|
|
|
}
|
2023-06-05 11:36:45 +08:00
|
|
|
} finally {
|
2023-07-24 00:11:56 +08:00
|
|
|
waitCreateTopic = false;
|
2023-05-31 16:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function handlerResponseText(partialDataText: string, chatResponse: ChatResponse) : Promise<string|undefined> {
|
|
|
|
let responseText = chatResponse.response.replace(/```\ncommitmsg/g, "```commitmsg");
|
|
|
|
if (userStop) {
|
|
|
|
userStop = false;
|
2023-06-06 11:14:36 +08:00
|
|
|
if (chatResponse.isError) {
|
2023-05-31 16:10:53 +08:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
2023-06-05 09:17:58 +08:00
|
|
|
|
2023-05-31 16:10:53 +08:00
|
|
|
return responseText;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 重构后的sendMessage函数
|
2023-07-24 00:11:56 +08:00
|
|
|
export async function sendMessageBase(message: any, handlePartialData: (data: { command: string, text: string, user: string, date: string}) => void, function_name: string| undefined = undefined): Promise<{ command: string, text: string, hash: string, user: string, date: string, isError: boolean }|undefined> {
|
2023-06-09 12:09:18 +08:00
|
|
|
userStop = false;
|
2023-05-31 16:10:53 +08:00
|
|
|
const chatOptions: any = {};
|
|
|
|
const parsedMessage = await parseMessageAndSetOptions(message, chatOptions);
|
|
|
|
|
2023-07-17 20:31:01 +08:00
|
|
|
if (message.parent_hash) {
|
|
|
|
chatOptions.parent = message.parent_hash;
|
2023-05-31 16:10:53 +08:00
|
|
|
}
|
2023-07-17 20:31:01 +08:00
|
|
|
logger.channel()?.info(`parent hash: ${chatOptions.parent}`);
|
2023-05-31 16:10:53 +08:00
|
|
|
|
2023-07-24 00:11:56 +08:00
|
|
|
chatOptions.functions = "./.chat/functions.json";
|
|
|
|
if (function_name) {
|
|
|
|
chatOptions.function_name = function_name;
|
|
|
|
chatOptions.role = "function";
|
|
|
|
}
|
|
|
|
|
2023-05-31 16:10:53 +08:00
|
|
|
let partialDataText = '';
|
|
|
|
const onData = (partialResponse: ChatResponse) => {
|
|
|
|
partialDataText = partialResponse.response.replace(/```\ncommitmsg/g, "```commitmsg");
|
|
|
|
handlePartialData({ command: 'receiveMessagePartial', text: partialDataText!, user: partialResponse.user, date: partialResponse.date });
|
|
|
|
};
|
|
|
|
|
|
|
|
const chatResponse = await devChat.chat(parsedMessage.text, chatOptions, onData);
|
2023-07-17 20:31:01 +08:00
|
|
|
await handleTopic(message.parent_hash, message, chatResponse);
|
2023-05-31 16:10:53 +08:00
|
|
|
const responseText = await handlerResponseText(partialDataText, chatResponse);
|
|
|
|
if (responseText === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return { command: 'receiveMessage', text: responseText, hash: chatResponse['prompt-hash'], user: chatResponse.user, date: chatResponse.date, isError: chatResponse.isError };
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function stopDevChatBase(message: any): Promise<void> {
|
|
|
|
logger.channel()?.info(`Stopping devchat`);
|
|
|
|
userStop = true;
|
|
|
|
devChat.stop();
|
2023-07-17 18:56:56 +08:00
|
|
|
}
|
|
|
|
|
2023-10-11 23:51:58 +08:00
|
|
|
export async function insertDevChatLog(message: any, request: string, response: string): Promise<string | undefined> {
|
2023-10-11 23:51:57 +08:00
|
|
|
logger.channel()?.info(`Inserting devchat log`);
|
|
|
|
await devChat.logInsert(request, response, message.parent_hash);
|
2023-10-11 23:51:58 +08:00
|
|
|
const logs = await devChat.log({"maxCount": 1});
|
|
|
|
if (logs && logs.length > 0) {
|
|
|
|
return logs[0]['hash'];
|
|
|
|
} else {
|
|
|
|
return undefined;
|
|
|
|
}
|
2023-10-11 23:51:57 +08:00
|
|
|
}
|
|
|
|
|
2023-07-17 18:56:56 +08:00
|
|
|
// delete a chat message
|
|
|
|
// each message is identified by hash
|
|
|
|
export async function deleteChatMessageBase(message:{'hash': string}): Promise<boolean> {
|
|
|
|
// if hash is undefined, return
|
|
|
|
if (!message.hash) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete the message from messageHistory
|
|
|
|
messageHistory.delete(message.hash);
|
|
|
|
|
|
|
|
// delete the message by devchat
|
|
|
|
const bSuccess = await devChat.delete(message.hash);
|
2023-07-21 17:17:43 +08:00
|
|
|
if (bSuccess) {
|
|
|
|
let topicId = TopicManager.getInstance().currentTopicId;
|
|
|
|
if (topicId) {
|
|
|
|
TopicManager.getInstance().deleteMessage(topicId, message.hash);
|
|
|
|
}
|
|
|
|
}
|
2023-07-17 18:56:56 +08:00
|
|
|
return bSuccess;
|
2023-05-31 16:10:53 +08:00
|
|
|
}
|