Skip to content

Commit a05bff7

Browse files
committed
feat: Rag creator UX improvements & localization
1 parent 449f2bc commit a05bff7

File tree

7 files changed

+155
-61
lines changed

7 files changed

+155
-61
lines changed

src/client/components/Courses/Course/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ const Course = () => {
287287
<Tab label={t('course:stats')} to={`/courses/${id}`} component={Link} />
288288
<Tab label={t('course:discussions')} to={`/courses/${id}/discussions`} component={Link} />
289289
<Tab label={t('course:prompts')} to={`/courses/${id}/prompts`} component={Link} />
290-
<Tab label={t('course:rag')} to={`/courses/${id}/rag`} component={Link} />
290+
<Tab label={t('course:sourceMaterials')} to={`/courses/${id}/rag`} component={Link} />
291291
</RouterTabs>
292292
</Box>
293293

src/client/components/Rag/Rag.tsx

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,60 +17,26 @@ import {
1717
MenuItem,
1818
InputLabel,
1919
} from '@mui/material'
20-
import { useNavigate, Link as RouterLink, useParams } from 'react-router-dom'
21-
import { useCourseRagIndices, useRagIndices } from '../../hooks/useRagIndices'
22-
import { useCreateRagIndexMutation } from './api'
20+
import { Link as RouterLink, useParams } from 'react-router-dom'
21+
import { useCourseRagIndices } from '../../hooks/useRagIndices'
2322
import useCourse from '../../hooks/useCourse'
23+
import { RagCreator } from './RagCreator'
24+
import { useTranslation } from 'react-i18next'
2425

2526
const Rag: React.FC = () => {
27+
const { t } = useTranslation()
2628
const { id: courseId } = useParams<{ id: string }>()
2729
const { data: chatInstance } = useCourse(courseId)
28-
const navigate = useNavigate()
30+
2931
const { ragIndices } = useCourseRagIndices(chatInstance?.id, true)
30-
const createIndexMutation = useCreateRagIndexMutation()
31-
const [indexName, setIndexName] = useState('')
32-
const [language, setLanguage] = useState<'Finnish' | 'English'>('English')
3332

3433
return (
3534
<Container sx={{ display: 'flex', gap: 2, mt: '4rem', mb: '10rem' }} maxWidth="xl">
3635
<Box>
3736
<Typography variant="h4" mb="1rem">
38-
RAG Indices
37+
{t('rag:sourceMaterials')}
3938
</Typography>
40-
{chatInstance?.id && (
41-
<Box sx={{ display: 'flex', gap: 2, marginBottom: 2 }}>
42-
<TextField
43-
label="Index Name"
44-
helperText="Use a descriptive name. It is shown to users when RAG is used."
45-
variant="outlined"
46-
value={indexName}
47-
onChange={(e) => setIndexName(e.target.value)}
48-
fullWidth
49-
/>
50-
<FormControl fullWidth>
51-
<InputLabel id="language-label">Language</InputLabel>
52-
<Select labelId="language-label" id="language-select" value={language} onChange={(e) => setLanguage(e.target.value as 'Finnish' | 'English')}>
53-
<MenuItem value={'Finnish'}>Finnish</MenuItem>
54-
<MenuItem value={'English'}>English</MenuItem>
55-
</Select>
56-
</FormControl>
57-
<Button
58-
variant="contained"
59-
color="primary"
60-
onClick={async () => {
61-
const newIndex = await createIndexMutation.mutateAsync({
62-
chatInstanceId: chatInstance?.id,
63-
indexName,
64-
language,
65-
})
66-
setIndexName('')
67-
navigate(`/rag/${newIndex.id}`)
68-
}}
69-
>
70-
Create Index
71-
</Button>
72-
</Box>
73-
)}
39+
{chatInstance?.id && <RagCreator chatInstance={chatInstance} />}
7440
{ragIndices?.map((index) => (
7541
<Paper
7642
key={index.id}
@@ -82,10 +48,10 @@ const Rag: React.FC = () => {
8248
<Table sx={{ mb: 1 }}>
8349
<TableHead>
8450
<TableRow>
85-
<TableCell>ID</TableCell>
86-
<TableCell>Name</TableCell>
87-
<TableCell>Language</TableCell>
88-
<TableCell>Number of files</TableCell>
51+
<TableCell>{t('rag:id')}</TableCell>
52+
<TableCell>{t('rag:name')}</TableCell>
53+
<TableCell>{t('rag:language')}</TableCell>
54+
<TableCell>{t('rag:numberOfFiles')}</TableCell>
8955
</TableRow>
9056
</TableHead>
9157
<TableBody>
@@ -99,7 +65,7 @@ const Rag: React.FC = () => {
9965
</Table>
10066
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
10167
<Link to={`/rag/${index.id}`} component={RouterLink} sx={{ ml: 'auto' }}>
102-
View details
68+
{t('rag:viewDetails')}
10369
</Link>
10470
</Box>
10571
</Paper>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { useState } from 'react'
2+
import { useCreateRagIndexMutation } from './api'
3+
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, InputLabel, MenuItem, Select, TextField } from '@mui/material'
4+
import { OutlineButtonBlack } from '../ChatV2/general/Buttons'
5+
import { useNavigate } from 'react-router-dom'
6+
import type { Course } from '../../types'
7+
import { useTranslation } from 'react-i18next'
8+
9+
export const RagCreator = ({ chatInstance }: { chatInstance: Course }) => {
10+
const { t } = useTranslation()
11+
const navigate = useNavigate()
12+
const createIndexMutation = useCreateRagIndexMutation()
13+
const [indexName, setIndexName] = useState('')
14+
const [language, setLanguage] = useState<'Finnish' | 'English'>('English')
15+
const [open, setOpen] = useState(false)
16+
17+
return (
18+
<>
19+
<OutlineButtonBlack onClick={() => setOpen(true)}>{t('rag:createNewIndex')}</OutlineButtonBlack>
20+
<Dialog
21+
open={open}
22+
onClose={() => setOpen(false)}
23+
slotProps={{
24+
paper: {
25+
component: 'form',
26+
onSubmit: async (event: React.FormEvent<HTMLFormElement>) => {
27+
event.preventDefault()
28+
const newIndex = await createIndexMutation.mutateAsync({
29+
chatInstanceId: chatInstance?.id,
30+
indexName,
31+
language,
32+
})
33+
setIndexName('')
34+
navigate(`/rag/${newIndex.id}`)
35+
setOpen(false)
36+
},
37+
},
38+
}}
39+
>
40+
<DialogTitle>{t('rag:createNewIndex')}</DialogTitle>
41+
<DialogContent>
42+
<DialogContentText>{t('rag:creatorGuide')}</DialogContentText>
43+
<TextField
44+
label={t('rag:nameLabel')}
45+
helperText={t('rag:nameHelperText')}
46+
variant="outlined"
47+
value={indexName}
48+
onChange={(e) => setIndexName(e.target.value)}
49+
fullWidth
50+
required
51+
slotProps={{
52+
htmlInput: { minLength: 5 },
53+
}}
54+
sx={{ my: '2rem' }}
55+
/>
56+
<FormControl fullWidth sx={{ my: '2rem' }}>
57+
<InputLabel id="language-label">{t('rag:language')}</InputLabel>
58+
<Select labelId="language-label" id="language-select" value={language} onChange={(e) => setLanguage(e.target.value as 'Finnish' | 'English')}>
59+
<MenuItem value={'Finnish'}>{t('rag:finnish')}</MenuItem>
60+
<MenuItem value={'English'}>{t('rag:english')}</MenuItem>
61+
</Select>
62+
</FormControl>
63+
</DialogContent>
64+
<DialogActions>
65+
<OutlineButtonBlack color="primary" type="submit">
66+
{t('rag:createIndex')}
67+
</OutlineButtonBlack>
68+
</DialogActions>
69+
</Dialog>
70+
</>
71+
)
72+
}

src/client/components/Rag/RagFile.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import { RagFileInfo } from './RagFileDetails'
77
import type { RagIndexAttributes } from '../../../server/db/models/ragIndex'
88
import { Chunk } from './Chunk'
99
import { useDeleteRagFileMutation } from './api'
10+
import { useTranslation } from 'react-i18next'
1011

1112
type RagFile = RagFileAttributes & {
1213
fileContent: string
1314
ragIndex: RagIndexAttributes
1415
}
1516

1617
export const RagFile: React.FC = () => {
18+
const { t } = useTranslation()
1719
const { id, fileId } = useParams()
1820
const {
1921
data: ragFile,
@@ -41,9 +43,9 @@ export const RagFile: React.FC = () => {
4143
return (
4244
<Container sx={{ mt: '4rem', mb: '10rem' }} maxWidth="xl">
4345
<Link component={RouterLink} to={`/rag/${id}`}>
44-
Back to RAG Index
46+
{t('rag:backToCollection')}
4547
</Link>
46-
<Typography variant="body1">RAG file</Typography>
48+
<Typography variant="body1">{t('rag:file')}</Typography>
4749
<Typography variant="h3">
4850
{ragFile.ragIndex.metadata?.name} / {ragFile.filename}
4951
</Typography>
@@ -61,12 +63,12 @@ export const RagFile: React.FC = () => {
6163
}
6264
}}
6365
>
64-
Delete File
66+
{t('rag:deleteFile')}
6567
</Button>
6668
<RagFileInfo file={ragFile} />
67-
<Typography variant="h4">Content</Typography>
69+
<Typography variant="h4">{t('rag:content')}</Typography>
6870
{ragFile.fileContent.length === 0 ? (
69-
<Typography variant="body1">No content</Typography>
71+
<Typography variant="body1">{t('rag:noContent')}</Typography>
7072
) : (
7173
<Chunk
7274
doc={{

src/client/components/Rag/RagIndex.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { orderBy } from 'lodash'
66
import { RagFileInfo } from './RagFileDetails'
77
import { useDeleteRagIndexMutation, useRagIndexDetails, useUploadMutation } from './api'
88
import { Search } from './Search'
9+
import { useTranslation } from 'react-i18next'
910

1011
const VisuallyHiddenInput = styled('input')({
1112
clip: 'rect(0 0 0 0)',
@@ -20,6 +21,7 @@ const VisuallyHiddenInput = styled('input')({
2021
})
2122

2223
export const RagIndex: React.FC = () => {
24+
const { t } = useTranslation()
2325
const { id: strId } = useParams() as { id: string }
2426
const navigate = useNavigate()
2527
const id = parseInt(strId, 10)
@@ -33,12 +35,12 @@ export const RagIndex: React.FC = () => {
3335

3436
return (
3537
<Container sx={{ mt: '4rem', mb: '10rem' }} maxWidth="xl">
36-
<Typography variant="body1">RAG index</Typography>
38+
<Typography variant="body1">{t('rag:collection')}</Typography>
3739
<Typography variant="h3">{ragDetails?.metadata?.name}</Typography>
3840
<Box py={2}>
3941
<Box sx={{ display: 'flex', gap: 2 }}>
4042
<Button component="label" variant="contained" tabIndex={-1} startIcon={<CloudUpload />} disabled={uploadMutation.isPending}>
41-
{uploadMutation.isPending ? 'Uploading...' : 'Upload Files'}
43+
{uploadMutation.isPending ? t('rag:uploading') : t('rag:uploadFiles')}
4244
<VisuallyHiddenInput
4345
type="file"
4446
onChange={async (event) => {
@@ -62,12 +64,12 @@ export const RagIndex: React.FC = () => {
6264
}
6365
}}
6466
>
65-
Delete Index
67+
{t('rag:deleteCollection')}
6668
</Button>
6769
</Box>
6870
<Search ragIndex={ragDetails} />
6971
<Box mt={2}>
70-
<Typography variant="h6">Files:</Typography>
72+
<Typography variant="h6">{t('rag:files')}</Typography>
7173
{orderBy(ragDetails?.ragFiles, [(f) => Date.parse(f.createdAt as unknown as string)], ['desc']).map((file) => (
7274
<RagFileInfo key={file.id} file={file} link />
7375
))}

src/client/locales/en.json

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@
291291
"rag": "RAG",
292292
"remove": "remove",
293293
"customResponsibility": "manually added",
294-
"add": "add"
294+
"add": "add",
295+
"sourceMaterials": "Source materials"
295296
},
296297
"tooltip": {
297298
"copied": "Copied!"
@@ -323,5 +324,30 @@
323324
"toNewline": "to add a new line",
324325
"ok": "Ok",
325326
"openConfigurator": "Keyboard shortcut for sending a message"
327+
},
328+
"rag": {
329+
"sourceMaterials": "Source materials",
330+
"id": "ID",
331+
"name": "Name",
332+
"language": "Language",
333+
"numberOfFiles": "Number of files",
334+
"viewDetails": "View details",
335+
"collection": "Source material collection",
336+
"deleteCollection": "Delete collection",
337+
"files": "Source material files",
338+
"backToCollection": "Back to collection",
339+
"file": "Source material file",
340+
"deleteFile": "Delete file",
341+
"content": "Content",
342+
"noContent": "No content",
343+
"creatorGuide": "A RAG index is a collection of documents that are indexed for semantic search and retrieval. Students may activate it in the course chat, which gives the LLM a tool to retrieve relevant information from the index based on a query which it will base its response on. The index name, description and language are especially important as the LLM will use them to decide when to search the index and how to formulate the search query.",
344+
"uploading": "Uploading",
345+
"uploadFiles": "Upload files",
346+
"createNewIndex": "Create a new collection",
347+
"finnish": "Finnish",
348+
"english": "English",
349+
"createIndex": "Create collection",
350+
"nameLabel": "Collection name",
351+
"nameHelperText": "Use a descriptive name (for example the full name of the course)"
326352
}
327-
}
353+
}

src/client/locales/fi.json

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@
291291
"rag": "RAG",
292292
"remove": "poista",
293293
"customResponsibility": "manuaalisesti lisätty",
294-
"add": "lisää"
294+
"add": "lisää",
295+
"sourceMaterials": "Lähdemateriaalit"
295296
},
296297
"tooltip": {
297298
"copied": "Kopioitu!"
@@ -323,5 +324,30 @@
323324
"toNewline": "lisää uuden rivin",
324325
"ok": "Ok",
325326
"openConfigurator": "Viestin lähetyksen näppäinyhdistelmä"
327+
},
328+
"rag": {
329+
"sourceMaterials": "Lähdemateriaalit",
330+
"id": "ID",
331+
"name": "Name",
332+
"language": "Kieli",
333+
"numberOfFiles": "Tiedostojen lukumäärä",
334+
"viewDetails": "Lisätiedot",
335+
"collection": "Lähdemateriaalikokoelma",
336+
"deleteCollection": "Poista kokoelma",
337+
"files": "Lähdemateriaalin tiedostot",
338+
"backToCollection": "Takaisin kokoelmaan",
339+
"file": "Lähdemateriaalin tiedosto",
340+
"deleteFile": "Poista tiedosto",
341+
"content": "Sisältö",
342+
"noContent": "Ei sisältöä",
343+
"creatorGuide": "Lähdemateriaalikokoelma on joukko tiedostoja, joista kielimalli voi hakea tietoa tarpeen mukaan. Opiskelija voi aktivoida lähdemateriaalikokoelman kurssichatissa, jolloin se tulee hakutyökaluna kielimallille näkyväksi. Kuvaava kokoelman nimi, kuvaus ja kieli ovat tärkeitä, koska kielimalli käyttää niitä hakukyselyn muodostamiseen ja päättelee niistä, milloin sen kannattaa tehdä lähdemateriaalihaku vastatakseen opiskelijalle.",
344+
"uploading": "Ladataan",
345+
"uploadFiles": "Lisää tiedostoja",
346+
"createNewIndex": "Luo uusi kokoelma",
347+
"finnish": "Suomi",
348+
"english": "Englanti",
349+
"createIndex": "Luo kokoelma",
350+
"nameLabel": "Kokoelman nimi",
351+
"nameHelperText": "Käytä kuvaavaa nimeä (esim. kurssin koko nimi)"
326352
}
327-
}
353+
}

0 commit comments

Comments
 (0)