Akshayram1 commited on
Commit
05d5a92
·
verified ·
1 Parent(s): faf423e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +298 -0
app.py ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import re
4
+ from datetime import datetime
5
+
6
+ # Page configuration
7
+ st.set_page_config(
8
+ page_title="Scholarship Search",
9
+ page_icon="🎓",
10
+ layout="wide"
11
+ )
12
+
13
+ # Load and prepare data
14
+ @st.cache_data
15
+ def load_scholarships():
16
+ try:
17
+ df = pd.read_csv("scholarships_data.csv", quotechar='"', quoting=1)
18
+ df = df.map(lambda x: x.strip() if isinstance(x, str) else x)
19
+ df.rename(columns=lambda x: x.strip(), inplace=True)
20
+ return df
21
+ except Exception as e:
22
+ st.error(f"Error loading data: {str(e)}")
23
+ st.stop()
24
+
25
+ # Custom CSS for styling
26
+ def load_css():
27
+ st.markdown("""
28
+ <style>
29
+ /* Base styles */
30
+ body {
31
+ font-family: 'Roboto', sans-serif;
32
+ color: #333;
33
+ background-color: #f9f9f9;
34
+ }
35
+
36
+ /* Header styles */
37
+ .hero-section {
38
+ background: linear-gradient(135deg, #3a7bd5, #00d2ff);
39
+ color: white;
40
+ padding: 1.5rem;
41
+ border-radius: 0.8rem;
42
+ text-align: center;
43
+ margin-bottom: 1.5rem;
44
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
45
+ }
46
+
47
+ .hero-title {
48
+ font-size: 2.5rem;
49
+ font-weight: 700;
50
+ margin-bottom: 0.5rem;
51
+ text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
52
+ }
53
+
54
+ /* Search box */
55
+ .search-container {
56
+ background-color: white;
57
+ border-radius: 0.8rem;
58
+ padding: 1.5rem;
59
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
60
+ margin-bottom: 1.5rem;
61
+ text-align: center;
62
+ }
63
+
64
+ /* Results styles */
65
+ .results-container {
66
+ background-color: white;
67
+ border-radius: 0.8rem;
68
+ padding: 1.5rem;
69
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
70
+ }
71
+
72
+ .results-header {
73
+ color: #3a7bd5;
74
+ font-size: 1.5rem;
75
+ margin-bottom: 1rem;
76
+ font-weight: 600;
77
+ }
78
+
79
+ /* Scholarship item styles */
80
+ .scholarship-item {
81
+ padding: 1.2rem;
82
+ margin-bottom: 1rem;
83
+ border-radius: 0.6rem;
84
+ background-color: #f8faff;
85
+ border-left: 4px solid #3a7bd5;
86
+ transition: transform 0.2s ease;
87
+ }
88
+
89
+ .scholarship-item:hover {
90
+ transform: translateY(-2px);
91
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
92
+ }
93
+
94
+ .scholarship-name {
95
+ font-size: 1.3rem;
96
+ font-weight: 600;
97
+ color: #2c3e50;
98
+ margin-bottom: 0.5rem;
99
+ }
100
+
101
+ .scholarship-details {
102
+ font-size: 0.95rem;
103
+ color: #34495e;
104
+ margin-bottom: 0.8rem;
105
+ }
106
+
107
+ .deadline-tag {
108
+ background-color: #ff7675;
109
+ color: white;
110
+ padding: 0.2rem 0.6rem;
111
+ border-radius: 0.3rem;
112
+ font-size: 0.8rem;
113
+ font-weight: 600;
114
+ display: inline-block;
115
+ margin-bottom: 0.5rem;
116
+ }
117
+
118
+ .apply-button {
119
+ background-color: #3a7bd5;
120
+ color: white;
121
+ padding: 0.4rem 0.8rem;
122
+ border-radius: 0.3rem;
123
+ font-size: 0.9rem;
124
+ font-weight: 500;
125
+ text-decoration: none;
126
+ transition: all 0.2s ease;
127
+ display: inline-block;
128
+ }
129
+
130
+ .apply-button:hover {
131
+ background-color: #2c65b1;
132
+ transform: translateY(-1px);
133
+ }
134
+
135
+ /* Highlight search term */
136
+ .highlight {
137
+ background-color: #fff9c4;
138
+ padding: 0 2px;
139
+ border-radius: 2px;
140
+ }
141
+
142
+ /* No results message */
143
+ .no-results {
144
+ text-align: center;
145
+ padding: 2rem;
146
+ color: #7f8c8d;
147
+ }
148
+
149
+ /* Make search input larger and centered */
150
+ .search-input-container {
151
+ max-width: 800px;
152
+ margin: 0 auto;
153
+ }
154
+
155
+ .stTextInput>div>div>input {
156
+ font-size: 1.1rem;
157
+ padding: 0.8rem 1rem;
158
+ border-radius: 2rem;
159
+ border: 1px solid #ddd;
160
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
161
+ }
162
+
163
+ /* Footer */
164
+ .footer {
165
+ text-align: center;
166
+ padding: 1.5rem 0;
167
+ color: #7f8c8d;
168
+ font-size: 0.85rem;
169
+ margin-top: 2rem;
170
+ }
171
+ </style>
172
+ """, unsafe_allow_html=True)
173
+
174
+ # Format the deadline status
175
+ def format_deadline(deadline_str):
176
+ try:
177
+ if not deadline_str or pd.isna(deadline_str):
178
+ return "No deadline specified", "gray"
179
+
180
+ # Handle different date formats
181
+ try:
182
+ deadline = datetime.strptime(deadline_str, "%d-%m-%Y")
183
+ except ValueError:
184
+ try:
185
+ deadline = datetime.strptime(deadline_str, "%Y-%m-%d")
186
+ except ValueError:
187
+ return deadline_str, "gray"
188
+
189
+ today = datetime.now()
190
+ days_left = (deadline - today).days
191
+
192
+ if days_left < 0:
193
+ return "Expired", "#e74c3c"
194
+ elif days_left <= 7:
195
+ return f"{days_left} days left!", "#ff7675"
196
+ elif days_left <= 30:
197
+ return f"{days_left} days left", "#00b894"
198
+ else:
199
+ return f"{days_left} days left", "#3498db"
200
+ except:
201
+ return deadline_str, "gray"
202
+
203
+ # Highlight search terms in text
204
+ def highlight_text(text, search_term):
205
+ if not search_term or not text:
206
+ return text
207
+
208
+ pattern = re.compile(re.escape(search_term), re.IGNORECASE)
209
+ return pattern.sub(f'<span class="highlight">{search_term}</span>', text)
210
+
211
+ # Display scholarship results
212
+ def display_scholarships(df, search_term=""):
213
+ if df.empty:
214
+ st.markdown('<div class="no-results">No scholarships found. Try a different search term.</div>', unsafe_allow_html=True)
215
+ return
216
+
217
+ st.markdown(f"<div class='results-header'>Found {len(df)} scholarships</div>", unsafe_allow_html=True)
218
+
219
+ for _, row in df.iterrows():
220
+ name = row['Scholarship Name']
221
+ eligibility = row['Eligibility']
222
+ deadline = row['Deadline'] if 'Deadline' in row else ""
223
+ link = row['Link']
224
+
225
+ # Format deadline text and color
226
+ deadline_text, deadline_color = format_deadline(deadline)
227
+
228
+ # Highlight search terms if provided
229
+ if search_term:
230
+ name = highlight_text(name, search_term)
231
+ eligibility = highlight_text(eligibility, search_term)
232
+
233
+ # Display scholarship card
234
+ st.markdown(f"""
235
+ <div class="scholarship-item">
236
+ <div class="scholarship-name">{name}</div>
237
+ <div class="deadline-tag" style="background-color: {deadline_color}">⏰ {deadline_text}</div>
238
+ <div class="scholarship-details"><strong>Eligibility:</strong> {eligibility}</div>
239
+ <a href="{link}" target="_blank" class="apply-button">Apply Now</a>
240
+ </div>
241
+ """, unsafe_allow_html=True)
242
+
243
+ # App header
244
+ def display_header():
245
+ st.markdown("""
246
+ <div class="hero-section">
247
+ <h1 class="hero-title">🎓 Scholarship Search</h1>
248
+ </div>
249
+ """, unsafe_allow_html=True)
250
+
251
+ # Main function
252
+ def main():
253
+ # Load custom CSS
254
+ load_css()
255
+
256
+ # Load scholarship data
257
+ df = load_scholarships()
258
+
259
+ # Display header
260
+ display_header()
261
+
262
+ # Main search container
263
+ st.markdown('<div class="search-container">', unsafe_allow_html=True)
264
+ st.markdown('<div class="search-input-container">', unsafe_allow_html=True)
265
+ search_term = st.text_input("", placeholder="🔍 Search scholarships by name, eligibility, or keywords")
266
+ st.markdown('</div>', unsafe_allow_html=True)
267
+ st.markdown('</div>', unsafe_allow_html=True)
268
+
269
+ # Results container
270
+ st.markdown('<div class="results-container">', unsafe_allow_html=True)
271
+
272
+ # Process search
273
+ if search_term:
274
+ # Create search pattern
275
+ results_df = df[
276
+ df['Scholarship Name'].str.contains(search_term, case=False, na=False) |
277
+ df['Eligibility'].str.contains(search_term, case=False, na=False)
278
+ ]
279
+
280
+ # Display results
281
+ display_scholarships(results_df, search_term)
282
+ else:
283
+ # Display all scholarships when no search term is provided
284
+ display_scholarships(df.head(10))
285
+ if len(df) > 10:
286
+ st.markdown('<div style="text-align: center; margin-top: 20px;">Use the search bar above to find more specific scholarships</div>', unsafe_allow_html=True)
287
+
288
+ st.markdown('</div>', unsafe_allow_html=True)
289
+
290
+ # Footer
291
+ st.markdown("""
292
+ <div class="footer">
293
+ © 2025 Scholarship Search Portal | Data updated: March 2025
294
+ </div>
295
+ """, unsafe_allow_html=True)
296
+
297
+ if __name__ == "__main__":
298
+ main()