Rsr2425 commited on
Commit
16339ba
·
1 Parent(s): b22f9a0

Added topics field to FE

Browse files
backend/app/main.py CHANGED
@@ -90,7 +90,7 @@ async def get_feedback(request: FeedbackRequest):
90
  raise HTTPException(status_code=500, detail=str(e))
91
 
92
 
93
- @app.post("/api/topics", response_model=TopicsResponse)
94
  async def get_topics():
95
  sources = get_all_unique_source_of_docs_in_collection_DUMB()
96
  return {"sources": sources}
 
90
  raise HTTPException(status_code=500, detail=str(e))
91
 
92
 
93
+ @app.get("/api/topics", response_model=TopicsResponse)
94
  async def get_topics():
95
  sources = get_all_unique_source_of_docs_in_collection_DUMB()
96
  return {"sources": sources}
frontend/src/App.tsx CHANGED
@@ -1,8 +1,9 @@
1
- import { Container, CssBaseline, ThemeProvider, createTheme, Button, Box, Typography, Alert } from '@mui/material';
2
  import Header from './components/Header';
3
  import DocumentInput from './components/DocumentInput';
4
  import QuizGenerator from './components/QuizGenerator';
5
  import ProblemAnswer from './components/ProblemAnswer';
 
6
  import { useState } from 'react';
7
  import { Problem } from './types/Problem';
8
 
@@ -25,6 +26,8 @@ function App() {
25
  const [problems, setProblems] = useState<ProblemWithFeedback[]>([]);
26
  const [quizTopic, setQuizTopic] = useState<string>('');
27
  const [error, setError] = useState<string | null>(null);
 
 
28
 
29
  const handleProblemsGenerated = (newProblems: string[], query: string) => {
30
  const problemObjects = newProblems.map(question => ({ question }));
@@ -40,9 +43,14 @@ function App() {
40
  });
41
  };
42
 
 
 
 
 
43
  const handleSubmit = async () => {
44
  try {
45
  setError(null);
 
46
 
47
  // Validate that all problems have answers
48
  const unansweredProblems = problems.some(p => !p.userAnswer);
@@ -58,8 +66,9 @@ function App() {
58
  },
59
  body: JSON.stringify({
60
  user_query: quizTopic,
 
61
  problems: problems.map(p => p.question),
62
- user_answers: problems.map(p => p.userAnswer as string) // We can safely cast since we validated above
63
  })
64
  });
65
 
@@ -78,6 +87,8 @@ function App() {
78
  );
79
  } catch (error) {
80
  setError(error instanceof Error ? error.message : 'An error occurred');
 
 
81
  }
82
  };
83
 
@@ -87,6 +98,7 @@ function App() {
87
  <Container maxWidth="md" sx={{ py: 4 }}>
88
  <Header />
89
  <DocumentInput />
 
90
  <QuizGenerator onProblemsGenerated={handleProblemsGenerated} />
91
 
92
  {error && (
@@ -116,15 +128,17 @@ function App() {
116
  ))}
117
 
118
  {problems.length > 0 && (
119
- <Box sx={{ mt: 4, display: 'flex', justifyContent: 'center' }}>
120
  <Button
121
  variant="contained"
122
  color="primary"
123
  size="large"
124
  onClick={handleSubmit}
 
125
  >
126
- Submit for Feedback
127
  </Button>
 
128
  </Box>
129
  )}
130
  </Container>
 
1
+ import { Container, CssBaseline, ThemeProvider, createTheme, Button, Box, Typography, Alert, CircularProgress } from '@mui/material';
2
  import Header from './components/Header';
3
  import DocumentInput from './components/DocumentInput';
4
  import QuizGenerator from './components/QuizGenerator';
5
  import ProblemAnswer from './components/ProblemAnswer';
6
+ import Topics from './components/Topics';
7
  import { useState } from 'react';
8
  import { Problem } from './types/Problem';
9
 
 
26
  const [problems, setProblems] = useState<ProblemWithFeedback[]>([]);
27
  const [quizTopic, setQuizTopic] = useState<string>('');
28
  const [error, setError] = useState<string | null>(null);
29
+ const [isSubmitting, setIsSubmitting] = useState(false);
30
+ const [selectedTopic, setSelectedTopic] = useState<string>('');
31
 
32
  const handleProblemsGenerated = (newProblems: string[], query: string) => {
33
  const problemObjects = newProblems.map(question => ({ question }));
 
43
  });
44
  };
45
 
