Skip to content

Commit

Permalink
Merge branch 'dev' into 828-streamline-chat-model-configuration-info-…
Browse files Browse the repository at this point in the history
…message-network-call
  • Loading branch information
pmarsh-scottlogic authored Mar 27, 2024
2 parents c51a48d + b231883 commit ebac4a0
Show file tree
Hide file tree
Showing 18 changed files with 66 additions and 90 deletions.
24 changes: 24 additions & 0 deletions backend/src/controller/chatController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
...levelResult.chatResponse,
wonLevel:
!levelResult.chatResponse.defenceReport.isBlocked &&
!levelResult.chatResponse.openAIErrorMessage &&
isLevelWon(levelResult.chatResponse.sentEmails, currentLevel),
};

Expand Down Expand Up @@ -334,6 +335,29 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
req.session.levelState[currentLevel].chatHistory = updatedChatHistory;
req.session.levelState[currentLevel].sentEmails = totalSentEmails;

// If the level has just been won, add a level complete message to chat history and return it in the response
const levelCompleteMessageInChatHistory = req.session.levelState[
currentLevel
].chatHistory.some((msg) => msg.chatMessageType === 'LEVEL_COMPLETE');
if (updatedChatResponse.wonLevel && !levelCompleteMessageInChatHistory) {
const levelCompleteMessage = {
chatMessageType: 'LEVEL_COMPLETE',
infoMessage:
currentLevel === LEVEL_NAMES.LEVEL_3
? `🎉 Congratulations, you have completed the final level of your assignment!`
: `🎉 Congratulations! You have completed this level. Please click on the next level to continue.`,
} as ChatInfoMessage;

// add level complete message to chat history
req.session.levelState[currentLevel].chatHistory = pushMessageToHistory(
req.session.levelState[currentLevel].chatHistory,
levelCompleteMessage
);

// add level complete message to chat response
updatedChatResponse.wonLevelMessage = levelCompleteMessage;
}

console.log('chatResponse: ', updatedChatResponse);
console.log('chatHistory: ', updatedChatHistory);

Expand Down
3 changes: 2 additions & 1 deletion backend/src/models/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ChatCompletionMessageParam,
} from 'openai/resources/chat/completions';

import { ChatMessage } from './chatMessage';
import { ChatInfoMessage, ChatMessage } from './chatMessage';
import { DEFENCE_ID } from './defence';
import { EmailInfo } from './email';

Expand Down Expand Up @@ -97,6 +97,7 @@ interface ChatHttpResponse {
openAIErrorMessage: string | null;
sentEmails: EmailInfo[];
transformedMessageInfo?: string;
wonLevelMessage?: ChatInfoMessage;
}

