Skip to content

Commit

Permalink
Merge with dev
Browse files Browse the repository at this point in the history
  • Loading branch information
heatherlogan-scottlogic committed Aug 4, 2023
2 parents 7810a95 + 004f57f commit 5e60a7e
Show file tree
Hide file tree
Showing 18 changed files with 178 additions and 142 deletions.
4 changes: 2 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import EmailBox from "./components/EmailBox/EmailBox";
import Header from "./components/Header";
import ModelSelectionBox from "./components/ModelSelectionBox/ModelSelectionBox";
import { useState } from "react";
import { OpenAIEmail } from "./service/emailService";
import { EmailInfo } from "./models/email";

function App() {
const [defenceBoxKey, setDefenceBoxKey] = useState<number>(0);
const [emails, setEmails] = useState<OpenAIEmail[]>([]);
const [emails, setEmails] = useState<EmailInfo[]>([]);
const [triggeredDefences, setTriggeredDefences] = useState<string[]>([]);

const updateTriggeredDefences = (defenceDetails: string[]) => {
Expand Down
31 changes: 31 additions & 0 deletions frontend/src/Defences.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DEFENCE_TYPES, DefenceInfo } from "./models/defence";

const DEFENCE_DETAILS: DefenceInfo[] = [
new DefenceInfo(
DEFENCE_TYPES.CHARACTER_LIMIT,
"Character Limit",
"Limit the number of characters in the user input. This is a form of prompt validation."
),
new DefenceInfo(
DEFENCE_TYPES.EMAIL_WHITELIST,
"Email Whitelist",
"Only allow emails to those on a whitelist. They can be full email addresses, or domains in the format '*@scottlogic.com'"
),
new DefenceInfo(
DEFENCE_TYPES.RANDOM_SEQUENCE_ENCLOSURE,
"Random Sequence Enclosure",
"Enclose the prompt between a random string and instruct bot to only follow enclosed instructions. This is a form of prompt validation."
),
new DefenceInfo(
DEFENCE_TYPES.SYSTEM_ROLE,
"System Role",
"Tell the chat bot to follow a specific role."
),
new DefenceInfo(
DEFENCE_TYPES.XML_TAGGING,
"XML Tagging",
"Enclose the users prompt between <user_input> tags and escapes xml characters in raw input. This is a form of prompt validation."
),
];

export { DEFENCE_DETAILS };
12 changes: 12 additions & 0 deletions frontend/src/Models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const MODELS = [
"gpt-4",
"gpt-4-0613",
"gpt-4-32k",
"gpt-4-32k-0613",
"gpt-3.5-turbo",
"gpt-3.5-turbo-0613",
"gpt-3.5-turbo-16k",
"gpt-3.5-turbo-16k-0613",
];

export { MODELS };
29 changes: 13 additions & 16 deletions frontend/src/components/ChatBox/ChatBox.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
import React, { useEffect, useState } from "react";
import "./ChatBox.css";
import ChatBoxFeed from "./ChatBoxFeed";
import {
OpenAIMessage,
OpenAIResponse,
clearOpenAiChat,
openAiSendMessage,
} from "../../service/openaiService";
import { OpenAIEmail, getSentEmails } from "../../service/emailService";
import { clearChat, sendMessage } from "../../service/chatService";
import { getSentEmails } from "../../service/emailService";
import { ChatMessage, ChatResponse } from "../../models/chat";
import { EmailInfo } from "../../models/email";

function ChatBox(
this: any,
{
setEmails,
updateTriggeredDefences,
}: {
setEmails: (emails: any) => void;
setEmails: (emails: EmailInfo[]) => void;
updateTriggeredDefences: (defences: string[]) => void;
}
) {
const [isSendingMessage, setIsSendingMessage] = useState<boolean>(false);
const [messages, setMessages] = useState<OpenAIMessage[]>([]);
const [messages, setMessages] = useState<ChatMessage[]>([]);

// called on mount
useEffect(() => {
// clear remote messages
clearOpenAiChat();
clearChat();
// get sent emails
getSentEmails().then((sentEmails) => {
setEmails(sentEmails);
Expand All @@ -36,7 +33,7 @@ function ChatBox(
// clear local messages
setMessages([]);
// clear remote messages
clearOpenAiChat();
clearChat();
};

const sendChatMessage = async (
Expand All @@ -48,19 +45,19 @@ function ChatBox(
const message = event.currentTarget.value;

// if input has been edited, add both messages to the list of messages. otherwise add original message only
setMessages((messages: OpenAIMessage[]) => [
setMessages((messages: ChatMessage[]) => [
...messages,
{ message: message, isUser: true, isOriginalMessage: true },
]);
// clear the input
event.currentTarget.value = "";

const response: OpenAIResponse = await openAiSendMessage(message);
const response: ChatResponse = await sendMessage(message);
const transformedMessage = response.transformedMessage;
const isTransformed = transformedMessage !== message;
// add the transformed message to the chat box if it is different from the original message
if (isTransformed) {
setMessages((messages: OpenAIMessage[]) => [
setMessages((messages: ChatMessage[]) => [
...messages,
{
message: transformedMessage,
Expand All @@ -70,7 +67,7 @@ function ChatBox(
]);
}
// add it to the list of messages
setMessages((messages: OpenAIMessage[]) => [
setMessages((messages: ChatMessage[]) => [
...messages,
{
isUser: false,
Expand All @@ -86,7 +83,7 @@ function ChatBox(
setIsSendingMessage(false);

// get sent emails
const sentEmails: OpenAIEmail[] = await getSentEmails();
const sentEmails: EmailInfo[] = await getSentEmails();
// update emails
setEmails(sentEmails);
}
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/ChatBox/ChatBoxFeed.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from "react";
import { OpenAIMessage } from "../../service/openaiService";
import "./ChatBoxFeed.css";
import { ChatMessage } from "../../models/chat";
import ChatBoxMessage from "./ChatBoxMessage";

function ChatBoxFeed({ messages }: { messages: OpenAIMessage[] }) {
function ChatBoxFeed({ messages }: { messages: ChatMessage[] }) {
return (
<div id="chat-box-feed">
{[...messages].reverse().map((message, index) => {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/ChatBox/ChatBoxMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from "react";
import { OpenAIMessage } from "../../service/openaiService";
import { ChatMessage } from "../../models/chat";
import "./ChatBoxMessage.css";

function ChatBoxMessage({ message }: { message: OpenAIMessage }) {
function ChatBoxMessage({ message }: { message: ChatMessage }) {
return (
<div
className={
Expand Down
23 changes: 6 additions & 17 deletions frontend/src/components/DefenceBox/DefenceBox.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
import React from "react";
import { useEffect, useState } from "react";
import "./DefenceBox.css";
import DefenceMechanism from "./DefenceMechanism";
import {
getActiveDefences,
activateDefence,
deactivateDefence,
DEFENCE_DETAILS,
} from "../../service/defenceService";
import { DEFENCE_DETAILS } from "../../Defences";

function DefenceBox({ triggeredDefences }: { triggeredDefences: string[] }) {
// list of defence mechanisms
const [defenceDetails, setDefenceDetails] = useState(
DEFENCE_DETAILS.map((defence) => {
return {
...defence,
isActive: false,
isTriggered: false,
};
})
);
const [defenceDetails, setDefenceDetails] = useState(DEFENCE_DETAILS);

// called on mount
useEffect(() => {
// fetch defences from backend
getActiveDefences().then((activeDefences) => {
const newDefencesDetails = defenceDetails.map((defencesDetail) => {
defencesDetail.isActive = activeDefences.includes(defencesDetail.type);
defencesDetail.isActive = activeDefences.includes(defencesDetail.id);
return defencesDetail;
});
setDefenceDetails(newDefencesDetails);
Expand All @@ -39,9 +30,7 @@ function DefenceBox({ triggeredDefences }: { triggeredDefences: string[] }) {
console.log("updating triggered defences: ", triggeredDefences);
// update state
const newDefences = defenceDetails.map((defenceDetail) => {
defenceDetail.isTriggered = triggeredDefences.includes(
defenceDetail.type
);
defenceDetail.isTriggered = triggeredDefences.includes(defenceDetail.id);
return defenceDetail;
});
setDefenceDetails(newDefences);
Expand All @@ -52,7 +41,7 @@ function DefenceBox({ triggeredDefences }: { triggeredDefences: string[] }) {
activateDefence(defenceType).then(() => {
// update state
const newDefenceDetails = defenceDetails.map((defenceDetail) => {
if (defenceDetail.type === defenceType) {
if (defenceDetail.id === defenceType) {
defenceDetail.isActive = true;
defenceDetail.isTriggered = false;
}
Expand All @@ -66,7 +55,7 @@ function DefenceBox({ triggeredDefences }: { triggeredDefences: string[] }) {
deactivateDefence(defenceType).then(() => {
// update state
const newDefenceDetails = defenceDetails.map((defenceDetail) => {
if (defenceDetail.type === defenceType) {
if (defenceDetail.id === defenceType) {
defenceDetail.isActive = false;
defenceDetail.isTriggered = false;
}
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/DefenceBox/DefenceMechanism.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from "react";
import { OpenAIDefence } from "../../service/defenceService";
import { useState } from "react";
import { DefenceInfo } from "../../models/defence";
import "./DefenceMechanism.css";

const ANIMATION_FLASH_TIME_SECONDS = 1;
Expand All @@ -12,7 +12,7 @@ function DefenceMechanism({
setDefenceInactive,
}: {
key: number;
defenceDetail: OpenAIDefence;
defenceDetail: DefenceInfo;
setDefenceActive: (defenceId: string) => void;
setDefenceInactive: (defenceId: string) => void;
}) {
Expand Down Expand Up @@ -50,8 +50,8 @@ function DefenceMechanism({
}
onClick={() => {
defenceDetail.isActive
? setDefenceInactive(defenceDetail.type)
: setDefenceActive(defenceDetail.type);
? setDefenceInactive(defenceDetail.id)
: setDefenceActive(defenceDetail.id);
}}
>
<div className="defence-mechanism-header">
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/components/EmailBox/EmailBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from "react";
import SentEmail from "./SentEmail";
import "./EmailBox.css";
import { OpenAIEmail } from "../../service/emailService";
import SentEmail from "./SentEmail";
import { EmailInfo } from "../../models/email";

function EmailBox({ emails }: { emails: OpenAIEmail[] }) {
function EmailBox({ emails }: { emails: EmailInfo[] }) {
return (
<div id="email-box-feed">
{[...emails].reverse().map((email, index) => {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/EmailBox/SentEmail.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from "react";
import { OpenAIEmail } from "../../service/emailService";
import "./SentEmail.css";
import { EmailInfo } from "../../models/email";

function SentEmail({
emailDetails,
key,
}: {
emailDetails: OpenAIEmail;
emailDetails: EmailInfo;
key: number;
}) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#model-selection-info p {
margin: 0;
padding: 0;
color:cadetblue
}

#model-selection-row p {
Expand All @@ -24,7 +25,7 @@
}

#model-selection-menu {
width: 50%;
width: 60%;
padding: 5px;
margin-right: 10px;
}
Expand Down
33 changes: 16 additions & 17 deletions frontend/src/components/ModelSelectionBox/ModelSelectionBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,29 @@
import React, { useEffect, useState } from "react";
import "./ModelSelectionBox.css";
import { setGptModel, getGptModel } from "../../service/openaiService";
import { MODELS } from "../../Models";

// return a drop down menu with the models
function ModelSelectionBox() {
const modelList = [
"gpt-4",
"gpt-4-0613",
"gpt-4-32k",
"gpt-4-32k-0613",
"gpt-3.5-turbo",
"gpt-3.5-turbo-0613",
"gpt-3.5-turbo-16k",
"gpt-3.5-turbo-16k-0613",
];

// model currently selected in the dropdown
const [selectedModel, setSelectedModel] = useState("gpt-4");
// model in use by the app
const [modelInUse, setModelInUse] = useState("gpt-4");

// handle button click to log the selected model
const submitSelectedModel = async () => {
console.log("selected model: " + selectedModel);
await setGptModel(selectedModel);
if (await setGptModel(selectedModel)) {
setModelInUse(selectedModel);
}
};

// get the model
useEffect(() => {
const getModel = async () => {
const model = await getGptModel();
if (model) {
console.log("Previous set model: " + model);
setSelectedModel(model);
setModelInUse(model);
}
};
getModel();
Expand All @@ -40,14 +34,14 @@ function ModelSelectionBox() {
return (
<div id="model-selection-box">
<div id="model-selection-row">
<p>Select a model: {selectedModel} </p>
<p>Select a model: </p>
<select
id="model-selection-menu"
aria-label="model-select"
onChange={(e) => setSelectedModel(e.target.value)}
placeholder={selectedModel}
placeholder={modelInUse}
>
{modelList.map((model) => (
{MODELS.map((model) => (
<option value={model}>{model}</option>
))}
;
Expand All @@ -59,6 +53,11 @@ function ModelSelectionBox() {
Choose
</button>
</div>
<div id="model-selection-info">
<p>
You are chatting to model: <b> {modelInUse}</b>
</p>
</div>
</div>
);
}
Expand Down
Loading

0 comments on commit 5e60a7e

Please sign in to comment.