Skip to content

Commit 5b97e7d

Browse files
feat(client): add the ablity to generate titles for conversations (#183)
* feat: add function to generate title * feat(server): implement option for generating titles * docs(readme): update example settings
1 parent 8367ca6 commit 5b97e7d

4 files changed

Lines changed: 51 additions & 6 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ module.exports = {
244244
debug: false,
245245
// (Optional) Possible options: "chatgpt", "chatgpt-browser", "bing". (Default: "chatgpt")
246246
clientToUse: 'chatgpt',
247+
// (Optional) Generate titles for each conversation for clients that support it (only ChatGPTClient for now).
248+
// This will be returned as a `title` property in the first response of the conversation.
249+
generateTitles: false,
247250
// (Optional) Set this to allow changing the client or client options in POST /conversation.
248251
// To disable, set to `null`.
249252
perMessageClientOptionsWhitelist: {

bin/server.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ server.post('/conversation', async (request, reply) => {
102102
conversationSignature: body.conversationSignature,
103103
clientId: body.clientId,
104104
invocationId: body.invocationId,
105+
shouldGenerateTitle: settings.apiOptions?.generateTitles || false, // only used for ChatGPTClient
105106
clientOptions,
106107
onProgress,
107108
abortController,

settings.example.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ export default {
7070
debug: false,
7171
// (Optional) Possible options: "chatgpt", "chatgpt-browser", "bing". (Default: "chatgpt")
7272
clientToUse: 'chatgpt',
73+
// (Optional) Generate titles for each conversation for clients that support it (only ChatGPTClient for now).
74+
// This will be returned as a `title` property in the first response of the conversation.
75+
generateTitles: false,
7376
// (Optional) Set this to allow changing the client or client options in POST /conversation.
7477
// To disable, set to `null`.
7578
perMessageClientOptionsWhitelist: {

src/ChatGPTClient.js

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,7 @@ export default class ChatGPTClient {
142142
abortController = new AbortController();
143143
}
144144
const modelOptions = { ...this.modelOptions };
145-
if (typeof onProgress === 'function') {
146-
modelOptions.stream = true;
147-
}
145+
modelOptions.stream = typeof onProgress === 'function';
148146
if (this.isChatGptModel) {
149147
modelOptions.messages = input;
150148
} else {
@@ -262,6 +260,35 @@ export default class ChatGPTClient {
262260
return response.json();
263261
}
264262

263+
async generateTitle(userMessage, botMessage) {
264+
const instructionsPayload = {
265+
role: 'system',
266+
content: `Write an extremely concise subtitle for this conversation with no more than a few words. All words should be capitalized. Exclude punctuation.
267+
268+
||>Message:
269+
${userMessage.message}
270+
||>Response:
271+
${botMessage.message}
272+
273+
||>Title:`,
274+
};
275+
276+
const titleGenClientOptions = JSON.parse(JSON.stringify(this.options));
277+
titleGenClientOptions.modelOptions = {
278+
model: 'gpt-3.5-turbo',
279+
temperature: 0,
280+
presence_penalty: 0,
281+
frequency_penalty: 0,
282+
};
283+
const titleGenClient = new ChatGPTClient(this.apiKey, titleGenClientOptions);
284+
const result = await titleGenClient.getCompletion([instructionsPayload], null);
285+
// remove any non-alphanumeric characters, replace multiple spaces with 1, and then trim
286+
return result.choices[0].message.content
287+
.replace(/[^a-zA-Z0-9 ]/g, '')
288+
.replace(/\s+/g, ' ')
289+
.trim();
290+
}
291+
265292
async sendMessage(
266293
message,
267294
opts = {},
@@ -274,13 +301,17 @@ export default class ChatGPTClient {
274301
const parentMessageId = opts.parentMessageId || crypto.randomUUID();
275302

276303
let conversation = await this.conversationsCache.get(conversationId);
304+
let isNewConversation = false;
277305
if (!conversation) {
278306
conversation = {
279307
messages: [],
280308
createdAt: Date.now(),
281309
};
310+
isNewConversation = true;
282311
}
283312

313+
const shouldGenerateTitle = opts.shouldGenerateTitle && isNewConversation;
314+
284315
const userMessage = {
285316
id: crypto.randomUUID(),
286317
parentMessageId,
@@ -354,15 +385,22 @@ export default class ChatGPTClient {
354385
};
355386
conversation.messages.push(replyMessage);
356387

357-
await this.conversationsCache.set(conversationId, conversation);
358-
359-
return {
388+
const returnData = {
360389
response: replyMessage.message,
361390
conversationId,
362391
parentMessageId: replyMessage.parentMessageId,
363392
messageId: replyMessage.id,
364393
details: result || {},
365394
};
395+
396+
if (shouldGenerateTitle) {
397+
conversation.title = await this.generateTitle(userMessage, replyMessage);
398+
returnData.title = conversation.title;
399+
}
400+
401+
await this.conversationsCache.set(conversationId, conversation);
402+
403+
return returnData;
366404
}
367405

368406
async buildPrompt(messages, parentMessageId, isChatGptModel = false) {

0 commit comments

Comments
 (0)