From 8772da464c10e3e40222ad02713f97007a7e989b Mon Sep 17 00:00:00 2001 From: robgruen Date: Tue, 14 Jan 2025 00:00:51 -0800 Subject: [PATCH] Added user name to the user chat bubble (#553) Added user name and icon place holder to the UI: ![image](https://github.com/user-attachments/assets/ec84b344-7b55-4964-9f7f-ced2d3c48fa1) --- ts/packages/shell/package.json | 1 + .../shell/src/renderer/assets/styles.less | 18 +++++++++ .../shell/src/renderer/src/chatView.ts | 2 + ts/packages/shell/src/renderer/src/main.ts | 40 +++++++++++++++---- .../src/renderer/src/messageContainer.ts | 34 ++++++++++------ ts/pnpm-lock.yaml | 8 ++++ 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/ts/packages/shell/package.json b/ts/packages/shell/package.json index 8afd1b05..73fb89fa 100644 --- a/ts/packages/shell/package.json +++ b/ts/packages/shell/package.json @@ -41,6 +41,7 @@ "dompurify": "^3.1.6", "dotenv": "^16.3.1", "electron-updater": "^6.3.2", + "jose": "^5.9.6", "markdown-it": "^14.1.0", "microsoft-cognitiveservices-speech-sdk": "^1.38.0", "typechat": "^0.1.1", diff --git a/ts/packages/shell/src/renderer/assets/styles.less b/ts/packages/shell/src/renderer/assets/styles.less index 045f49f9..0abcb672 100644 --- a/ts/packages/shell/src/renderer/assets/styles.less +++ b/ts/packages/shell/src/renderer/assets/styles.less @@ -217,6 +217,7 @@ body { .chat-message-body; position: relative; background-color: lavender; + margin-right: 30px; } .chat-message-agent { @@ -355,6 +356,7 @@ table.table-message td { .chat-timestamp-user { .chat-timestamp; text-align: end; + margin-right: 35px; } .agent-icon { @@ -368,6 +370,22 @@ table.table-message td { text-align: center; } +.user-icon { + width: 30px; + height: 30px; + border-radius: 15px; + position: absolute; + right: 0px; + font-size: 20px; + font-style: normal; + text-align: center; + background: plum; + color: purple; + margin-top: 2px; + font-family: sans-serif; + font-weight: 300; +} + .agent-name { font-style: normal; font-weight: bold; diff --git a/ts/packages/shell/src/renderer/src/chatView.ts b/ts/packages/shell/src/renderer/src/chatView.ts index 8efb4598..ddb0596f 100644 --- a/ts/packages/shell/src/renderer/src/chatView.ts +++ b/ts/packages/shell/src/renderer/src/chatView.ts @@ -73,6 +73,8 @@ export class ChatView { private commandBackStackIndex = 0; private hideMetrics = true; + public userGivenName: string = ""; + constructor( private idGenerator: IdGenerator, public agents: Map, diff --git a/ts/packages/shell/src/renderer/src/main.ts b/ts/packages/shell/src/renderer/src/main.ts index e6eee9b9..1e2da88a 100644 --- a/ts/packages/shell/src/renderer/src/main.ts +++ b/ts/packages/shell/src/renderer/src/main.ts @@ -3,7 +3,11 @@ /// -import { ClientAPI, NotifyCommands } from "../../preload/electronTypes"; +import { + ClientAPI, + NotifyCommands, + SpeechToken, +} from "../../preload/electronTypes"; import { ChatView } from "./chatView"; import { TabView } from "./tabView"; import { recognizeOnce } from "./speech"; @@ -16,6 +20,7 @@ import { ShellSettings } from "../../main/shellSettings"; import { AppAgentEvent } from "@typeagent/agent-sdk"; import { CameraView } from "./cameraView"; import { createWebSocket, webapi } from "./webSocketAPI"; +import * as jose from "jose"; export function getClientAPI(): ClientAPI { if (globalThis.api !== undefined) { @@ -358,13 +363,34 @@ document.addEventListener("DOMContentLoaded", async function () { chatView.chatInputFocus(); - if ((window as any).electron) { - (window as any).electron.ipcRenderer.send("dom ready"); + try { + if (Android !== undefined) { + Bridge.interfaces.Android.domReady((userMessage: string) => { + chatView.addUserMessage(userMessage); + }); + } + } catch (e) { + console.log(e); + } + + // get the users's name to show in the chat view + let token: SpeechToken | undefined = await getClientAPI().getSpeechToken(); + const actualToken = token?.token.substring(token?.token.indexOf("#")); + if (actualToken) { + const dToken = jose.decodeProtectedHeader(actualToken); + console.log(dToken); + + const decoded = jose.decodeJwt(actualToken); + console.log(decoded); + + if (decoded.given_name) { + chatView.userGivenName = decoded.given_name + .toString() + .toLocaleLowerCase(); + } } - if (Android !== undefined) { - Bridge.interfaces.Android.domReady((userMessage: string) => { - chatView.addUserMessage(userMessage); - }); + if ((window as any).electron) { + (window as any).electron.ipcRenderer.send("dom ready"); } }); diff --git a/ts/packages/shell/src/renderer/src/messageContainer.ts b/ts/packages/shell/src/renderer/src/messageContainer.ts index 6d69f8d2..38ebe609 100644 --- a/ts/packages/shell/src/renderer/src/messageContainer.ts +++ b/ts/packages/shell/src/renderer/src/messageContainer.ts @@ -123,17 +123,22 @@ export class MessageContainer { const sourceIcon = this.agents.get(source); // set source and source icon - (this.timestampDiv.firstChild as HTMLDivElement).innerText = - actionName ?? source; // name - this.iconDiv.innerText = sourceIcon ?? "❔"; // icon + this.updateActionName(actionName ?? source); + + // use agent icon for agents, user Initial for users + if (this.iconDiv.className.indexOf("agent-") > -1) { + this.iconDiv.innerText = sourceIcon ?? "❔"; // icon + } else if (actionName && actionName.length > 0) { + this.iconDiv.innerText = actionName + ?.charAt(0) + .toLocaleUpperCase(); + } } } public updateActionName(name: string | undefined) { - if (name !== undefined) { + if (name !== undefined && name.length > 0) { (this.timestampDiv.firstChild as HTMLDivElement).innerText = name; - } else { - (this.timestampDiv.firstChild as HTMLDivElement).innerText = ""; } } @@ -158,12 +163,10 @@ export class MessageContainer { div.append(timestampDiv); this.timestampDiv = timestampDiv; - if (classNameSuffix === "agent") { - const agentIconDiv = document.createElement("div"); - agentIconDiv.className = "agent-icon"; - div.append(agentIconDiv); - this.iconDiv = agentIconDiv; - } + const agentIconDiv = document.createElement("div"); + agentIconDiv.className = `${classNameSuffix}-icon`; + this.iconDiv = agentIconDiv; + div.append(agentIconDiv); const messageBodyDiv = document.createElement("div"); const bodyClass = this.hideMetrics @@ -182,7 +185,12 @@ export class MessageContainer { beforeElem.before(div); this.div = div; - this.updateSource(); + + if (classNameSuffix == "agent") { + this.updateSource(); + } else { + this.updateSource(chatView.userGivenName); + } } public getMessage() { diff --git a/ts/pnpm-lock.yaml b/ts/pnpm-lock.yaml index 77245f32..fcc2c115 100644 --- a/ts/pnpm-lock.yaml +++ b/ts/pnpm-lock.yaml @@ -2034,6 +2034,9 @@ importers: electron-updater: specifier: ^6.3.2 version: 6.3.2 + jose: + specifier: ^5.9.6 + version: 5.9.6 markdown-it: specifier: ^14.1.0 version: 14.1.0 @@ -6629,6 +6632,9 @@ packages: jju@1.4.0: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -15076,6 +15082,8 @@ snapshots: jju@1.4.0: {} + jose@5.9.6: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: