diff --git a/src/features/chat-page/chat-services/chat-thread-service.ts b/src/features/chat-page/chat-services/chat-thread-service.ts index 8f42b27d7..db341ac9d 100644 --- a/src/features/chat-page/chat-services/chat-thread-service.ts +++ b/src/features/chat-page/chat-services/chat-thread-service.ts @@ -10,6 +10,7 @@ import { RedirectToChatThread } from "@/features/common/navigation-helpers"; import { ServerActionResponse } from "@/features/common/server-action-response"; import { uniqueId } from "@/features/common/util"; import { + AI_NAME, CHAT_DEFAULT_PERSONA, NEW_CHAT_NAME, } from "@/features/theme/theme-config"; @@ -17,10 +18,11 @@ import { SqlQuerySpec } from "@azure/cosmos"; import { HistoryContainer } from "../../common/services/cosmos"; import { DeleteDocuments } from "./azure-ai-search/azure-ai-search"; import { FindAllChatDocuments } from "./chat-document-service"; -import { FindAllChatMessagesForCurrentUser } from "./chat-message-service"; +import { CreateChatMessage, FindAllChatMessagesForCurrentUser } from "./chat-message-service"; import { CHAT_THREAD_ATTRIBUTE, ChatDocumentModel, + ChatRole, ChatThreadModel, } from "./models"; @@ -334,6 +336,18 @@ export const UpdateChatTitle = async ( } }; +export const CreateIntroMessage = async (chatThreadId: string, messageText: string) => { + let role: ChatRole = "assistant"; + const messageModel = { + name: AI_NAME, + role: role, + content: messageText, + chatThreadId: chatThreadId, + multiModalImage: "", + }; + void CreateChatMessage(messageModel); +} + export const CreateChatAndRedirect = async () => { const response = await CreateChatThread(); if (response.status === "OK") { diff --git a/src/features/persona-page/add-new-persona.tsx b/src/features/persona-page/add-new-persona.tsx index 1aa026a4f..96e35a93c 100644 --- a/src/features/persona-page/add-new-persona.tsx +++ b/src/features/persona-page/add-new-persona.tsx @@ -23,6 +23,7 @@ import { personaStore, usePersonaState, } from "./persona-store"; +import { AI_NAME } from "@/features/theme/theme-config"; interface Props {} @@ -109,6 +110,16 @@ export const AddNewPersona: FC = (props) => { placeholder="Personality of your persona" /> +
+ +
+ +
+
diff --git a/src/features/persona-page/persona-card/persona-view.tsx b/src/features/persona-page/persona-card/persona-view.tsx index 0250654b6..f07f180fd 100644 --- a/src/features/persona-page/persona-card/persona-view.tsx +++ b/src/features/persona-page/persona-card/persona-view.tsx @@ -12,6 +12,7 @@ import { SheetTrigger, } from "../../ui/sheet"; import { PersonaModel } from "../persona-services/models"; +import { AI_NAME } from "@/features/theme/theme-config"; interface Props { persona: PersonaModel; @@ -41,6 +42,18 @@ export const ViewPersona: FC = (props) => { name="personaMessage" placeholder="Personality of your persona" /> +
+ +
+ {AI_NAME} uses a customized introduction message for this persona +
+

{persona.isPublished ? `This is published and everyone in your organisation can use ${persona.name} persona` diff --git a/src/features/persona-page/persona-services/models.ts b/src/features/persona-page/persona-services/models.ts index 5829c7307..bf3014965 100644 --- a/src/features/persona-page/persona-services/models.ts +++ b/src/features/persona-page/persona-services/models.ts @@ -26,6 +26,7 @@ export const PersonaModelSchema = z.object({ .min(1) .refine(refineFromEmpty, "System message cannot be empty"), isPublished: z.boolean(), + useIntroductionMessage: z.boolean(), type: z.literal(PERSONA_ATTRIBUTE), createdAt: z.date(), }); diff --git a/src/features/persona-page/persona-services/persona-service.ts b/src/features/persona-page/persona-services/persona-service.ts index 57de4d943..afa81f165 100644 --- a/src/features/persona-page/persona-services/persona-service.ts +++ b/src/features/persona-page/persona-services/persona-service.ts @@ -2,7 +2,7 @@ import "server-only"; import { getCurrentUser, userHashedId } from "@/features/auth-page/helpers"; -import { UpsertChatThread } from "@/features/chat-page/chat-services/chat-thread-service"; +import { CreateIntroMessage, UpsertChatThread } from "@/features/chat-page/chat-services/chat-thread-service"; import { CHAT_THREAD_ATTRIBUTE, ChatThreadModel, @@ -15,12 +15,15 @@ import { HistoryContainer } from "@/features/common/services/cosmos"; import { uniqueId } from "@/features/common/util"; import { SqlQuerySpec } from "@azure/cosmos"; import { PERSONA_ATTRIBUTE, PersonaModel, PersonaModelSchema } from "./models"; +import { INTRODUCTION_MESSAGE_PROMPT} from "@/features/theme/theme-config"; +import { OpenAIInstance } from "@/features/common/services/openai"; interface PersonaInput { name: string; description: string; personaMessage: string; isPublished: boolean; + useIntroductionMessage: boolean; } export const FindPersonaByID = async ( @@ -84,6 +87,7 @@ export const CreatePersona = async ( description: props.description, personaMessage: props.personaMessage, isPublished: user.isAdmin ? props.isPublished : false, + useIntroductionMessage: props.useIntroductionMessage, userId: await userHashedId(), createdAt: new Date(), type: "PERSONA", @@ -197,6 +201,7 @@ export const UpsertPersona = async ( isPublished: user.isAdmin ? personaInput.isPublished : persona.isPublished, + useIntroductionMessage: personaInput.useIntroductionMessage, createdAt: new Date(), }; @@ -305,6 +310,9 @@ export const CreatePersonaChat = async ( personaMessageTitle: persona.name, extension: [], }); + if (response.status === "OK" && persona.useIntroductionMessage) { + await CreatePersonaIntroMessage(response.response.id, persona.personaMessage) + } return response; } @@ -326,3 +334,22 @@ const ValidateSchema = (model: PersonaModel): ServerActionResponse => { response: model, }; }; + +const CreatePersonaIntroMessage = async (chatThreadId: string, personaMessage: string) => { + let completionText = ""; + const openAI = OpenAIInstance(); + try { + const completion = await openAI.chat.completions.create({ + model: "", + messages: [ + { role: "system", content: INTRODUCTION_MESSAGE_PROMPT }, + { role: "user", content: `These are your general capabilities: ${personaMessage}`}, + ], + }); + + completionText = (completion.choices[0]?.message?.content || ""); + await CreateIntroMessage(chatThreadId, completionText); + } catch (error) { + console.error("Error during OpenAI completion:", error); + } +} diff --git a/src/features/persona-page/persona-store.ts b/src/features/persona-page/persona-store.ts index 0d2d2db43..b4dd1f071 100644 --- a/src/features/persona-page/persona-store.ts +++ b/src/features/persona-page/persona-store.ts @@ -14,6 +14,7 @@ class PersonaState { personaMessage: "", createdAt: new Date(), isPublished: false, + useIntroductionMessage: false, type: "PERSONA", userId: "", }; @@ -92,6 +93,7 @@ export const FormDataToPersonaModel = (formData: FormData): PersonaModel => { description: formData.get("description") as string, personaMessage: formData.get("personaMessage") as string, isPublished: formData.get("isPublished") === "on" ? true : false, + useIntroductionMessage: formData.get("useIntroductionMessage") === "on" ? true : false, userId: "", // the user id is set on the server once the user is authenticated createdAt: new Date(), type: PERSONA_ATTRIBUTE, diff --git a/src/features/theme/theme-config.ts b/src/features/theme/theme-config.ts index 57391f556..7d4cce6f5 100644 --- a/src/features/theme/theme-config.ts +++ b/src/features/theme/theme-config.ts @@ -8,3 +8,5 @@ You have access to the following functions: 1. create_img: You must only use the function create_img if the user asks you to create an image.`; export const NEW_CHAT_NAME = "New chat"; + +export const INTRODUCTION_MESSAGE_PROMPT = "Don't follow your capabilities for now and just greet the user and explain what you are capable of. You start with a h2 headline first, so that the user understands your main purpose. Make sure that headline includes a brief summary of your role."; \ No newline at end of file