Skip to content

Commit 081c075

Browse files
Merge branch 'main' into VoiceApi/Toggle
2 parents 06bb008 + 2c0e852 commit 081c075

File tree

79 files changed

+6908
-2783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+6908
-2783
lines changed

.github/workflows/deploy_gcp_core_backend.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ jobs:
6262
uses: "google-github-actions/get-secretmanager-secrets@v2"
6363
with:
6464
secrets: |-
65-
domain:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-domain
66-
jwt-secret:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-jwt-secret
67-
google-login-client-id:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-google-login-client-id
68-
langfuse-secret-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-langfuse-secret-key
69-
langfuse-public-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-langfuse-public-key
70-
db-host:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-db-host
71-
db-password:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-db-password
72-
admin-username:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-username
73-
admin-password:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-password
74-
admin-api-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-api-key
75-
gcp-credential-json:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-gcp-credential-json
65+
domain:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-domain
66+
jwt-secret:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-jwt-secret
67+
google-login-client-id:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-google-login-client-id
68+
langfuse-secret-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-langfuse-secret-key
69+
langfuse-public-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-langfuse-public-key
70+
db-host:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-db-host
71+
db-password:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-db-password
72+
admin-username:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-username
73+
admin-password:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-password
74+
admin-api-key:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-admin-api-key
75+
gcp-credential-json:${{ secrets.GCP_PROJECT_ID }}/${{ env.RESOURCE_PREFIX }}-gcp-credential-json
7676
7777
- name: Copy GCP credentials JSON
7878
working-directory: deployment/docker-compose

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ repos:
2929
hooks:
3030
- id: mypy
3131
exclude: ^data/|^scripts/
32-
additional_dependencies: [types-PyYAML==6.0.12.12, types-python-dateutil, redis]
32+
additional_dependencies:
33+
[types-PyYAML==6.0.12.12, types-python-dateutil, redis, types-requests]
3334
args: [--ignore-missing-imports, --explicit-package-base]
3435
- repo: https://github.com/pre-commit/mirrors-prettier
3536
rev: "v3.0.3" # Use the sha / tag you want to point at

.secrets.baseline

Lines changed: 105 additions & 106 deletions
Large diffs are not rendered by default.

admin_app/package-lock.json

Lines changed: 1721 additions & 1323 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