46
+ const handleTopicChange = (topic: string) => {
47
+ setSelectedTopic(topic);
48
+ };
49
+
50
  const handleSubmit = async () => {
51
  try {
52
  setError(null);
53
+ setIsSubmitting(true);
54
 
55
  // Validate that all problems have answers
56
  const unansweredProblems = problems.some(p => !p.userAnswer);
 
66
  },
67
  body: JSON.stringify({
68
  user_query: quizTopic,
69
+ selected_topic: selectedTopic,
70
  problems: problems.map(p => p.question),
71
+ user_answers: problems.map(p => p.userAnswer as string)
72
  })
73
  });
74
 
 
87
  );
88
  } catch (error) {
89
  setError(error instanceof Error ? error.message : 'An error occurred');
90
+ } finally {
91
+ setIsSubmitting(false);
92
  }
93
  };
94
 
 
98
  <Container maxWidth="md" sx={{ py: 4 }}>
99
  <Header />
100
  <DocumentInput />
101
+ <Topics onTopicChange={handleTopicChange} />
102
  <QuizGenerator onProblemsGenerated={handleProblemsGenerated} />
103
 
104
  {error && (
 
128
  ))}
129
 
130
  {problems.length > 0 && (
131
+ <Box sx={{ mt: 4, display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 2 }}>
132
  <Button
133
  variant="contained"
134
  color="primary"
135
  size="large"
136
  onClick={handleSubmit}
137
+ disabled={isSubmitting}
138
  >
139
+ {isSubmitting ? 'Submitting...' : 'Submit for Feedback'}
140
  </Button>
141
+ {isSubmitting && <CircularProgress size={24} />}
142
  </Box>
143
  )}
144
  </Container>
frontend/src/components/QuizGenerator.tsx CHANGED
@@ -38,7 +38,7 @@ function QuizGenerator({ onProblemsGenerated }: QuizGeneratorProps) {
38
  <Box sx={{ mb: 4, display: 'flex', gap: 2 }}>
39
  <TextField
40
  fullWidth
41
- label="Quiz topic?"
42
  value={query}
43
  onChange={(e) => setQuery(e.target.value)}
44
  disabled={isLoading}
 
38
  <Box sx={{ mb: 4, display: 'flex', gap: 2 }}>
39
  <TextField
40
  fullWidth
41
+ label="Quiz focus?"
42
  value={query}
43
  onChange={(e) => setQuery(e.target.value)}
44
  disabled={isLoading}
frontend/src/components/Topics.tsx ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormControl, InputLabel, Select, MenuItem, SelectChangeEvent } from '@mui/material';
2
+ import { useEffect, useState } from 'react';
3
+
4
+ interface TopicsProps {
5
+ onTopicChange: (topic: string) => void;
6
+ }
7
+
8
+ interface TopicsResponse {
9
+ sources: string[];
10
+ }
11
+
12
+ export default function Topics({ onTopicChange }: TopicsProps) {
13
+ const [topics, setTopics] = useState<string[]>([]);
14
+ const [selectedTopic, setSelectedTopic] = useState('');
15
+ const [error, setError] = useState<string | null>(null);
16
+
17
+ useEffect(() => {
18
+ const fetchTopics = async () => {
19
+ try {
20
+ const response = await fetch('/api/topics');
21
+ if (!response.ok) {
22
+ throw new Error('Failed to fetch topics');
23
+ }
24
+ const data: TopicsResponse = await response.json();
25
+
26
+ // Validate that we received an array of sources
27
+ if (!data.sources || !Array.isArray(data.sources)) {
28
+ throw new Error('Invalid topics data received');
29
+ }
30
+
31
+ setTopics(data.sources);
32
+ } catch (error) {
33
+ console.error('Error fetching topics:', error);
34
+ setError('Failed to load topics');
35
+ setTopics([]); // Ensure topics is at least an empty array
36
+ }
37
+ };
38
+
39
+ fetchTopics();
40
+ }, []);
41
+
42
+ const handleChange = (event: SelectChangeEvent) => {
43
+ const topic = event.target.value;
44
+ setSelectedTopic(topic);
45
+ onTopicChange(topic);
46
+ };
47
+
48
+ return (
49
+ <FormControl fullWidth sx={{ mb: 2 }}>
50
+ <InputLabel>Topics</InputLabel>
51
+ <Select
52
+ value={selectedTopic}
53
+ label="Topics"
54
+ onChange={handleChange}
55
+ error={!!error}
56
+ >
57
+ {Array.isArray(topics) && topics.map((topic) => (
58
+ <MenuItem key={topic} value={topic}>
59
+ {topic}
60
+ </MenuItem>
61
+ ))}
62
+ </Select>
63
+ </FormControl>
64
+ );
65
+ }