Skip to content

Commit 76fa5af

Browse files
committed
add custom category and switch question type
1 parent a68b6c5 commit 76fa5af

File tree

8 files changed

+812
-104
lines changed

8 files changed

+812
-104
lines changed

app/page.tsx

Lines changed: 125 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import ConfirmationModal from "@/components/modals/confirmation-modal"
1010
import SettingsModal from "@/components/modals/settings-modal"
1111
import HistoryModal from "@/components/modals/history-modal"
1212
import LoadingQuestionModal from "@/components/modals/loading-question-modal"
13+
import AnswerDisplay from "@/components/answer-display"
1314
import { useState, useEffect, useCallback } from "react"
1415
import type { Question, UserAnswer, QuestionHistory } from "@/lib/types"
16+
import { QuestionType } from "@/lib/types"
1517
import { generateRandomQuestion } from "@/lib/question"
1618
import { useTranslation } from "@/lib/i18n"
1719
import { useToast } from "@/hooks/use-toast"
1820
// Update the onSubmit function to use the OpenAI API for evaluation
1921
import { evaluateAnswer, getModelAnswer } from "@/lib/api"
22+
import { cleanupJsonResponse } from "@/lib/utils"
2023

2124
export default function Page() {
2225
const { t, language, setLanguage } = useTranslation()
@@ -36,8 +39,13 @@ export default function Page() {
3639
const [isStreaming, setIsStreaming] = useState(false)
3740
const { toast } = useToast()
3841
const [questionHistory, setQuestionHistory] = useState<QuestionHistory[]>([])
42+
43+
// State for showing answer in the main content area instead of modal
44+
const [showInlineAnswer, setShowInlineAnswer] = useState(false)
45+
const [parsedAnswer, setParsedAnswer] = useState<any>(null)
3946

4047
const [isLoadingQuestion, setIsLoadingQuestion] = useState(true)
48+
const [forcedQuestionType, setForcedQuestionType] = useState<string | null>(null)
4149

4250
// 在组件加载时从本地存储加载历史记录
4351
useEffect(() => {
@@ -197,47 +205,81 @@ export default function Page() {
197205
setShowConfirmationModal(true)
198206
}
199207

200-
// Updated handleConfirmation function with streaming support
208+
// Updated handleConfirmation function to show answers inline
201209
const handleConfirmation = async () => {
210+
// Make sure modals are properly managed
211+
setShowAnswerModal(false);
212+
202213
if (confirmationStep < 2) {
203214
setConfirmationStep((prevStep) => prevStep + 1)
204-
} else {
205-
setShowConfirmationModal(false)
206-
setAnswer(null)
207-
setIsStreaming(true)
208-
setShowAnswerModal(true)
215+
return
216+
}
209217

210-
try {
211-
// Call OpenAI to get the model answer with streaming
212-
await getModelAnswer(currentQuestion, language, (streamingAnswer) => {
213-
setAnswer(streamingAnswer)
214-
})
218+
// Reset to start
219+
setConfirmationStep(0)
220+
setShowConfirmationModal(false)
221+
222+
if (!currentQuestion) {
223+
return
224+
}
225+
226+
// Set streaming state and prepare to display inline answer
227+
setIsStreaming(true)
228+
setShowInlineAnswer(true)
229+
setAnswer(null)
230+
setParsedAnswer(null)
215231

216-
setIsStreaming(false)
217-
setIsSubmitted(true)
232+
try {
233+
// Call OpenAI to get the model answer with streaming
234+
await getModelAnswer(currentQuestion, language, (streamingAnswer) => {
235+
setAnswer(streamingAnswer)
218236

219-
// 更新历史记录中的问题状态为已回答
220-
if (currentQuestion) {
221-
setQuestionHistory(prevHistory => {
222-
const updatedHistory = prevHistory.map(item =>
223-
item.id === currentQuestion.id
224-
? { ...item, answered: true }
225-
: item
226-
);
227-
localStorage.setItem("questionHistory", JSON.stringify(updatedHistory));
228-
return updatedHistory;
229-
});
237+
// Try to parse the streaming answer as it comes in
238+
try {
239+
const cleanedAnswer = cleanupJsonResponse(streamingAnswer)
240+
const parsed = JSON.parse(cleanedAnswer)
241+
setParsedAnswer(parsed)
242+
} catch (e) {
243+
// It's okay if parsing fails during streaming
230244
}
231-
} catch (error) {
232-
console.error("Error getting model answer:", error)
233-
setIsStreaming(false)
234-
toast({
235-
title: t("toast.error.title"),
236-
description: t("toast.error.description"),
237-
variant: "destructive",
238-
duration: 5000,
239-
})
245+
})
246+
247+
setIsStreaming(false)
248+
setIsSubmitted(true)
249+
250+
// Once streaming is complete, try to parse the final answer
251+
try {
252+
if (answer) {
253+
const cleanedAnswer = cleanupJsonResponse(answer)
254+
const parsed = JSON.parse(cleanedAnswer)
255+
setParsedAnswer(parsed)
256+
}
257+
} catch (e) {
258+
// Keep using the raw answer if parsing fails
259+
console.error("Failed to parse answer:", e)
260+
}
261+
262+
// 更新历史记录中的问题状态为已回答
263+
if (currentQuestion) {
264+
setQuestionHistory(prevHistory => {
265+
const updatedHistory = prevHistory.map(item =>
266+
item.id === currentQuestion.id
267+
? { ...item, answered: true }
268+
: item
269+
);
270+
localStorage.setItem("questionHistory", JSON.stringify(updatedHistory));
271+
return updatedHistory;
272+
});
240273
}
274+
} catch (error) {
275+
console.error("Error getting model answer:", error)
276+
setIsStreaming(false)
277+
toast({
278+
title: t("toast.error.title"),
279+
description: t("toast.error.description"),
280+
variant: "destructive",
281+
duration: 5000,
282+
})
241283
}
242284
}
243285

@@ -270,6 +312,8 @@ export default function Page() {
270312

271313
const onCloseAnswerModal = () => {
272314
setShowAnswerModal(false)
315+
// For inline answers
316+
setShowInlineAnswer(false)
273317
}
274318

275319
const onOpenSettings = () => {
@@ -303,6 +347,36 @@ export default function Page() {
303347
setQuestionHistory([]);
304348
};
305349

350+
// Function to handle switching to code editor
351+
const handleSwitchToCode = () => {
352+
if (currentQuestion && currentQuestion.type !== QuestionType.Coding) {
353+
// Clone the current question and change the type
354+
const updatedQuestion = {
355+
...currentQuestion,
356+
type: QuestionType.Coding
357+
};
358+
359+
setCurrentQuestion(updatedQuestion);
360+
setForcedQuestionType("Coding");
361+
362+
toast({
363+
title: t("toast.switchedToCode.title") || "Switched to Code Editor",
364+
description: t("toast.switchedToCode.description") || "The question type has been changed to coding",
365+
duration: 3000,
366+
});
367+
}
368+
};
369+
370+
// Add a handler function to close the inline answer display
371+
const handleCloseInlineAnswer = () => {
372+
setShowInlineAnswer(false);
373+
}
374+
375+
// Add a handler function to edit the answer
376+
const handleEditAnswer = () => {
377+
setShowInlineAnswer(false);
378+
}
379+
306380
return (
307381
<div className="flex flex-col min-h-screen">
308382
<Header
@@ -316,7 +390,20 @@ export default function Page() {
316390
{currentQuestion && !isLoadingQuestion ? (
317391
<>
318392
<QuestionArea question={currentQuestion} language={language} onNotMyStack={handleNotMyStack} />
319-
<AnswerArea question={currentQuestion} userAnswer={userAnswer} setUserAnswer={setUserAnswer} />
393+
394+
{/* Show AI answer if requested */}
395+
{showInlineAnswer ? (
396+
<AnswerDisplay
397+
answer={answer}
398+
language={language}
399+
isStreaming={isStreaming}
400+
parsedAnswer={parsedAnswer}
401+
onClose={handleCloseInlineAnswer}
402+
onEdit={handleEditAnswer}
403+
/>
404+
) : (
405+
<AnswerArea question={currentQuestion} userAnswer={userAnswer} setUserAnswer={setUserAnswer} />
406+
)}
320407
</>
321408
) : !currentQuestion && !isLoadingQuestion ? (
322409
<div className="flex flex-col items-center justify-center py-16 space-y-4">
@@ -333,13 +420,16 @@ export default function Page() {
333420
onViewAnswer={onViewAnswer}
334421
isSubmitted={isSubmitted}
335422
onNotMyStack={handleNotMyStack}
423+
showSwitchTypeButton={currentQuestion?.type !== QuestionType.Coding}
424+
onSwitchToCode={handleSwitchToCode}
336425
/>
337426

338427
{showResultsModal && (
339428
<ResultsModal results={results} language={language} onClose={onCloseResultsModal} isStreaming={isStreaming} />
340429
)}
341430

342-
{showAnswerModal && (
431+
{/* AnswerModal is only used if not showing inline answers */}
432+
{showAnswerModal && !showInlineAnswer && (
343433
<AnswerModal answer={answer} language={language} onClose={onCloseAnswerModal} isStreaming={isStreaming} />
344434
)}
345435

0 commit comments

Comments
 (0)