interface LevelHandlerResponse {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/chatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TransformedChatMessage } from './chat';
const chatInfoMessageTypes = [
'DEFENCE_ALERTED',
'DEFENCE_TRIGGERED',
'LEVEL_INFO',
'LEVEL_COMPLETE',
'RESET_LEVEL',
'ERROR_MSG',
'BOT_BLOCKED',
Expand Down
21 changes: 17 additions & 4 deletions backend/test/unit/controller/chatController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -781,8 +781,17 @@ describe('handleChatToGPT unit tests', () => {

await handleChatToGPT(req, res);

const expectedWonLevelMessage = {
infoMessage:
'🎉 Congratulations! You have completed this level. Please click on the next level to continue.',
chatMessageType: 'LEVEL_COMPLETE',
} as ChatMessage;

expect(res.send).toHaveBeenCalledWith(
expect.objectContaining({ wonLevel: true })
expect.objectContaining({
wonLevel: true,
wonLevelMessage: expectedWonLevelMessage,
})
);
});

Expand Down Expand Up @@ -827,11 +836,13 @@ describe('handleChatToGPT unit tests', () => {
await handleChatToGPT(req, res);

expect(res.send).toHaveBeenCalledWith(
expect.objectContaining({ wonLevel: false })
expect.objectContaining({
wonLevel: false,
})
);
});

test('Given win condition met AND openAI error THEN level is won', async () => {
test('Given win condition met AND openAI error THEN level is not won', async () => {
const newUserChatMessage = {
completion: {
content: 'Here is the answer to the level',
Expand Down Expand Up @@ -868,7 +879,9 @@ describe('handleChatToGPT unit tests', () => {
await handleChatToGPT(req, res);

expect(res.send).toHaveBeenCalledWith(
expect.objectContaining({ wonLevel: true })
expect.objectContaining({
wonLevel: false,
})
);
});
});
Expand Down
1 change: 0 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ function App() {
setIsNewUser(false);
openOverlay(
<OverlayWelcome
currentLevel={currentLevel}
setStartLevel={(level: LEVEL_NAMES) => {
setStartLevel(level);
}}
Expand Down
28 changes: 5 additions & 23 deletions frontend/src/components/ChatBox/ChatBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,9 @@ function ChatBox({
setChatInput(recalledMessage);
}, [recalledMessageReverseIndex]);

function getSuccessMessage() {
return currentLevel < LEVEL_NAMES.LEVEL_3
? `Congratulations! You have completed this level. Please click on the next level to continue.`
: `Congratulations, you have completed the final level of your assignment!`;
}

function isLevelComplete() {
// level is complete if the chat contains a LEVEL_INFO message
return messages.some((message) => message.type === 'LEVEL_INFO');
}

function processChatResponse(response: ChatResponse) {
const transformedMessageInfo = response.transformedMessageInfo;
const transformedMessage = response.transformedMessage;
// add transformation info message to the chat box
if (transformedMessageInfo) {
addChatMessage({
message: transformedMessageInfo,
Expand Down Expand Up @@ -156,19 +144,13 @@ function ChatBox({
// update emails
addSentEmails(response.sentEmails);

if (response.wonLevel && !isLevelComplete()) {
if (response.wonLevelMessage) {
updateNumCompletedLevels(currentLevel);
const successMessage = getSuccessMessage();
addChatMessage({
type: 'LEVEL_INFO',
message: successMessage,
});
// asynchronously add the message to the chat history
void chatService.addInfoMessageToChatHistory(
successMessage,
'LEVEL_INFO',
currentLevel
const levelCompleteMessage = chatService.makeChatMessageFromDTO(
response.wonLevelMessage
);
addChatMessage(levelCompleteMessage);

// if this is the last level, show the level complete overlay
if (currentLevel === LEVEL_NAMES.LEVEL_3) {
openLevelsCompleteOverlay();
Expand Down
10 changes: 2 additions & 8 deletions frontend/src/components/ChatBox/ChatBoxMessage/MessageBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function MessageBubble({
const baseClassName = 'message-bubble';

const messageTypeClassName =
message.type === 'LEVEL_INFO'
message.type === 'LEVEL_COMPLETE'
? 'level-info'
: message.type === 'USER'
? 'user'
Expand All @@ -35,7 +35,7 @@ function MessageBubble({
);

const messageAuthor =
message.type === 'LEVEL_INFO'
message.type === 'LEVEL_COMPLETE'
? ''
: message.type === 'USER'
? 'You said:'
Expand All @@ -48,12 +48,6 @@ function MessageBubble({
return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
<section className={className} lang="en" tabIndex={0}>
{message.type === 'LEVEL_INFO' && (
<>
<p className="header">Information</p>
<span className="visually-hidden"> message: </span>
</>
)}
<span className="visually-hidden">{messageAuthor}</span>
{message.transformedMessage ? (
<span>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/DocumentViewer/DocumentViewBox.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
padding: 2rem;
border: 0.1875rem solid var(--main-border-colour);
background: var(--main-background);
aspect-ratio: 7/8;
color: var(--main-text-colour);
aspect-ratio: 7/8;
}

.document-viewer-container {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ExportChat/ExportChatMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function getMessageStyle(type: CHAT_MESSAGE_TYPE) {
return styles.chatBoxInfo;
case 'BOT_BLOCKED':
case 'BOT':
case 'LEVEL_INFO':
case 'LEVEL_COMPLETE':
case 'ERROR_MSG':
return styles.chatBoxMessageBot;
case 'USER':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function LevelSelectionBox({
}

return (
<div className="level-selection-box">
<nav className="level-selection-box">
{displayLevels.map(({ id, displayName }, index) => {
const disabled =
index > numCompletedLevels && id !== LEVEL_NAMES.SANDBOX;
Expand Down Expand Up @@ -62,7 +62,7 @@ function LevelSelectionBox({
</ThemedButton>
);
})}
</div>
</nav>
);
}

Expand Down
7 changes: 1 addition & 6 deletions frontend/src/components/Overlay/OverlayWelcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import { LEVEL_NAMES } from '@src/models/level';
import MultipageOverlay from './MultipageOverlay';

function OverlayWelcome({
currentLevel,
setStartLevel,
closeOverlay,
}: {
currentLevel: LEVEL_NAMES;
setStartLevel: (newLevel: LEVEL_NAMES) => void;
closeOverlay: () => void;
}) {
Expand Down Expand Up @@ -43,10 +41,7 @@ function OverlayWelcome({
beginning, or are you an expert spy, and would prefer to jump
straight in at the sandbox?
</p>
<StartLevelButtons
currentLevel={currentLevel}
setStartLevel={setStartLevel}
/>
<StartLevelButtons setStartLevel={setStartLevel} />
</>
),
imageUrl: BotAvatarDefault,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ThemedButtons/ChatButton.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 0.75rem;
border: 1px solid var(--chat-button-border-colour);
border-radius: 0.625rem;
background-color: var(--chat-button-background-colour);
color: var(--chat-button-text-colour);
font-weight: 700;
font-size: 1rem;
width: 100%;
}

.chat-button:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@ function LevelsCompleteButtons({
}
}

return (
<ModeSelectButtons
defaultSelection={lastLevel}
modeButtons={modes}
setLevel={handleLevelSelect}
/>
);
return <ModeSelectButtons modeButtons={modes} setLevel={handleLevelSelect} />;
}

export default LevelsCompleteButtons;
6 changes: 1 addition & 5 deletions frontend/src/components/ThemedButtons/ModeSelectButtons.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
align-items: center;
margin: 0;
padding: 1rem 2rem;
border: 0.0625rem solid var(--overlay-tab-colour);
border: 0.125rem solid var(--overlay-tab-colour);
border-radius: 0.5rem;
background-color: var(--overlay-background-colour);
font-weight: 700;
Expand All @@ -22,10 +22,6 @@
transition: ease 0.1s;
}

.mode-selection-buttons .mode-button.selected {
background-color: var(--overlay-tab-colour);
}

.mode-selection-buttons button:hover {
background-color: var(--overlay-tab-colour);
}
Expand Down
19 changes: 2 additions & 17 deletions frontend/src/components/ThemedButtons/ModeSelectButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,20 @@
import { clsx } from 'clsx';

import { LEVEL_NAMES, ModeSelectButton } from '@src/models/level';

import './ModeSelectButtons.css';

function ModeSelectButtons({
defaultSelection,
modeButtons,
setLevel,
}: {
defaultSelection: LEVEL_NAMES;
modeButtons: ModeSelectButton[];
setLevel: (newLevel: LEVEL_NAMES) => void;
}) {
function defaultButton(targetLevel: LEVEL_NAMES) {
return targetLevel === defaultSelection;
}

return (
<ul className="mode-selection-buttons">
{modeButtons.map((modeButton) => (
<li
key={modeButton.targetLevel}
aria-current={
defaultButton(modeButton.targetLevel) ? 'page' : undefined
}
>
<li key={modeButton.targetLevel}>
<button
className={clsx('mode-button', {
selected: defaultButton(modeButton.targetLevel),
})}
className="mode-button"
onClick={() => {
setLevel(modeButton.targetLevel);
}}
Expand Down
10 changes: 1 addition & 9 deletions frontend/src/components/ThemedButtons/StartLevelButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,16 @@ import { LEVEL_NAMES, ModeSelectButton } from '@src/models/level';
import ModeSelectButtons from './ModeSelectButtons';

function StartLevelButtons({
currentLevel,
setStartLevel,
}: {
currentLevel: LEVEL_NAMES;
setStartLevel: (newLevel: LEVEL_NAMES) => void;
}) {
const levels: ModeSelectButton[] = [
{ displayName: 'Level 1', targetLevel: LEVEL_NAMES.LEVEL_1 },
{ displayName: 'Sandbox', targetLevel: LEVEL_NAMES.SANDBOX },
];

return (
<ModeSelectButtons
defaultSelection={currentLevel}
modeButtons={levels}
setLevel={setStartLevel}
/>
);
return <ModeSelectButtons modeButtons={levels} setLevel={setStartLevel} />;
}

export default StartLevelButtons;
4 changes: 2 additions & 2 deletions frontend/src/components/ThemedButtons/ThemedButton.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@
}

.themed-button-tooltip.show.bottom-center {
top: auto;
right: 50%;
transform: translateX(50%);
bottom: calc(100% + 0.125rem);
top: auto;
transform: translateX(50%);
}

.themed-button:hover + .themed-button-tooltip.show,
Expand Down
Loading

0 comments on commit ebac4a0

Please sign in to comment.