Skip to content

Commit

Permalink
feat: start using @wisegpt/gpt-conversation-prompt library
Browse files Browse the repository at this point in the history
  • Loading branch information
Yengas authored Dec 29, 2022
2 parents 4308aa6 + 25480a7 commit a7deeae
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 223 deletions.
4 changes: 4 additions & 0 deletions .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .projenrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const project = new awscdk.AwsCdkTypeScriptApp({

deps: [
"@wisegpt/awscdk-slack-event-bus",
"@wisegpt/gpt-conversation-prompt",
"@aws-sdk/client-secrets-manager",
"@aws-sdk/client-dynamodb",
"@aws-sdk/lib-dynamodb",
Expand Down
271 changes: 143 additions & 128 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ export default {
secretArn:
"arn:aws:secretsmanager:eu-west-1:197771300946:secret:wisegpt-bot-3yGDD6",
},
bot: {
// to be used in database records
userId: "wisegpt",
// to be used in OpenAI prompts
name: "WsGPT",
},
conversation: {
// which persona to use for conversations see `src/domain/persona/index.ts`
persona: "slack-software-eng",
personaConfigName: "slack-software-eng",
},
};
6 changes: 3 additions & 3 deletions src/domain/conversation/conversation.aggregate.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import config from "../../config";
import { DomainEvent } from "../bus/event-bus";
import {
AddUserMessageCommand,
AIStatus,
BOT_USER_ID,
ConversationEvent,
Message,
} from "./conversation.dto";
Expand Down Expand Up @@ -91,7 +91,7 @@ export class ConversationAggregate {
case "BOT_RESPONSE_SUCCESS": {
const message: Message = {
id: messageId,
author: { userId: config.bot.userId },
author: { userId: BOT_USER_ID },
text: botResponse.message,
};

Expand All @@ -109,7 +109,7 @@ export class ConversationAggregate {
case "BOT_RESPONSE_ERROR": {
const message: Message = {
id: messageId,
author: { userId: config.bot.userId },
author: { userId: BOT_USER_ID },
text: `unexpected error occurred: ${botResponse.error.message}`,
};

Expand Down
2 changes: 2 additions & 0 deletions src/domain/conversation/conversation.dto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const BOT_USER_ID = "bot-user-id";

export type User = {
userId: string;
};
Expand Down
14 changes: 7 additions & 7 deletions src/domain/persona/base-persona/base-persona.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { CreateCompletionRequest } from "openai";
import {
AIPersona,
ModelConfiguration,
} from "@wisegpt/gpt-conversation-prompt";

export const SEPARATOR_TOKEN = "<|endofstatement|>";

export type Persona = {
name: string;
basePrompt: string;
baseCompletionRequest: CreateCompletionRequest;
export type Persona = AIPersona & {
configName: string;
modelConfiguration: ModelConfiguration;
};
6 changes: 3 additions & 3 deletions src/domain/persona/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { slackSoftwareEngPersona } from "./slack-software-eng/slack-software-eng

const personas = [slackSoftwareEngPersona];

export function getPersonaByConfigName(name: string): Persona {
const persona = personas.find((p) => p.name === name);
export function getPersonaByConfigName(configName: string): Persona {
const persona = personas.find((p) => p.configName === configName);

if (!persona) {
throw new Error(`unknown persona: '${name}'`);
throw new Error(`unknown persona config name: '${configName}'`);
}

return persona;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import config from "../../../config";
import { Persona, SEPARATOR_TOKEN } from "../base-persona/base-persona.dto";
import { Persona } from "../base-persona/base-persona.dto";

export const slackSoftwareEngPersona: Persona = {
name: "slack-software-eng",
basePrompt: `Instructions for ${config.bot.name}:
You're a regular Slack user.
configName: "slack-software-eng",
name: "wiseGPT",
instructions: `You're a regular Slack user.
When providing code examples, use triple backticks and do not suffix the markdown shortcut for the language.
You always like providing lengthy responses and explaining things.
You are helpful and descriptive.
Expand All @@ -24,22 +23,9 @@ You are mindful of the conversation history and are consistent with your answers
You speak in a fun, casual, and friendly tone, like you're talking to a friend.
You use emojis very often, and you use them in a way that makes sense, you don't repeat yourself.
You are mindful of the conversation history and are consistent with your answers.
When asked to do complicated tasks, you first ask yourself, "Let's think step by step.", and break the problem down into parts to reach the most accurate answer.
The conversations are in this format, there can be an arbitrary amount of newlines between chat entries. The text "${SEPARATOR_TOKEN}" is used to separate chat entries and make it easier for you to understand the context:
Human: [MESSAGE 1] <|endofstatement|>
${config.bot.name}: [RESPONSE TO MESSAGE 1] <|endofstatement|>
Human: [MESSAGE 2] <|endofstatement|>
${config.bot.name}: [RESPONSE TO MESSAGE 2] <|endofstatement|>
...
You're a regular Slack user, be friendly, casual, and fun, speak with "lol", "haha", and etc when it seems fitting, and use emojis in your responses in a way that makes sense, avoid repeating yourself at all costs. Never say "<|endofstatement|>".
Continue the conversation, paying very close attention to things Human told you, such as their name, and personal details.
`,
baseCompletionRequest: {
When asked to do complicated tasks, you first ask yourself, "Let's think step by step.", and break the problem down into parts to reach the most accurate answer.`,
exampleConversations: [],
modelConfiguration: {
model: "text-davinci-003",
// higher value means more random, lower value means more likely to be a coherent sentence
temperature: 0.6,
Expand All @@ -50,9 +36,5 @@ Continue the conversation, paying very close attention to things Human told you,
presence_penalty: 0,
// penalize new tokens based on their existing frequency in the text so far. (Higher frequency = lower probability of being chosen.)
frequency_penalty: 0,
// number of responses to compare
best_of: 1,
n: 1,
echo: false,
},
};
71 changes: 25 additions & 46 deletions src/infrastructure/openai/openai.service.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,41 @@
import { ConversationPromptService } from "@wisegpt/gpt-conversation-prompt";
import { Configuration, OpenAIApi } from "openai";
import config from "../../config";
import { Message } from "../../domain/conversation/conversation.dto";
import { getPersonaByConfigName } from "../../domain/persona";
import {
Persona,
SEPARATOR_TOKEN,
} from "../../domain/persona/base-persona/base-persona.dto";
BOT_USER_ID,
Message,
} from "../../domain/conversation/conversation.dto";
import { getPersonaByConfigName } from "../../domain/persona";
import { Persona } from "../../domain/persona/base-persona/base-persona.dto";
import { OpenAiSecretsService } from "../secrets/open-ai-secrets.service";

type AIResponse = {
text: string;
usage: {
promptTokens: number;
completionTokens: number;
totalTokens: number;
};
};

export class OpenAIService {
constructor(
private readonly openAiSecretsService = new OpenAiSecretsService(),
private readonly persona: Persona = getPersonaByConfigName(
config.conversation.persona
config.conversation.personaConfigName
)
) {}

async askForResponse(messages: Message[]): Promise<AIResponse> {
const prompt =
this.persona.basePrompt +
messages
.map(
(message) =>
`${
message.author.userId === config.bot.userId
? config.bot.name
: "Human"
}: ${message.text}`
)
.join(` ${SEPARATOR_TOKEN}\n`) +
`\n${config.bot.name}: `;

// TODO: take out secret retrieval to outside of this class
async askForResponse(messages: Message[]) {
const { apiKey } = await this.openAiSecretsService.retrieve();
const api = new OpenAIApi(new Configuration({ apiKey }));

const { data } = await api.createCompletion({
...this.persona.baseCompletionRequest,
prompt,
const openAIApi = new OpenAIApi(new Configuration({ apiKey }));
const conversationPromptService = new ConversationPromptService(openAIApi);

return conversationPromptService.conversationCompletion({
prompt: {
conversation: {
messages: messages.map(({ text, author }) => ({
text,
author:
author.userId === BOT_USER_ID
? { type: "BOT" }
: { type: "USER", id: author.userId },
})),
},
aiPersona: this.persona,
},
modelConfiguration: this.persona.modelConfiguration,
});

const text = data.choices?.[0].text!.trim().replace(SEPARATOR_TOKEN, "");

const {
prompt_tokens: promptTokens,
completion_tokens: completionTokens,
total_tokens: totalTokens,
} = data.usage!;

return { text, usage: { promptTokens, completionTokens, totalTokens } };
}
}

0 comments on commit a7deeae

Please sign in to comment.