Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- frontend/court/court.js +69 -7
- src/court/orchestrator.py +5 -0
frontend/court/court.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
| 5 |
const state = {
|
| 6 |
currentSession: null,
|
| 7 |
currentScreen: 'lobby',
|
|
|
|
| 8 |
setupStep: 1,
|
| 9 |
setupData: {
|
| 10 |
side: null,
|
|
@@ -128,15 +129,28 @@ function goToStep(step) {
|
|
| 128 |
}
|
| 129 |
if (state.setupStep === 2) {
|
| 130 |
const title = document.getElementById('case-title').value.trim();
|
|
|
|
|
|
|
| 131 |
if (!title) {
|
| 132 |
-
alert('
|
| 133 |
console.warn('Cannot advance: case title missing');
|
| 134 |
return;
|
| 135 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
state.setupData.title = title;
|
| 137 |
state.setupData.userClient = document.getElementById('user-client').value;
|
| 138 |
state.setupData.opposingParty = document.getElementById('opposing-party').value;
|
| 139 |
-
state.setupData.facts =
|
| 140 |
state.setupData.jurisdiction = document.getElementById('jurisdiction').value;
|
| 141 |
}
|
| 142 |
|
|
@@ -257,7 +271,7 @@ async function submitArgument() {
|
|
| 257 |
}
|
| 258 |
|
| 259 |
if (state.isWaitingForResponse) {
|
| 260 |
-
alert('Waiting for court response. Please be patient.');
|
| 261 |
return;
|
| 262 |
}
|
| 263 |
|
|
@@ -315,30 +329,78 @@ async function submitArgument() {
|
|
| 315 |
});
|
| 316 |
}
|
| 317 |
|
| 318 |
-
// Update round
|
| 319 |
state.currentRound = data.round;
|
|
|
|
| 320 |
updateRoundIndicator();
|
| 321 |
|
| 322 |
-
// Check if session
|
| 323 |
-
if (data.session_ended) {
|
| 324 |
setTimeout(() => {
|
| 325 |
showScreen('loading');
|
| 326 |
finishLoadingAnimation();
|
| 327 |
state.currentSession = data.session_id;
|
| 328 |
showScreen('analysis');
|
| 329 |
}, 2500);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
} else {
|
|
|
|
|
|
|
| 331 |
setTimeout(() => showScreen('courtroom'), 2500);
|
| 332 |
}
|
| 333 |
|
| 334 |
} catch (error) {
|
| 335 |
console.error('Error submitting argument:', error);
|
| 336 |
alert('Error submitting argument. Please try again.');
|
| 337 |
-
state.isWaitingForResponse = false;
|
| 338 |
showScreen('courtroom');
|
| 339 |
}
|
| 340 |
}
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
async function submitObjection() {
|
| 343 |
console.log("Objection - Session ID:", state.currentSession); // DEBUG
|
| 344 |
|
|
|
|
| 5 |
const state = {
|
| 6 |
currentSession: null,
|
| 7 |
currentScreen: 'lobby',
|
| 8 |
+
currentPhase: 'briefing', // Track court phase
|
| 9 |
setupStep: 1,
|
| 10 |
setupData: {
|
| 11 |
side: null,
|
|
|
|
| 129 |
}
|
| 130 |
if (state.setupStep === 2) {
|
| 131 |
const title = document.getElementById('case-title').value.trim();
|
| 132 |
+
const facts = document.getElementById('brief-facts').value.trim();
|
| 133 |
+
|
| 134 |
if (!title) {
|
| 135 |
+
alert('⚠ Case title is required');
|
| 136 |
console.warn('Cannot advance: case title missing');
|
| 137 |
return;
|
| 138 |
}
|
| 139 |
+
if (!facts || facts.length < 20) {
|
| 140 |
+
alert('⚠ Please provide detailed facts (minimum 20 characters). The system needs facts to generate appropriate charges and legal context.');
|
| 141 |
+
console.warn('Cannot advance: facts too brief');
|
| 142 |
+
return;
|
| 143 |
+
}
|
| 144 |
+
if (!state.setupData.issues || state.setupData.issues.length === 0) {
|
| 145 |
+
alert('⚠ Please add at least one legal issue. Without legal issues, the court cannot focus arguments properly.');
|
| 146 |
+
console.warn('Cannot advance: no legal issues');
|
| 147 |
+
return;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
state.setupData.title = title;
|
| 151 |
state.setupData.userClient = document.getElementById('user-client').value;
|
| 152 |
state.setupData.opposingParty = document.getElementById('opposing-party').value;
|
| 153 |
+
state.setupData.facts = facts;
|
| 154 |
state.setupData.jurisdiction = document.getElementById('jurisdiction').value;
|
| 155 |
}
|
| 156 |
|
|
|
|
| 271 |
}
|
| 272 |
|
| 273 |
if (state.isWaitingForResponse) {
|
| 274 |
+
alert('⏳ Waiting for court response. Please be patient.');
|
| 275 |
return;
|
| 276 |
}
|
| 277 |
|
|
|
|
| 329 |
});
|
| 330 |
}
|
| 331 |
|
| 332 |
+
// Update round and phase
|
| 333 |
state.currentRound = data.round;
|
| 334 |
+
state.currentPhase = data.phase; // CRITICAL: Track current phase
|
| 335 |
updateRoundIndicator();
|
| 336 |
|
| 337 |
+
// Check if session ended or phase changed
|
| 338 |
+
if (data.session_ended || data.phase === 'completed') {
|
| 339 |
setTimeout(() => {
|
| 340 |
showScreen('loading');
|
| 341 |
finishLoadingAnimation();
|
| 342 |
state.currentSession = data.session_id;
|
| 343 |
showScreen('analysis');
|
| 344 |
}, 2500);
|
| 345 |
+
} else if (data.phase === 'closing') {
|
| 346 |
+
// Provide guidance for closing arguments
|
| 347 |
+
setTimeout(() => {
|
| 348 |
+
state.isWaitingForResponse = false; // CRITICAL: Reset waiting state
|
| 349 |
+
showScreen('courtroom');
|
| 350 |
+
showClosingArgumentsGuidance();
|
| 351 |
+
}, 2500);
|
| 352 |
} else {
|
| 353 |
+
// Standard rounds phase
|
| 354 |
+
state.isWaitingForResponse = false; // CRITICAL: Reset waiting state
|
| 355 |
setTimeout(() => showScreen('courtroom'), 2500);
|
| 356 |
}
|
| 357 |
|
| 358 |
} catch (error) {
|
| 359 |
console.error('Error submitting argument:', error);
|
| 360 |
alert('Error submitting argument. Please try again.');
|
| 361 |
+
state.isWaitingForResponse = false; // Reset on error
|
| 362 |
showScreen('courtroom');
|
| 363 |
}
|
| 364 |
}
|
| 365 |
|
| 366 |
+
/**
|
| 367 |
+
* Show UI guidance for closing arguments phase.
|
| 368 |
+
*/
|
| 369 |
+
function showClosingArgumentsGuidance() {
|
| 370 |
+
const textarea = document.getElementById('argument-input');
|
| 371 |
+
const placeholder = textarea.getAttribute('placeholder');
|
| 372 |
+
|
| 373 |
+
// Update placeholder for closing arguments
|
| 374 |
+
textarea.setAttribute('placeholder', 'Provide your closing arguments... (summarize key points, address judge\'s concerns)');
|
| 375 |
+
|
| 376 |
+
// Show notification
|
| 377 |
+
const notification = document.createElement('div');
|
| 378 |
+
notification.className = 'closing-phase-notification';
|
| 379 |
+
notification.innerHTML = `
|
| 380 |
+
<div style="padding: 16px; background: rgba(212,175,55,0.15); border: 2px solid #d4af37; border-radius: 4px; margin-bottom: 16px;">
|
| 381 |
+
<p style="font-weight: 600; color: #d4af37; margin: 0 0 8px 0;">📜 Closing Arguments Phase</p>
|
| 382 |
+
<p style="margin: 0; font-size: 13px; color: #4a4a4a; line-height: 1.5;">
|
| 383 |
+
The court is ready for closing arguments. Summarize your case, address the judge's questions,
|
| 384 |
+
and make your final legal submissions. This is your last opportunity to persuade the court.
|
| 385 |
+
</p>
|
| 386 |
+
</div>
|
| 387 |
+
`;
|
| 388 |
+
|
| 389 |
+
const container = document.querySelector('.argument-input-section');
|
| 390 |
+
if (container) {
|
| 391 |
+
// Remove old notification if exists
|
| 392 |
+
const oldNotif = container.querySelector('.closing-phase-notification');
|
| 393 |
+
if (oldNotif) oldNotif.remove();
|
| 394 |
+
|
| 395 |
+
// Insert new notification before textarea
|
| 396 |
+
textarea.parentNode.insertBefore(notification, textarea);
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
// Focus textarea
|
| 400 |
+
textarea.focus();
|
| 401 |
+
console.log('✓ Closing arguments guidance displayed');
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
async function submitObjection() {
|
| 405 |
console.log("Objection - Session ID:", state.currentSession); // DEBUG
|
| 406 |
|
src/court/orchestrator.py
CHANGED
|
@@ -328,6 +328,7 @@ def _handle_briefing(session_id: str, user_argument: str, session: Dict) -> Dict
|
|
| 328 |
"new_concessions": [],
|
| 329 |
"round_number": 1,
|
| 330 |
"phase": "rounds",
|
|
|
|
| 331 |
}
|
| 332 |
|
| 333 |
|
|
@@ -463,6 +464,7 @@ def _handle_round(session_id: str, user_argument: str, session: Dict) -> Dict:
|
|
| 463 |
"new_concessions": new_concessions,
|
| 464 |
"round_number": new_round,
|
| 465 |
"phase": new_phase,
|
|
|
|
| 466 |
}
|
| 467 |
|
| 468 |
|
|
@@ -533,6 +535,7 @@ def _handle_cross_exam_answer(
|
|
| 533 |
"round_number": session["current_round"],
|
| 534 |
"phase": "cross_examination",
|
| 535 |
"cross_exam_complete": False,
|
|
|
|
| 536 |
}
|
| 537 |
|
| 538 |
else:
|
|
@@ -558,6 +561,7 @@ def _handle_cross_exam_answer(
|
|
| 558 |
"round_number": session["current_round"],
|
| 559 |
"phase": "closing",
|
| 560 |
"cross_exam_complete": True,
|
|
|
|
| 561 |
}
|
| 562 |
|
| 563 |
|
|
@@ -637,6 +641,7 @@ def _handle_closing(session_id: str, user_closing: str, session: Dict) -> Dict:
|
|
| 637 |
"round_number": session["current_round"],
|
| 638 |
"phase": "completed",
|
| 639 |
"ready_for_analysis": True,
|
|
|
|
| 640 |
}
|
| 641 |
|
| 642 |
|
|
|
|
| 328 |
"new_concessions": [],
|
| 329 |
"round_number": 1,
|
| 330 |
"phase": "rounds",
|
| 331 |
+
"session_ended": False,
|
| 332 |
}
|
| 333 |
|
| 334 |
|
|
|
|
| 464 |
"new_concessions": new_concessions,
|
| 465 |
"round_number": new_round,
|
| 466 |
"phase": new_phase,
|
| 467 |
+
"session_ended": new_phase == "completed",
|
| 468 |
}
|
| 469 |
|
| 470 |
|
|
|
|
| 535 |
"round_number": session["current_round"],
|
| 536 |
"phase": "cross_examination",
|
| 537 |
"cross_exam_complete": False,
|
| 538 |
+
"session_ended": False,
|
| 539 |
}
|
| 540 |
|
| 541 |
else:
|
|
|
|
| 561 |
"round_number": session["current_round"],
|
| 562 |
"phase": "closing",
|
| 563 |
"cross_exam_complete": True,
|
| 564 |
+
"session_ended": False,
|
| 565 |
}
|
| 566 |
|
| 567 |
|
|
|
|
| 641 |
"round_number": session["current_round"],
|
| 642 |
"phase": "completed",
|
| 643 |
"ready_for_analysis": True,
|
| 644 |
+
"session_ended": True,
|
| 645 |
}
|
| 646 |
|
| 647 |
|