Compare and evaluate outputs from different legal technology tools to help us understand user preferences.
Question 1 of 0
Please select your preferred response
Prompt
Sample A
Sample B
Sample C
No data file found
Please upload a JSONL file to begin the evaluation
"""
def start_session(name):
"""Start a new evaluation session"""
if not name:
return json.dumps({"showWelcome": True})
if not evaluator.data:
return json.dumps({"showFileUpload": True})
evaluator.create_user_session(name)
return get_current_state()
def get_current_state():
"""Get current state as JSON"""
question = evaluator.get_current_question()
if not evaluator.current_user_name:
return json.dumps({"showWelcome": True})
if not question:
return json.dumps({"showFileUpload": True})
return json.dumps({
"showWelcome": False,
"showFileUpload": False,
"userName": evaluator.current_user_name,
"currentIndex": evaluator.current_index,
"totalQuestions": len(evaluator.data),
"introductoryExample": question.get("introductory_example", ""),
"sampleZero": question.get("sample_zero", ""),
"sampleOne": question.get("sample_one", ""),
"sampleTwo": question.get("sample_two", "")
})
def confirm_selection(selection):
"""Confirm user's selection"""
if selection and evaluator.record_choice(selection):
# Auto-advance to next question
if evaluator.current_index < len(evaluator.data) - 1:
evaluator.current_index += 1
return get_current_state()
def previous_question():
"""Navigate to previous question"""
if evaluator.current_index > 0:
evaluator.current_index -= 1
return get_current_state()
def next_question():
"""Navigate to next question"""
if evaluator.current_index < len(evaluator.data) - 1:
evaluator.current_index += 1
return get_current_state()
def export_results_handler():
"""Export results and return status"""
try:
jsonl_file, md_file, json_file, md_content = evaluator.export_results()
return (
get_current_state(),
"✅ Results exported successfully!",
jsonl_file,
md_file,
md_content
)
except Exception as e:
return (
get_current_state(),
f"❌ Export failed: {str(e)}",
None,
None,
""
)
def load_file(file):
"""Load data from uploaded file"""
if file:
evaluator.load_from_file(file.name)
return get_current_state()
# Create Gradio interface
with gr.Blocks(css=custom_css, js=js_code, theme=gr.themes.Base()) as demo:
gr.HTML(html_template)
# Visible name input in welcome screen
with gr.Column(elem_id="name-input-wrapper", visible=True):
user_name_input = gr.Textbox(
label="",
placeholder="Enter your name",
elem_id="user-name-field"
)
start_button = gr.Button("Start Evaluation", elem_classes=["start-button"])
# Hidden components for JavaScript interaction
with gr.Column(visible=False):
hidden_name = gr.Textbox(elem_id="hidden-name")
start_btn = gr.Button("Start", elem_id="start-session-btn")
current_state = gr.Textbox(value=json.dumps({"showWelcome": True}), elem_id="current-state")
selection_input = gr.Textbox(elem_id="hidden-selection")
confirm_btn = gr.Button("Confirm", elem_id="confirm-btn")
prev_btn = gr.Button("Previous", elem_id="prev-btn")
next_btn = gr.Button("Next", elem_id="next-btn")
export_btn = gr.Button("Export", elem_id="export-btn")
file_upload = gr.File(elem_id="file-upload-input", file_types=[".jsonl"])
# Output components (hidden)
with gr.Column(visible=False):
export_status = gr.Textbox()
download_jsonl = gr.File(label="Download JSONL")
download_md = gr.File(label="Download Summary")
summary_display = gr.Markdown()
# Event handlers
start_button.click(
fn=start_session,
inputs=[user_name_input],
outputs=[current_state]
)
start_btn.click(
fn=start_session,
inputs=[hidden_name],
outputs=[current_state]
)
confirm_btn.click(
fn=confirm_selection,
inputs=[selection_input],
outputs=[current_state]
)
prev_btn.click(
fn=previous_question,
outputs=[current_state]
)
next_btn.click(
fn=next_question,
outputs=[current_state]
)
export_btn.click(
fn=export_results_handler,
outputs=[current_state, export_status, download_jsonl, download_md, summary_display]
)
file_upload.change(
fn=load_file,
inputs=[file_upload],
outputs=[current_state]
)
# Move name input to welcome screen on load
demo.load(
fn=None,
js="""
() => {
// Move the name input to the welcome screen
const nameWrapper = document.querySelector('#name-input-wrapper');
const nameContainer = document.querySelector('#name-input-container');
if (nameWrapper && nameContainer) {
const nameField = nameWrapper.querySelector('.wrap');
if (nameField) {
nameContainer.appendChild(nameField);
}
nameWrapper.style.display = 'none';
}
// Style the start button
const startBtn = document.querySelector('#name-input-wrapper').nextElementSibling;
if (startBtn) {
const btn = startBtn.querySelector('button');
if (btn) {
btn.className = 'start-button';
btn.onclick = () => startEvaluation();
}
document.querySelector('#welcome-screen').appendChild(btn);
startBtn.style.display = 'none';
}
}
"""
)
# Create sample data if no file exists
if not os.path.exists("test_legal_tech.jsonl"):
sample_data = [
{
"introductory_example": "Draft a confidentiality clause for a software development agreement",
"sample_zero": "The Receiving Party agrees to maintain the confidentiality of all Confidential Information received from the Disclosing Party and shall not disclose such information to any third party without prior written consent. This obligation shall survive termination of this Agreement for a period of five (5) years.",
"sample_one": "All proprietary information, trade secrets, and confidential data disclosed by either party shall be kept strictly confidential. The receiving party must implement reasonable security measures and limit access to authorized personnel only. Breach of this clause may result in immediate termination and legal action.",
"sample_two": "Confidential Information shall mean any non-public information disclosed by one party to the other, whether orally, in writing, or electronically. Both parties agree to protect such information using the same degree of care used for their own confidential information, but no less than reasonable care."
},
{
"introductory_example": "Create an indemnification provision for a service agreement",
"sample_zero": "The Service Provider shall indemnify, defend, and hold harmless the Client from any claims, damages, or losses arising from the Service Provider's negligence, willful misconduct, or breach of this Agreement, except to the extent caused by the Client's own negligence.",
"sample_one": "Each party agrees to indemnify the other against third-party claims arising from their respective breaches of this Agreement or negligent acts. This indemnification includes reasonable attorneys' fees and costs, subject to prompt notice and cooperation in defense.",
"sample_two": "Provider shall defend, indemnify, and hold Client harmless from all liabilities, costs, and expenses (including reasonable legal fees) resulting from Provider's performance under this Agreement, provided Client gives prompt notice of any claim and allows Provider to control the defense."
},
{
"introductory_example": "Write a limitation of liability clause for a technology services contract",
"sample_zero": "Neither party shall be liable for any indirect, incidental, special, consequential, or punitive damages, regardless of the cause of action. Total liability under this Agreement shall not exceed the fees paid in the twelve months preceding the claim.",
"sample_one": "IN NO EVENT SHALL EITHER PARTY BE LIABLE FOR LOST PROFITS, LOST DATA, OR CONSEQUENTIAL DAMAGES. THE MAXIMUM LIABILITY OF EITHER PARTY SHALL BE LIMITED TO THE TOTAL AMOUNT PAID UNDER THIS AGREEMENT IN THE SIX (6) MONTHS PRIOR TO THE EVENT GIVING RISE TO LIABILITY.",
"sample_two": "Except for breaches of confidentiality, indemnification obligations, or willful misconduct, neither party's liability shall exceed the greater of (a) $100,000 or (b) the fees paid in the prior 12 months. This limitation applies to all claims in aggregate."
}
]
with open("test_legal_tech.jsonl", "w") as f:
for item in sample_data:
f.write(json.dumps(item) + "\n")
if __name__ == "__main__":
demo.launch(share=False, ssr_mode=False)