SR05 commited on
Commit
c674f01
1 Parent(s): 894ff40

Create project_file.py

Browse files
Files changed (1) hide show
  1. project_file.py +192 -0
project_file.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import bisect
4
+ import requests
5
+ from io import BytesIO
6
+ from bs4 import BeautifulSoup
7
+
8
+ # ------------------------------------------------------------------------------------
9
+ # Step 1: Load Data (Fetch and Prepare the DataFrame)
10
+ # ------------------------------------------------------------------------------------
11
+
12
+ @st.cache_data(ttl=3600)
13
+ def fetch_ods_file():
14
+ """
15
+ Fetches the .ods file from the visa decisions website and returns its binary content.
16
+
17
+ Returns:
18
+ - A BytesIO object containing the file content if successful.
19
+ - None if the file could not be fetched.
20
+ """
21
+ url = "https://www.ireland.ie/en/india/newdelhi/services/visas/processing-times-and-decisions/"
22
+ headers = {
23
+ "User-Agent": (
24
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
25
+ "(KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
26
+ )
27
+ }
28
+
29
+ response = requests.get(url, headers=headers)
30
+ if response.status_code == 200:
31
+ soup = BeautifulSoup(response.content, 'html.parser')
32
+ links = soup.find_all('a')
33
+
34
+ # Find the link containing the specific text
35
+ file_url = None
36
+ for link in links:
37
+ if "Visa decisions made from 1 January 2024 to" in link.get_text(strip=True):
38
+ file_url = link.get('href')
39
+ break
40
+
41
+ if file_url:
42
+ # Resolve relative URLs to absolute
43
+ if not file_url.startswith("http"):
44
+ file_url = requests.compat.urljoin(url, file_url)
45
+
46
+ file_response = requests.get(file_url, headers=headers)
47
+ if file_response.status_code == 200:
48
+ return BytesIO(file_response.content)
49
+ return None
50
+
51
+ @st.cache_data
52
+ def prepare_dataframe(file):
53
+ """
54
+ Prepares and cleans the DataFrame from the fetched .ods file.
55
+
56
+ Args:
57
+ file: The .ods file content as BytesIO.
58
+
59
+ Returns:
60
+ A cleaned and sorted DataFrame ready for searching.
61
+ """
62
+ df = pd.read_excel(file, engine='odf')
63
+ df.drop(columns=["Unnamed: 0", "Unnamed: 1"], inplace=True, errors="ignore")
64
+ df.dropna(how="all", inplace=True)
65
+ df.reset_index(drop=True, inplace=True)
66
+
67
+ # Identify the header row
68
+ for idx, row in df.iterrows():
69
+ if row["Unnamed: 2"] == "Application Number" and row["Unnamed: 3"] == "Decision":
70
+ df.columns = ["Application Number", "Decision"]
71
+ df = df.iloc[idx + 1:] # Skip the header row
72
+ break
73
+
74
+ # Process application numbers and sort the DataFrame
75
+ df["Application Number"] = df["Application Number"].astype(str).str.strip().astype(int)
76
+ df.sort_values(by="Application Number", inplace=True)
77
+ df.reset_index(drop=True, inplace=True)
78
+
79
+ return df
80
+
81
+ # ------------------------------------------------------------------------------------
82
+ # Step 2: Binary Search Utility for Finding Nearest Application Numbers
83
+ # ------------------------------------------------------------------------------------
84
+
85
+ def binary_search_nearest(df, target):
86
+ """
87
+ Uses binary search to find the nearest application numbers in the DataFrame.
88
+
89
+ Args:
90
+ df: The DataFrame containing the application numbers.
91
+ target: The target application number to search for.
92
+
93
+ Returns:
94
+ Two nearest application numbers (before and after the target).
95
+ """
96
+ application_numbers = df["Application Number"].tolist()
97
+ pos = bisect.bisect_left(application_numbers, target)
98
+
99
+ before = application_numbers[pos - 1] if pos > 0 else None
100
+ after = application_numbers[pos] if pos < len(application_numbers) else None
101
+
102
+ return before, after
103
+
104
+ # ------------------------------------------------------------------------------------
105
+ # Step 3: Search Application Status
106
+ # ------------------------------------------------------------------------------------
107
+
108
+ def search_application(df):
109
+ """
110
+ Handles the user input and searches for the application number in the DataFrame.
111
+
112
+ Args:
113
+ df: The DataFrame containing application numbers and decisions.
114
+ """
115
+ user_input = st.text_input("Enter your Application Number (including IRL if applicable):")
116
+
117
+ if user_input:
118
+ # Validate user input
119
+ if "irl" in user_input.lower():
120
+ try:
121
+ application_number = int("".join(filter(str.isdigit, user_input.lower().split("irl")[-1])))
122
+ if len(str(application_number)) < 8:
123
+ st.warning("Please enter a valid application number with at least 8 digits after IRL.")
124
+ return
125
+ except ValueError:
126
+ st.error("Invalid input after IRL. Please enter only digits.")
127
+ return
128
+ else:
129
+ if not user_input.isdigit() or len(user_input) < 8:
130
+ st.warning("Please enter at least 8 digits for your VISA application number.")
131
+ return
132
+ elif len(user_input) > 8:
133
+ st.warning("The application number cannot exceed 8 digits. Please correct your input.")
134
+ return
135
+ application_number = int(user_input)
136
+
137
+ # Search for the application number in the DataFrame
138
+ result = df[df["Application Number"] == application_number]
139
+
140
+ if not result.empty:
141
+ decision = result.iloc[0]["Decision"]
142
+ if decision.lower() == "refused":
143
+ st.error(f"Application Number: {application_number}\n\nDecision: **Refused**")
144
+ elif decision.lower() == "approved":
145
+ st.success(f"Application Number: {application_number}\n\nDecision: **Approved**")
146
+ else:
147
+ st.info(f"Application Number: {application_number}\n\nDecision: **{decision}**")
148
+ else:
149
+ st.warning(f"No record found for Application Number: {application_number}.")
150
+
151
+ # Find nearest application numbers using binary search
152
+ before, after = binary_search_nearest(df, application_number)
153
+
154
+ nearest_records = pd.DataFrame({
155
+ "Nearest Application": ["Before", "After"],
156
+ "Application Number": [before, after],
157
+ "Decision": [
158
+ df[df["Application Number"] == before]["Decision"].values[0] if before else None,
159
+ df[df["Application Number"] == after]["Decision"].values[0] if after else None
160
+ ],
161
+ "Difference": [
162
+ application_number - before if before else None,
163
+ after - application_number if after else None
164
+ ]
165
+ }).dropna()
166
+
167
+ if not nearest_records.empty:
168
+ st.subheader("Nearest Application Numbers")
169
+ st.table(nearest_records.reset_index(drop=True))
170
+ else:
171
+ st.info("No nearest application numbers found.")
172
+
173
+ # ------------------------------------------------------------------------------------
174
+ # Main Streamlit Application Logic
175
+ # ------------------------------------------------------------------------------------
176
+
177
+ def main():
178
+ st.title("Visa Application Status Checker")
179
+
180
+ # Fetch and prepare the data
181
+ ods_file = fetch_ods_file()
182
+ if ods_file:
183
+ df = prepare_dataframe(ods_file)
184
+ if df is not None:
185
+ search_application(df)
186
+ else:
187
+ st.error("Failed to prepare the data.")
188
+ else:
189
+ st.error("Failed to fetch the .ods file.")
190
+
191
+ if __name__ == "__main__":
192
+ main()