diff --git a/backend/controllers/profile_controller.go b/backend/controllers/profile_controller.go index 489261a..bcb955b 100644 --- a/backend/controllers/profile_controller.go +++ b/backend/controllers/profile_controller.go @@ -254,7 +254,7 @@ func GetProfile(c *gin.Context) { "opponent": transcript.Opponent, "debateType": transcript.DebateType, "date": transcript.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), - "eloChange": 0, // TODO: Add actual Elo change tracking + "eloChange": transcript.EloChange,// TODO: Add actual Elo change tracking }) } diff --git a/backend/models/transcript.go b/backend/models/transcript.go index cb0a796..70cac57 100644 --- a/backend/models/transcript.go +++ b/backend/models/transcript.go @@ -30,12 +30,14 @@ type SavedDebateTranscript struct { Topic string `bson:"topic" json:"topic"` Opponent string `bson:"opponent" json:"opponent"` // Bot name or opponent email Result string `bson:"result" json:"result"` // "win", "loss", "draw", "pending" + EloChange float64 `bson:"eloChange" json:"eloChange"` Messages []Message `bson:"messages" json:"messages"` - Transcripts map[string]string `bson:"transcripts,omitempty" json:"transcripts,omitempty"` // For user vs user debates + Transcripts map[string]string `bson:"transcripts,omitempty" json:"transcripts,omitempty"` CreatedAt time.Time `bson:"createdAt" json:"createdAt"` UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` } + func (s SavedDebateTranscript) MarshalJSON() ([]byte, error) { type Alias SavedDebateTranscript a := Alias(s) diff --git a/backend/services/transcriptservice.go b/backend/services/transcriptservice.go index 2d893a5..d6290ae 100644 --- a/backend/services/transcriptservice.go +++ b/backend/services/transcriptservice.go @@ -186,6 +186,7 @@ func SubmitTranscripts( resultFor, []models.Message{}, // You might want to reconstruct messages from transcripts forSubmission.Transcripts, + forRecord.RatingChange ) if err != nil { } @@ -659,7 +660,7 @@ func buildFallbackJudgeResult(merged map[string]string) string { } // SaveDebateTranscript saves a debate transcript for later viewing -func SaveDebateTranscript(userID primitive.ObjectID, email, debateType, topic, opponent, result string, messages []models.Message, transcripts map[string]string) error { +func SaveDebateTranscript(userID primitive.ObjectID, email, debateType, topic, opponent, result string, messages []models.Message, transcripts map[string]string, eloChange float64) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -682,11 +683,13 @@ func SaveDebateTranscript(userID primitive.ObjectID, email, debateType, topic, o // If the result has changed or is "pending", update the transcript if existingTranscript.Result != result || existingTranscript.Result == "pending" { + update := bson.M{ "$set": bson.M{ "result": result, "messages": messages, "transcripts": transcripts, + "eloChange": eloChange, "updatedAt": time.Now(), }, } @@ -712,6 +715,7 @@ func SaveDebateTranscript(userID primitive.ObjectID, email, debateType, topic, o Opponent: opponent, Result: result, Messages: messages, + EloChange: eloChange, Transcripts: transcripts, CreatedAt: time.Now(), UpdatedAt: time.Now(), diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 2cbe4b1..75e2b02 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -50,57 +50,59 @@ function AppRoutes() { } const { isAuthenticated } = authContext; return ( - - {/* Public routes */} - : - } - /> - } /> - } /> - } /> - {/* Protected routes with layout */} - }> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } - /> - } - /> - } /> - } - />{' '} - {/* Add this route */} - } /> + + {/* Public routes */} + : + } + /> + } /> + } /> + } /> + + {/* Protected routes */} + }> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + + {/* Coach routes */} + }> + } + /> + } /> + + + + {/* Debate routes (outside layout) */} + } /> + } /> + } /> + } /> + } /> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - {/* Redirect unknown routes */} - } /> - + + {/* Redirect unknown routes */} + } /> + + ); } diff --git a/frontend/src/Pages/DebateRoom.tsx b/frontend/src/Pages/DebateRoom.tsx index c2ed137..92303e0 100644 --- a/frontend/src/Pages/DebateRoom.tsx +++ b/frontend/src/Pages/DebateRoom.tsx @@ -7,6 +7,7 @@ import JudgmentPopup from "@/components/JudgementPopup"; import { Mic, MicOff } from "lucide-react"; import { useAtom } from "jotai"; import { userAtom } from "@/state/userAtom"; +import JSON5 from "json5"; // Bot type definition (same as in BotSelection) interface Bot { @@ -217,8 +218,9 @@ const extractJSON = (response: string): string => { }; const DebateRoom: React.FC = () => { - const location = useLocation(); + const judgingRef = useRef(false); const navigate = useNavigate(); + const location = useLocation(); const debateData = location.state as DebateProps; const phases = debateData.phaseTimings; const debateKey = `debate_${debateData.userId}_${debateData.topic}_${debateData.debateId}`; @@ -574,50 +576,49 @@ const DebateRoom: React.FC = () => { } }; - const judgeDebateResult = async (messages: Message[]) => { + const judgeDebateResult = async (messages: Message[]) => { + if (judgingRef.current) { + console.log("Judging already in progress, skipping duplicate call"); + return; + } + + judgingRef.current = true; + try { console.log("Starting judgment with messages:", messages); const { result } = await judgeDebate({ history: messages, userId: debateData.userId, }); + console.log("Raw judge result:", result); - + const jsonString = extractJSON(result); console.log("Extracted JSON string:", jsonString); - + let judgment: JudgmentData; try { - judgment = JSON.parse(jsonString); - } catch (parseError) { - console.error("JSON parse error:", parseError, "Trying to fix JSON..."); - // Try to fix common JSON issues - const fixedJson = jsonString - .replace(/'/g, '"') // Replace single quotes with double quotes - .replace(/(\w+):/g, '"$1":') // Add quotes to keys - .replace(/,\s*}/g, '}') // Remove trailing commas - .replace(/,\s*]/g, ']'); // Remove trailing commas in arrays - try { - judgment = JSON.parse(fixedJson); - } catch (e) { - throw new Error(`Failed to parse JSON: ${e}`); - } + judgment = JSON5.parse(jsonString); + }catch (e) { + throw new Error(`Failed to parse judgment JSON: ${e}`); } - + console.log("Parsed judgment:", judgment); setJudgmentData(judgment); setPopup({ show: false, message: "" }); setShowJudgment(true); + } catch (error) { console.error("Judging error:", error); - // Show error to user + setPopup({ show: true, - message: `Judgment error: ${error instanceof Error ? error.message : "Unknown error"}. Showing default results.`, + message: `Judgment error: ${ + error instanceof Error ? error.message : "Unknown error" + }. Showing default results.`, isJudging: false, }); - - // Set default judgment data + setJudgmentData({ opening_statement: { user: { score: 0, reason: "Error occurred during judgment" }, @@ -643,13 +644,18 @@ const DebateRoom: React.FC = () => { opponent_analysis: "", }, }); + setTimeout(() => { setPopup({ show: false, message: "" }); setShowJudgment(true); }, 3000); + + } finally { + judgingRef.current = false; } }; + const formatTime = (seconds: number) => { const timeStr = `${Math.floor(seconds / 60)}:${(seconds % 60) .toString() @@ -690,9 +696,12 @@ const DebateRoom: React.FC = () => { const currentTurnType = turnTypes[state.currentPhase][state.phaseStep]; return ( -
+
-
+

Debate: {debateData.topic}

@@ -716,7 +725,7 @@ const DebateRoom: React.FC = () => { {popup.show && (
-
+
{popup.isJudging ? (
@@ -747,17 +756,16 @@ const DebateRoom: React.FC = () => { userStance={state.userStance} botStance={state.botStance} botDesc={bot.desc} - onClose={() => setShowJudgment(false)} + onClose={() => { + setShowJudgment(false); + navigate("/"); + }} /> )}
{/* Bot Section */} -
+
{ box-shadow: 0 0 5px rgba(255, 149, 0, 0.5); } 50% { - box-shadow: 0 0 20px rgba(255, 149, 0, 0.8); + box-shadow: 0 0 20px rgba(255, 180, 80, 0.9); } 100% { box-shadow: 0 0 5px rgba(255, 149, 0, 0.5); diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 7a33148..788bfe9 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -121,8 +121,11 @@ function Header() { return ( <> -
-
{getBreadcrumbs()}
+
+
+ {getBreadcrumbs()} +
+
@@ -239,7 +242,7 @@ function Header() {
+