Upload 4 files
Browse files- cd.json +13 -0
- database.py +23 -0
- display.py +160 -0
- requirements.txt +0 -0
cd.json
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"type": "service_account",
|
3 |
+
"project_id": "bijay-c173f",
|
4 |
+
"private_key_id": "9df1ed7f7c5f1c41055e509a480d8e8be1ae56f6",
|
5 |
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQClV9jABJzcK3vs\n+Lpflu0eGzt7ioI7qZNffnl8mm11e0YqSSJ95ZfV6DSydTx3kdpgG1pXdgWy9Vbu\nqIWuB5Hqf7MkZbsCat2nzmP8it3BeGyMaPSbUMhplRHeniTOcDvkO7PAVY/PKoIU\nrEDEvQCkVlII6IatbowSTG+OWjWkobJtdPK68WzFKsbAPJ4B79ITfwa1MXFD3TNn\nlRKsmVxteIvEP4W0nguc8FhkRlzf6OgnoGEcqbuVQHEgwz3V7soxFYquXRJ+ZTOG\nwQ0mUe53U1y1aiYfrWMP0/Lg6YkSv7ZhFvWrghh2R1f6YJHtSGi2SGcLHRrcFsrw\nA/Fol+6jAgMBAAECgf8IvrCsmGTIu5vZjrvmrV9DOn/+BcKn/xrhJLOqBQqwmvwO\ntdqUp8YC7jH4O8acXLg8Yv3Vw4uJnpCQmXfJVhDUAnsPvrlu7UCHCyJk8SE3ILob\nuq29V+IsaWdNcFjzH2G4MWDbfKbBYIf1Q2eoRr6NpE34LTMGukfcMgbC4udSrBZy\n7bxACyATZVhEGMnY5ZYTUyZKkM/0bsMoO8VncXmswntvz2wSZFYmBac7H99BMBib\ngWmGgAxQ3i/Ye7rDNaFCQwOo4skkfbuLR3KwmZDsJdtSLJpeoWFH2Ah5k5HKPy1W\n6iXSuXIG+T3nwkWVofCpyq6nogHSyvgotMmf8ckCgYEA1P98mHQHbcCl7eGah6Ga\n++N8ald6u2CP80KYI0IcA58iW+T8qPelARGsGGspPLQ9cFrmI9Rox0GrHorR+L20\nKB7kQmJEPbLS/pU9ka+Zk3Hf1BMSfWuhi/99ByubbOAa++XYYGqlyyVTC+0uVuQ9\nkms95hfkakmcJUiQlJEfLfkCgYEAxrliQmshphRjNGBBVBSvkscAhcnEhKmPZx5Q\ni/ygKmIPwW+jkBqoZIu1zCIP9w0LcX5kYKCwKNSfEaZCawDCLa2aAxWLrsn61FQx\noMwnQHfvrzGqOID2WTON0w5wurjVdzVzTiyiJWnyUbumauCjg3g380cmxbhGaLEy\nSp4ZmHsCgYBLjpXUPtSjykMSL4Vxt5IS6I+p6X5QGeD2mhj96OWnIzw8/O3jwnV1\n+57gyqLGNenVgWlCLIc+p7zcCMKTSjguQ0cVhWZPvK+8P5SnqXMBKtQLlvhoJVYZ\nI3hmosFvzc/Eq7Ql/67wcT0Ubf6SNETjO8epZ7BPQ+1wDF29Vf2JgQKBgEunjAbp\nLjhCDrqD4psV/PmOFV7Zv50ZyGRjoBqLJJa+Gm10CPr1iyIsJhv+48EUEEU27xPy\nWN5Sg/R+LU77TPGC491EuJbkgj+Phg1Ha7IZdwBlkf5M6nxvKhEtsDEF6Q6nJKyg\nRWKlAQGoxORvfRCyFeriLZqcWwHEY/cQVYI9AoGAFYrYsujk9fvCX9mMU7qFe27d\n9PNEaLoSweezEQUtTxEtuIM49nyVmtg3zOUx9tH+B6EEKY66HB2J92EZJ8gK59U3\nfd0nNQ/sw+RkClIfH1Muv7NmAINpb9eva5H7EcfrCMZlBiS8//ABWXSVW3WgBvmT\n8oca5n/CHQHftfzZePM=\n-----END PRIVATE KEY-----\n",
|
6 |
+
"client_email": "[email protected]",
|
7 |
+
"client_id": "102116671708400313176",
|
8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40bijay-c173f.iam.gserviceaccount.com",
|
12 |
+
"universe_domain": "googleapis.com"
|
13 |
+
}
|
database.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import firebase_admin
|
2 |
+
from firebase_admin import credentials, firestore
|
3 |
+
|
4 |
+
def init_firebase():
|
5 |
+
"""Initialize Firebase Admin SDK if not already initialized."""
|
6 |
+
try:
|
7 |
+
# Check if Firebase app is already initialized
|
8 |
+
if not firebase_admin._apps:
|
9 |
+
# Load Firebase credentials
|
10 |
+
cred = credentials.Certificate("cd.json")
|
11 |
+
firebase_admin.initialize_app(cred)
|
12 |
+
print("Firebase initialized successfully!")
|
13 |
+
else:
|
14 |
+
print("Firebase already initialized.")
|
15 |
+
|
16 |
+
# Return Firestore client
|
17 |
+
return firestore.client()
|
18 |
+
except Exception as e:
|
19 |
+
print(f"Error initializing Firebase: {e}")
|
20 |
+
raise
|
21 |
+
|
22 |
+
# Initialize Firestore
|
23 |
+
db = init_firebase()
|
display.py
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from database import db # Import Firestore client
|
3 |
+
import html
|
4 |
+
import re
|
5 |
+
|
6 |
+
def get_text_from_firebase(text_id):
|
7 |
+
"""Retrieve text from Firebase Firestore."""
|
8 |
+
try:
|
9 |
+
doc = db.collection("texts").document(text_id).get()
|
10 |
+
if doc.exists:
|
11 |
+
return doc.to_dict()["content"]
|
12 |
+
else:
|
13 |
+
return None
|
14 |
+
except Exception as e:
|
15 |
+
st.error(f"Error retrieving text from Firebase: {e}")
|
16 |
+
return None
|
17 |
+
|
18 |
+
def process_text(text):
|
19 |
+
"""Clean and structure the extracted text."""
|
20 |
+
# Preserve paragraph breaks
|
21 |
+
text = re.sub(r'\n\s*\n', '\n\n', text)
|
22 |
+
|
23 |
+
# Convert bullet points to HTML lists
|
24 |
+
text = re.sub(r'^(\s*•\s+)(.*)$', r'<li>\2</li>', text, flags=re.MULTILINE)
|
25 |
+
text = re.sub(r'(<li>.*</li>\n)+', r'<ul>\g<0></ul>\n', text)
|
26 |
+
|
27 |
+
# Detect headings (lines ending with colons or in all caps)
|
28 |
+
text = re.sub(r'^([A-Z][A-Z\s]+:?)\s*$', r'<h3 class="heading">\1</h3>', text, flags=re.MULTILINE)
|
29 |
+
|
30 |
+
# Convert URLs to clickable links
|
31 |
+
text = re.sub(r'(https?://\S+)', r'<a href="\1" target="_blank">\1</a>', text)
|
32 |
+
|
33 |
+
# Preserve original paragraph structure
|
34 |
+
paragraphs = text.split('\n\n')
|
35 |
+
processed = []
|
36 |
+
|
37 |
+
for p in paragraphs:
|
38 |
+
p = p.strip()
|
39 |
+
if p:
|
40 |
+
if p.startswith('<ul>') or p.startswith('<h3'):
|
41 |
+
processed.append(p)
|
42 |
+
else:
|
43 |
+
processed.append(f'<p>{p}</p>')
|
44 |
+
|
45 |
+
return '\n'.join(processed)
|
46 |
+
|
47 |
+
def main():
|
48 |
+
st.title("Accessibility-Optimized Viewer")
|
49 |
+
|
50 |
+
# Ask user for Document ID
|
51 |
+
text_id = st.text_input("Enter Document ID to view text:")
|
52 |
+
|
53 |
+
if text_id:
|
54 |
+
text = get_text_from_firebase(text_id)
|
55 |
+
if text:
|
56 |
+
# Accessibility Controls
|
57 |
+
col1, col2, col3 = st.columns(3)
|
58 |
+
with col1:
|
59 |
+
font_size = st.slider("Font Size", 8, 48, 16)
|
60 |
+
line_height = st.slider("Line Height", 1.0, 2.5, 1.5)
|
61 |
+
with col2:
|
62 |
+
font_color = st.color_picker("Text Color", "#000000")
|
63 |
+
bg_color = st.color_picker("Background Color", "#FFFFFF")
|
64 |
+
with col3:
|
65 |
+
contrast_mode = st.checkbox("High Contrast Mode")
|
66 |
+
dyslexia_font = st.checkbox("Dyslexia-Friendly Font")
|
67 |
+
|
68 |
+
# Apply contrast mode
|
69 |
+
if contrast_mode:
|
70 |
+
font_color = "#FFFFFF"
|
71 |
+
bg_color = "#000000"
|
72 |
+
|
73 |
+
# Create CSS styles
|
74 |
+
font_family = "Arial" if not dyslexia_font else "OpenDyslexic, sans-serif"
|
75 |
+
|
76 |
+
custom_css = f"""
|
77 |
+
<style>
|
78 |
+
.content {{
|
79 |
+
font-size: {font_size}px;
|
80 |
+
color: {font_color};
|
81 |
+
background-color: {bg_color};
|
82 |
+
line-height: {line_height};
|
83 |
+
font-family: {font_family};
|
84 |
+
padding: 20px;
|
85 |
+
border-radius: 10px;
|
86 |
+
margin: 10px 0;
|
87 |
+
white-space: pre-wrap;
|
88 |
+
word-wrap: break-word;
|
89 |
+
hyphens: auto;
|
90 |
+
}}
|
91 |
+
|
92 |
+
.content p {{
|
93 |
+
margin: 0.8em 0;
|
94 |
+
}}
|
95 |
+
|
96 |
+
.content ul {{
|
97 |
+
margin: 0.8em 20px;
|
98 |
+
padding-left: 20px;
|
99 |
+
list-style-type: disc;
|
100 |
+
}}
|
101 |
+
|
102 |
+
.content h3 {{
|
103 |
+
font-size: 1.2em;
|
104 |
+
margin: 1.2em 0 0.5em;
|
105 |
+
padding-bottom: 3px;
|
106 |
+
border-bottom: 2px solid {font_color};
|
107 |
+
}}
|
108 |
+
|
109 |
+
.content a {{
|
110 |
+
color: {font_color};
|
111 |
+
text-decoration: underline;
|
112 |
+
word-break: break-all;
|
113 |
+
}}
|
114 |
+
|
115 |
+
@keyframes highlight {{ 0% {{background: yellow;}} 100% {{background: transparent;}} }}
|
116 |
+
.highlight {{ animation: highlight 2s; }}
|
117 |
+
</style>
|
118 |
+
"""
|
119 |
+
st.markdown(custom_css, unsafe_allow_html=True)
|
120 |
+
|
121 |
+
# Process and display text
|
122 |
+
processed_text = process_text(html.escape(text))
|
123 |
+
st.markdown(f'<div class="content">{processed_text}</div>', unsafe_allow_html=True)
|
124 |
+
|
125 |
+
# Additional accessibility features
|
126 |
+
with st.expander("More Accessibility Options"):
|
127 |
+
col1, col2 = st.columns(2)
|
128 |
+
with col1:
|
129 |
+
letter_spacing = st.slider("Letter Spacing (px)", -1, 5, 0)
|
130 |
+
word_spacing = st.slider("Word Spacing (px)", 0, 10, 0)
|
131 |
+
with col2:
|
132 |
+
text_align = st.selectbox("Text Alignment", ["left", "justify", "center"])
|
133 |
+
text_transform = st.selectbox("Text Case", ["none", "uppercase", "lowercase"])
|
134 |
+
|
135 |
+
# Update CSS
|
136 |
+
st.markdown(f"""
|
137 |
+
<style>
|
138 |
+
.content {{
|
139 |
+
letter-spacing: {letter_spacing}px;
|
140 |
+
word-spacing: {word_spacing}px;
|
141 |
+
text-align: {text_align};
|
142 |
+
text-transform: {text_transform};
|
143 |
+
}}
|
144 |
+
</style>
|
145 |
+
""", unsafe_allow_html=True)
|
146 |
+
|
147 |
+
# Text-to-Speech Integration
|
148 |
+
if st.button("Read Aloud"):
|
149 |
+
st.markdown("""
|
150 |
+
<script>
|
151 |
+
var msg = new SpeechSynthesisUtterance();
|
152 |
+
msg.text = document.querySelector('.content').textContent;
|
153 |
+
window.speechSynthesis.speak(msg);
|
154 |
+
</script>
|
155 |
+
""", unsafe_allow_html=True)
|
156 |
+
else:
|
157 |
+
st.error("Text not found. Please check the ID.")
|
158 |
+
|
159 |
+
if __name__ == "__main__":
|
160 |
+
main()
|
requirements.txt
ADDED
Binary file (132 Bytes). View file
|
|