Spaces:
Sleeping
Sleeping
# app.py | |
import streamlit as st | |
import requests | |
import time | |
import plotly.express as px | |
import os | |
from dotenv import load_dotenv | |
# Load environment variables | |
load_dotenv() | |
# Set up Streamlit page | |
st.set_page_config( | |
page_title="Legal Rights Explorer", | |
page_icon="โ๏ธ", | |
layout="wide", | |
initial_sidebar_state="collapsed" | |
) | |
# Custom CSS for professional styling | |
st.markdown(""" | |
<style> | |
:root { | |
--primary: #2c3e50; | |
--secondary: #3498db; | |
--accent: #e74c3c; | |
--light: #ecf0f1; | |
--dark: #2c3e50; | |
--success: #27ae60; | |
--card-shadow: 0 6px 20px rgba(0,0,0,0.1); | |
} | |
.stApp { | |
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); | |
color: #333; | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
} | |
.header { | |
background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%); | |
color: white; | |
padding: 1.8rem 2rem; | |
border-radius: 0 0 20px 20px; | |
box-shadow: var(--card-shadow); | |
margin-bottom: 2.5rem; | |
} | |
.card { | |
background: white; | |
border-radius: 15px; | |
padding: 1.8rem; | |
box-shadow: var(--card-shadow); | |
margin-bottom: 1.8rem; | |
transition: all 0.3s ease; | |
border-left: 4px solid var(--secondary); | |
} | |
.card:hover { | |
box-shadow: 0 12px 30px rgba(0,0,0,0.15); | |
transform: translateY(-5px); | |
} | |
.scenario-btn { | |
width: 100%; | |
padding: 1.1rem; | |
background: linear-gradient(135deg, var(--secondary) 0%, #2980b9 100%); | |
color: white; | |
border: none; | |
border-radius: 12px; | |
font-weight: 600; | |
margin: 0.7rem 0; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
text-align: left; | |
padding-left: 20px; | |
font-size: 1.05rem; | |
} | |
.scenario-btn:hover { | |
background: linear-gradient(135deg, var(--primary) 0%, #2c3e50 100%); | |
transform: scale(1.02); | |
} | |
.response-card { | |
background: white; | |
border-left: 5px solid var(--success); | |
border-radius: 12px; | |
padding: 2rem; | |
margin-top: 2rem; | |
box-shadow: var(--card-shadow); | |
animation: fadeIn 0.6s ease; | |
} | |
.country-card { | |
display: flex; | |
align-items: center; | |
gap: 15px; | |
padding: 1.2rem; | |
border-radius: 12px; | |
background: white; | |
box-shadow: var(--card-shadow); | |
margin-bottom: 15px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.country-card:hover { | |
transform: translateX(5px); | |
box-shadow: 0 8px 25px rgba(0,0,0,0.15); | |
} | |
.country-card.selected { | |
background: linear-gradient(135deg, var(--light) 0%, var(--secondary) 100%); | |
border-left: 4px solid var(--accent); | |
} | |
.footer { | |
text-align: center; | |
padding: 2rem; | |
margin-top: 3rem; | |
color: var(--dark); | |
font-size: 0.95rem; | |
background: rgba(236, 240, 241, 0.7); | |
border-radius: 15px; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(20px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
@media (max-width: 768px) { | |
.header { | |
padding: 1.3rem; | |
} | |
.card { | |
padding: 1.3rem; | |
} | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# Country data with flags | |
COUNTRIES = { | |
"๐บ๐ธ United States": "US", | |
"๐ฌ๐ง United Kingdom": "UK", | |
"๐จ๐ฆ Canada": "CA", | |
"๐ฆ๐บ Australia": "AU", | |
"๐ฎ๐ณ India": "IN", | |
"๐ฉ๐ช Germany": "DE", | |
"๐ซ๐ท France": "FR", | |
"๐ฏ๐ต Japan": "JP", | |
"๐ง๐ท Brazil": "BR", | |
"๐ฟ๐ฆ South Africa": "ZA", | |
"๐ช๐ธ Spain": "ES", | |
"๐ฎ๐น Italy": "IT" | |
} | |
# Common legal scenarios | |
SCENARIOS = [ | |
"Traffic Stop by Police", | |
"Workplace Discrimination", | |
"Rental Housing Issues", | |
"Medical Emergency Rights", | |
"Consumer Protection", | |
"Arrest or Detention", | |
"Border Crossing", | |
"Online Privacy", | |
"Employment Termination", | |
"Debt Collection", | |
"Freedom of Speech", | |
"Immigration Rights" | |
] | |
# Simulated API function | |
def get_legal_rights(country, scenario): | |
"""Simulate API response with country-specific legal rights""" | |
# In a real implementation, this would call an external API | |
# For this demo, we'll return simulated responses | |
# Simulate API delay | |
time.sleep(1.5) | |
# Base rights that apply to most countries | |
base_rights = [ | |
"Right to remain silent", | |
"Right to legal representation", | |
"Right to be treated with dignity and respect", | |
"Right to understand the charges against you", | |
"Right to a fair and impartial process" | |
] | |
# Country-specific additions | |
country_specific = { | |
"US": [ | |
"Right to refuse unwarranted searches (4th Amendment)", | |
"Right to due process (5th Amendment)", | |
"Right to a speedy and public trial (6th Amendment)" | |
], | |
"UK": [ | |
"Right to legal advice under the Police and Criminal Evidence Act", | |
"Right to have someone informed of your arrest", | |
"Protection under the Human Rights Act 1998" | |
], | |
"CA": [ | |
"Right to be informed of the reason for detention (Charter of Rights)", | |
"Right to retain and instruct counsel without delay", | |
"Right to habeas corpus" | |
], | |
"AU": [ | |
"Right to silence during police questioning", | |
"Right to communicate with a friend or relative", | |
"Protection under the Australian Human Rights Commission Act" | |
], | |
"IN": [ | |
"Right to free legal aid under Article 39A of the Constitution", | |
"Protection against self-incrimination (Article 20)", | |
"Right to be informed of grounds for arrest (Article 22)" | |
] | |
} | |
# Scenario-specific additions | |
scenario_specific = { | |
"Traffic Stop by Police": [ | |
"Right to see official identification", | |
"Right to know the reason for the stop", | |
"Right to refuse a search without probable cause", | |
"Right to record the interaction" | |
], | |
"Workplace Discrimination": [ | |
"Right to a discrimination-free workplace", | |
"Right to report without retaliation", | |
"Right to reasonable accommodations", | |
"Right to equal pay for equal work" | |
], | |
"Medical Emergency Rights": [ | |
"Right to emergency treatment regardless of insurance", | |
"Right to informed consent", | |
"Right to access medical records", | |
"Right to privacy of health information" | |
], | |
"Arrest or Detention": [ | |
"Right to be informed of charges", | |
"Right to contact your embassy if foreign national", | |
"Right to humane treatment", | |
"Right to challenge the lawfulness of detention" | |
] | |
} | |
# Combine rights based on country and scenario | |
rights = base_rights.copy() | |
if country in country_specific: | |
rights.extend(country_specific[country]) | |
for key, value in scenario_specific.items(): | |
if key in scenario: | |
rights.extend(value) | |
break | |
# Format the response | |
response = f"## ๐ Your Rights in {country}\n" | |
response += f"### Situation: {scenario}\n\n" | |
response += "Based on the laws of your selected country, you have the following rights:\n\n" | |
for i, right in enumerate(set(rights), 1): | |
response += f"โ **{right}**\n\n" | |
response += "\n**Important Notes:**\n" | |
response += "- This information is for educational purposes only\n" | |
response += "- Laws vary by jurisdiction and circumstances\n" | |
response += "- Consult a qualified attorney for legal advice\n" | |
return response | |
# Main app | |
def main(): | |
# Header section | |
st.markdown(""" | |
<div class="header"> | |
<h1 style="margin:0;font-size:2.3rem;">Legal Rights Explorer</h1> | |
<p style="margin:0;font-size:1.2rem;opacity:0.9;">Know your rights in any situation, anywhere in the world</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# Initialize session state | |
if 'selected_country' not in st.session_state: | |
st.session_state.selected_country = "๐บ๐ธ United States" | |
if 'selected_scenario' not in st.session_state: | |
st.session_state.selected_scenario = None | |
# Main content columns | |
col1, col2 = st.columns([1, 2], gap="large") | |
with col1: | |
st.markdown("### ๐ Select Your Country") | |
st.markdown("Choose your country to see jurisdiction-specific rights information") | |
# Country selection cards | |
for country_display in COUNTRIES.keys(): | |
is_selected = st.session_state.selected_country == country_display | |
card_class = "country-card selected" if is_selected else "country-card" | |
st.markdown(f""" | |
<div class="{card_class}" onclick="selectCountry('{country_display}')"> | |
<span style="font-size:1.8rem;">{country_display.split()[0]}</span> | |
<span style="font-weight:500;">{country_display.split(' ', 1)[1]}</span> | |
</div> | |
""", unsafe_allow_html=True) | |
# Country visualization | |
st.markdown("### ๐ Global Rights Index") | |
countries = list(COUNTRIES.values()) | |
awareness = [92, 89, 87, 85, 82, 88, 86, 84, 79, 81, 85, 83] # Simulated data | |
fig = px.bar( | |
x=countries, | |
y=awareness, | |
labels={'x': 'Country', 'y': 'Rights Awareness'}, | |
color=awareness, | |
color_continuous_scale='Blues', | |
height=300 | |
) | |
fig.update_layout( | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
margin=dict(l=0, r=0, t=30, b=0) | |
) | |
st.plotly_chart(fig, use_container_width=True) | |
# Legal resources | |
with st.expander("๐ Legal Resources"): | |
st.markdown(""" | |
- [United Nations Human Rights](https://www.ohchr.org/) | |
- [International Justice Resource Center](https://ijrcenter.org/) | |
- [Global Legal Information Network](https://www.loc.gov/law/help/legal-info.php) | |
- [World Legal Information Institute](https://www.worldlii.org/) | |
""") | |
with col2: | |
st.markdown("### ๐จ Select a Legal Scenario") | |
st.markdown("Choose a situation to understand your rights and protections") | |
# Create buttons for each scenario | |
cols = st.columns(2) | |
for i, scenario in enumerate(SCENARIOS): | |
with cols[i % 2]: | |
if st.button( | |
f"**{scenario}**", | |
key=scenario, | |
use_container_width=True, | |
help=f"Click to see your rights for {scenario}" | |
): | |
st.session_state.selected_scenario = scenario | |
# Custom scenario input | |
custom_scenario = st.text_input("**Or describe your specific situation:**", placeholder="e.g., 'Rights during home search'") | |
if custom_scenario: | |
st.session_state.selected_scenario = custom_scenario | |
# Response area | |
st.markdown("### โ๏ธ Your Legal Rights") | |
if st.session_state.selected_scenario: | |
country_code = COUNTRIES[st.session_state.selected_country] | |
with st.spinner(f"Analyzing your rights for {st.session_state.selected_scenario} in {country_code}..."): | |
response = get_legal_rights( | |
country_code, | |
st.session_state.selected_scenario | |
) | |
if response: | |
st.markdown(f'<div class="response-card">{response}</div>', unsafe_allow_html=True) | |
else: | |
st.error("Failed to get response. Please try again.") | |
else: | |
st.info("Please select a legal scenario to see your rights information") | |
st.image("https://images.unsplash.com/photo-1589391886645-d51941baf7fb?auto=format&fit=crop&w=600&h=400", | |
caption="Know Your Rights, Exercise Your Freedom") | |
st.markdown(""" | |
<div class="card"> | |
<h3>Why Know Your Rights?</h3> | |
<p>Understanding your legal rights empowers you to:</p> | |
<ul> | |
<li>Protect yourself in difficult situations</li> | |
<li>Make informed decisions when facing legal issues</li> | |
<li>Prevent exploitation and rights violations</li> | |
<li>Access justice when your rights are infringed</li> | |
<li>Confidently navigate complex legal systems</li> | |
</ul> | |
<p style="margin-top:15px;font-style:italic;">"Knowledge of the law is the first defense against injustice."</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# Footer | |
st.markdown(""" | |
<div class="footer"> | |
<p>Legal Rights Explorer | ยฉ 2023 | For Educational Purposes Only | Not Legal Advice</p> | |
<p>Always consult a qualified attorney in your jurisdiction for your specific legal situation</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# JavaScript for country selection | |
st.markdown(""" | |
<script> | |
function selectCountry(country) { | |
window.parent.document.querySelectorAll("button[kind='secondary']")[0].click(); | |
setTimeout(function() { | |
const countryButtons = window.parent.document.querySelectorAll("button[kind='secondary']"); | |
for (let btn of countryButtons) { | |
if (btn.innerText.includes(country)) { | |
btn.click(); | |
break; | |
} | |
} | |
}, 100); | |
} | |
</script> | |
""", unsafe_allow_html=True) | |
if __name__ == "__main__": | |
main() |