admin_app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
"axios": "^1.7.7",
2222
"date-fns": "^3.6.0",
2323
"jwt-decode": "^4.0.0",
24-
"next": "14.2.12",
24+
"next": "^14.2.23",
2525
"next-runtime-env": "^3.2.2",
2626
"papaparse": "^5.4.1",
2727
"react": "^18",
2828
"react-apexcharts": "^1.4.1",
29+
"react-datepicker": "^8.0.0",
2930
"react-dom": "^18"
3031
},
3132
"devDependencies": {

admin_app/src/app/content/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface ContentBody {
88
const getContentList = async ({
99
token,
1010
skip = 0,
11-
limit = 200,
11+
limit = 0,
1212
}: {
1313
token: string;
1414
skip?: number;
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
import React, { useEffect, useState } from "react";
2+
3+
import TypingAnimation from "@/components/TypingAnimation";
4+
import { Close, Send } from "@mui/icons-material";
5+
import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
6+
import CloseIcon from "@mui/icons-material/Close";
7+
import RestartAltIcon from "@mui/icons-material/RestartAlt";
8+
import {
9+
Avatar,
10+
Box,
11+
CircularProgress,
12+
Fade,
13+
IconButton,
14+
Link,
15+
Modal,
16+
Paper,
17+
TextField,
18+
Tooltip,
19+
Typography,
20+
} from "@mui/material";
21+
22+
import { appColors, sizes } from "@/utils";
23+
24+
interface ResponseSummary {
25+
index: string;
26+
title: string;
27+
text: string;
28+
}
29+
30+
interface BaseMessage {
31+
dateTime: string;
32+
type: "question" | "response";
33+
}
34+
35+
interface UserMessage extends BaseMessage {
36+
type: "question";
37+
content: string;
38+
}
39+
40+
interface ResponseMessage extends BaseMessage {
41+
type: "response";
42+
content: ResponseSummary[] | string;
43+
json: string;
44+
}
45+
46+
type Message = UserMessage | ResponseMessage;
47+
48+
const ChatSideBar = ({
49+
closeSidebar,
50+
getResponse,
51+
setSnackMessage,
52+
}: {
53+
closeSidebar: () => void;
54+
getResponse: (question: string, session_id?: number) => Promise<any>;
55+
setSnackMessage: (message: string) => void;
56+
}) => {
57+
const [loading, setLoading] = useState(false);
58+
const [question, setQuestion] = useState<string>("");
59+
const [messages, setMessages] = useState<Message[]>([]);
60+
const [sessionId, setSessionId] = useState<number | null>(null);
61+
const bottomRef = React.useRef<HTMLDivElement>(null); // Ref to scroll to bottom of chat
62+
63+
useEffect(() => {
64+
bottomRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
65+
}, [messages, loading]);
66+
const handleQuestionChange = (
67+
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
68+
) => {
69+
setQuestion(event.target.value);
70+
};
71+
72+
const processErrorMessage = (error: Error) => {
73+
setMessages((prevMessages) => [
74+
...prevMessages,
75+
{
76+
dateTime: new Date().toISOString(),
77+
type: "response",
78+
content: "API call failed. See JSON for details.",
79+
json: `{error: ${error.message}}`,
80+
},
81+
]);
82+
};
83+
const handleReset = () => {
84+
setMessages([]);
85+
setSessionId(null);
86+
};
87+
const handleSendClick = () => {
88+
setQuestion("");
89+
setMessages((prevMessages) => [
90+
...prevMessages,
91+
{
92+
dateTime: new Date().toISOString(),
93+
type: "question",
94+
content: question,
95+
} as UserMessage,
96+
]);
97+
setLoading(true);
98+
const responsePromise = sessionId
99+
? getResponse(question, sessionId)
100+
: getResponse(question);
101+
responsePromise
102+
.then((response) => {
103+
const errorMessage = response.error
104+
? response.error.error_message
105+
: "LLM Response failed.";
106+
const responseMessage = {
107+
dateTime: new Date().toISOString(),
108+
type: "response",
109+
content: response.status == 200 ? response.llm_response : errorMessage,
110+
json: response,
111+
} as ResponseMessage;
112+
113+
setMessages((prevMessages) => [...prevMessages, responseMessage]);
114+
if (sessionId === null) {
115+
setSessionId(response.session_id);
116+
}
117+
})
118+
.catch((error: Error) => {
119+
processErrorMessage(error);
120+
setSnackMessage(error.message);
121+
console.error(error);
122+
})
123+
.finally(() => {
124+
setLoading(false);
125+
});
126+
};
127+
128+
return (
129+
<Paper
130+
elevation={2}
131+
sx={{
132+
display: "flex",
133+
flexDirection: "column",
134+
padding: 3,
135+
paddingTop: 4,
136+
height: "94vh",
137+
}}
138+
>
139+
<Box
140+
display="flex"
141+
justifyContent="space-between"
142+
alignItems="center"
143+
marginBottom={4}
144+
>
145+
<Typography variant="h6">Test Chat</Typography>
146+
<IconButton onClick={closeSidebar}>
147+
<Close />
148+
</IconButton>
149+
</Box>
150+
<Box
151+
sx={{
152+
overflowY: "auto",
153+
flexGrow: 1,
154+
}}
155+
>
156+
{messages.map((message, index) => (
157+
<MessageBox key={index} {...message} />
158+
))}
159+
{loading ? (
160+
<Box display="flex" alignItems="center">
161+
<Avatar
162+
alt="FA"
163+
sx={{
164+
mr: 1,
165+
my: 1,
166+
width: sizes.icons.medium,
167+
height: sizes.icons.medium,
168+
bgcolor: "primary.main",
169+
}}
170+
>
171+
<AutoAwesomeIcon />
172+
</Avatar>
173+
<TypingAnimation />
174+
</Box>
175+
) : null}
176+
<div ref={bottomRef}></div>
177+
</Box>
178+
<Box display="flex" justifyContent="flex-end" margin={1}>
179+
<Tooltip title="Reset conversation" aria-label="reset">
180+
<IconButton
181+
onClick={handleReset}
182+
sx={{ color: appColors.primary }}
183+
disabled={loading}
184+
>
185+
<RestartAltIcon />
186+
<Typography variant="body2">Reset chat</Typography>
187+
</IconButton>
188+
</Tooltip>
189+
</Box>
190+
<Box
191+
sx={{
192+
padding: 2,
193+
border: 1,
194+
borderRadius: 1,
195+
borderColor: "grey.400",
196+
}}
197+
>
198+
<TextField
199+
variant="standard"
200+
placeholder="Ask a question..."
201+
fullWidth
202+
value={question}
203+
onChange={handleQuestionChange}
204+
onKeyDown={(event) => {
205+
if (event.key === "Enter" && loading === false) {
206+
handleSendClick();
207+
}
208+
}}
209+
InputProps={{ disableUnderline: true }}
210+
/>
211+
<Box
212+
display="flex"
213+
flexDirection="row"
214+
justifyContent="flex-end"
215+
paddingTop={2}
216+
>
217+
<IconButton
218+
onClick={handleSendClick}
219+
sx={{ color: appColors.primary }}
220+
disabled={loading || question == "" ? true : false}
221+
>
222+
{loading ? <CircularProgress size={24} /> : <Send />}
223+
</IconButton>
224+
</Box>
225+
</Box>
226+
</Paper>
227+
);
228+
};
229+
const MessageBox = (message: Message) => {
230+
const [open, setOpen] = useState(false);
231+
const toggleJsonModal = () => setOpen(!open);
232+
const modalStyle = {
233+
position: "absolute",
234+
top: "50%",
235+
left: "50%",
236+
transform: "translate(-50%, -50%)",
237+
width: "80%",
238+
maxHeight: "80%",
239+
flexGrow: 1,
240+
bgcolor: "background.paper",
241+
boxShadow: 24,
242+
p: 4,
243+
overflow: "scroll",
244+
borderRadius: "10px",
245+
};
246+
const avatarOrder = message.type === "question" ? 2 : 0;
247+
const contentOrder = 1;
248+
const messageBubbleStyles = {
249+
py: 1.5,
250+
px: 2,
251+
borderRadius: "15px",
252+
bgcolor: message.type === "question" ? appColors.lightGrey : appColors.primary,
253+
color: message.type === "question" ? "black" : "white",
254+
maxWidth: "75%",
255+
wordBreak: "break-word",
256+
order: contentOrder,
257+
};
258+
return (
259+
<Box
260+
sx={{
261+
display: "flex",
262+
alignItems: "center",
263+
justifyContent: message.type === "question" ? "flex-end" : "flex-start",
264+
mb: 1,
265+
}}
266+
>
267+
{message.type === "response" && (
268+
<Avatar
269+
alt="FA"
270+
sx={{
271+
mr: 1,
272+
my: 1,
273+
width: sizes.icons.medium,
274+
height: sizes.icons.medium,
275+
bgcolor: "primary.main",
276+
alignSelf: "flex-end",
277+
order: avatarOrder,
278+
}}
279+
>
280+
<AutoAwesomeIcon />
281+
</Avatar>
282+
)}
283+
284+
<Box sx={messageBubbleStyles}>
285+
<Typography component={"span"} variant="body1" align="left">
286+
{typeof message.content === "string" ? message.content : null}
287+
</Typography>
288+
{message.hasOwnProperty("json") && (
289+
<Link
290+
onClick={toggleJsonModal}
291+
variant="caption"
292+
align="right"
293+
underline="hover"
294+
sx={{ cursor: "pointer", display: "block", color: appColors.white }}
295+
>
296+
{"<json>"}
297+
</Link>
298+
)}
299+
</Box>
300+
301+
<Modal
302+
open={open}
303+
onClose={toggleJsonModal}
304+
aria-labelledby="modal-modal-title"
305+
aria-describedby="modal-modal-description"
306+
>
307+
<Fade in={!!open}>
308+
<Box sx={modalStyle}>
309+
<Box sx={{ display: "flex", justifyContent: "flex-end" }}>
310+
<IconButton onClick={toggleJsonModal}>
311+
<CloseIcon />
312+
</IconButton>
313+
</Box>
314+
<Typography component={"span"} id="modal-modal-description" sx={{ mt: 2 }}>
315+
<pre
316+
style={{
317+
backgroundColor: "#f5f5f5",
318+
border: "1px solid #ccc",
319+
padding: "10px",
320+
borderRadius: "10px",
321+
overflowX: "auto",
322+
fontFamily: "Courier, monospace",
323+
}}
324+
>
325+
{"json" in message
326+
? JSON.stringify(message.json, null, 2)
327+
: "No JSON message found"}
328+
</pre>
329+
</Typography>
330+
</Box>
331+
</Fade>
332+
</Modal>
333+
</Box>
334+
);
335+
};
336+
export { ChatSideBar };

0 commit comments

Comments
 (0)