Skip to content

Commit

Permalink
feat(client): add the ablity to generate titles for conversations (#183)
Browse files Browse the repository at this point in the history
* feat: add function to generate title

* feat(server): implement option for generating titles

* docs(readme): update example settings
  • Loading branch information
waylaidwanderer authored Mar 13, 2023
1 parent 8367ca6 commit 5b97e7d
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 6 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ module.exports = {
debug: false,
// (Optional) Possible options: "chatgpt", "chatgpt-browser", "bing". (Default: "chatgpt")
clientToUse: 'chatgpt',
// (Optional) Generate titles for each conversation for clients that support it (only ChatGPTClient for now).
// This will be returned as a `title` property in the first response of the conversation.
generateTitles: false,
// (Optional) Set this to allow changing the client or client options in POST /conversation.
// To disable, set to `null`.
perMessageClientOptionsWhitelist: {
Expand Down
1 change: 1 addition & 0 deletions bin/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ server.post('/conversation', async (request, reply) => {
conversationSignature: body.conversationSignature,
clientId: body.clientId,
invocationId: body.invocationId,
shouldGenerateTitle: settings.apiOptions?.generateTitles || false, // only used for ChatGPTClient
clientOptions,
onProgress,
abortController,
Expand Down
3 changes: 3 additions & 0 deletions settings.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ export default {
debug: false,
// (Optional) Possible options: "chatgpt", "chatgpt-browser", "bing". (Default: "chatgpt")
clientToUse: 'chatgpt',
// (Optional) Generate titles for each conversation for clients that support it (only ChatGPTClient for now).
// This will be returned as a `title` property in the first response of the conversation.
generateTitles: false,
// (Optional) Set this to allow changing the client or client options in POST /conversation.
// To disable, set to `null`.
perMessageClientOptionsWhitelist: {
Expand Down
50 changes: 44 additions & 6 deletions src/ChatGPTClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ export default class ChatGPTClient {
abortController = new AbortController();
}
const modelOptions = { ...this.modelOptions };
if (typeof onProgress === 'function') {
modelOptions.stream = true;
}
modelOptions.stream = typeof onProgress === 'function';
if (this.isChatGptModel) {
modelOptions.messages = input;
} else {
Expand Down Expand Up @@ -262,6 +260,35 @@ export default class ChatGPTClient {
return response.json();
}

async generateTitle(userMessage, botMessage) {
const instructionsPayload = {
role: 'system',
content: `Write an extremely concise subtitle for this conversation with no more than a few words. All words should be capitalized. Exclude punctuation.
||>Message:
${userMessage.message}
||>Response:
${botMessage.message}
||>Title:`,
};

const titleGenClientOptions = JSON.parse(JSON.stringify(this.options));
titleGenClientOptions.modelOptions = {
model: 'gpt-3.5-turbo',
temperature: 0,
presence_penalty: 0,
frequency_penalty: 0,
};
const titleGenClient = new ChatGPTClient(this.apiKey, titleGenClientOptions);
const result = await titleGenClient.getCompletion([instructionsPayload], null);
// remove any non-alphanumeric characters, replace multiple spaces with 1, and then trim
return result.choices[0].message.content
.replace(/[^a-zA-Z0-9 ]/g, '')
.replace(/\s+/g, ' ')
.trim();
}

async sendMessage(
message,
opts = {},
Expand All @@ -274,13 +301,17 @@ export default class ChatGPTClient {
const parentMessageId = opts.parentMessageId || crypto.randomUUID();

let conversation = await this.conversationsCache.get(conversationId);
let isNewConversation = false;
if (!conversation) {
conversation = {
messages: [],
createdAt: Date.now(),
};
isNewConversation = true;
}

const shouldGenerateTitle = opts.shouldGenerateTitle && isNewConversation;

const userMessage = {
id: crypto.randomUUID(),
parentMessageId,
Expand Down Expand Up @@ -354,15 +385,22 @@ export default class ChatGPTClient {
};
conversation.messages.push(replyMessage);

await this.conversationsCache.set(conversationId, conversation);

return {
const returnData = {
response: replyMessage.message,
conversationId,
parentMessageId: replyMessage.parentMessageId,
messageId: replyMessage.id,
details: result || {},
};

if (shouldGenerateTitle) {
conversation.title = await this.generateTitle(userMessage, replyMessage);
returnData.title = conversation.title;
}

await this.conversationsCache.set(conversationId, conversation);

return returnData;
}

async buildPrompt(messages, parentMessageId, isChatGptModel = false) {
Expand Down

0 comments on commit 5b97e7d

Please sign in to comment.