mrfirdauss commited on
Commit
6228ce3
Β·
1 Parent(s): e2304c7

feat: add page doc gen

Browse files
src/pages/{Visa_Indo.py β†’ 01_Visa_Indo.py} RENAMED
File without changes
src/pages/{Passport_Power_Explorer.py β†’ 02_Passport_Power_Explorer.py} RENAMED
@@ -1,169 +1,164 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- import re
5
- import os
6
-
7
- # --- Page Configuration ---
8
- st.set_page_config(
9
- page_title="Passport Power Explorer",
10
- page_icon="✈️",
11
- layout="wide"
12
- )
13
-
14
- # --- Data Loading and Processing ---
15
-
16
- @st.cache_data
17
- def load_and_process_data(filepath):
18
- """
19
- Loads visa data from a CSV, cleans it, and extracts structured information.
20
- Caches the result for performance.
21
- """
22
- try:
23
- df = pd.read_csv(filepath)
24
- except FileNotFoundError:
25
- st.error(f"Error: The file was not found at '{filepath}'. Please make sure 'asean_visa_avaibility_playwright.csv' is in the project's src/data directory.")
26
- return pd.DataFrame()
27
-
28
- # --- Feature Engineering: Extract Visa Type and Duration ---
29
-
30
- # 1. Extract Duration in Days
31
- def extract_days(text):
32
- if not isinstance(text, str):
33
- return np.nan
34
- # Find numbers followed by 'days'
35
- matches = re.findall(r'(\d+)\s*days', text, re.IGNORECASE)
36
- if matches:
37
- return int(matches[0])
38
- return np.nan
39
-
40
- df['duration_days'] = df['text'].apply(extract_days)
41
-
42
- # 2. Categorize Visa Type
43
- def categorize_visa(text):
44
- if not isinstance(text, str):
45
- return "Unknown"
46
- text_lower = text.lower()
47
- if 'visa-free' in text_lower:
48
- return "βœ… Visa-Free"
49
- if 'visa on arrival' in text_lower:
50
- return "πŸ›¬ Visa on Arrival"
51
- if 'evisa' in text_lower or 'eta' in text_lower:
52
- return "πŸ“§ eVisa / eTA"
53
- if 'visa required' in text_lower:
54
- return "❌ Visa Required"
55
- return "πŸ“„ Other / Pre-enrollment"
56
-
57
- df['visa_category'] = df['text'].apply(categorize_visa)
58
-
59
- # Clean up column names for display
60
- df.rename(columns={
61
- 'text': 'Requirement',
62
- 'pass': 'Passport',
63
- 'dest': 'Destination',
64
- 'source': 'Source Country',
65
- 'duration_days': 'Duration (Days)',
66
- 'visa_category': 'Visa Category'
67
- }, inplace=True)
68
-
69
- return df
70
-
71
- # --- Main Application UI ---
72
-
73
- st.title("✈️ Passport Power & Visa Explorer")
74
- st.markdown("Analyze inbound and outbound visa requirements for Southeast Asian countries based on the provided dataset.")
75
-
76
- # Load the data
77
- # Adjust the path to be relative to the script's location if needed
78
- # Assuming the script is in src/pages and the CSV is in the root
79
- # The path should be ../../visa_avaibility_playwright_20251015.csv
80
- file_path = "src/data/asean_visa_avaibility_playwright.csv"
81
- visa_df = load_and_process_data(file_path)
82
-
83
- if not visa_df.empty:
84
-
85
- # --- Sidebar Filters ---
86
- st.sidebar.header("πŸ” Filters")
87
-
88
- # 1. Select Focus Country
89
- focus_countries = ['Indonesia', 'Vietnam', 'Philippines', 'Thailand']
90
- selected_country = st.sidebar.selectbox(
91
- "Select your focus country:",
92
- options=focus_countries
93
- )
94
-
95
- # 2. Select Travel Direction (Inbound/Outbound)
96
- travel_direction = st.sidebar.radio(
97
- "Select travel direction:",
98
- options=['Outbound', 'Inbound'],
99
- horizontal=True
100
- )
101
-
102
- # --- Filtering Logic ---
103
- if travel_direction == 'Outbound':
104
- filtered_df = visa_df[visa_df['Source Country'] == selected_country].copy()
105
- st.header(f"πŸ›‚ Outbound Travel for {selected_country} Passport Holders")
106
- else: # Inbound
107
- filtered_df = visa_df[visa_df['Destination'] == selected_country].copy()
108
- st.header(f"πŸ›¬ Inbound Travel to {selected_country}")
109
-
110
- # --- Dynamic Filters Based on Data ---
111
-
112
- # 3. Filter by Visa Category
113
- visa_categories = sorted(filtered_df['Visa Category'].unique())
114
- selected_categories = st.sidebar.multiselect(
115
- "Filter by Visa Category:",
116
- options=visa_categories,
117
- default=visa_categories # Default to all selected
118
- )
119
-
120
- # 4. Filter by Duration
121
- min_duration, max_duration = 0, int(filtered_df['Duration (Days)'].max())
122
-
123
- duration_range = st.sidebar.slider(
124
- "Filter by Stay Duration (Days):",
125
- min_value=min_duration,
126
- max_value=max_duration,
127
- value=(min_duration, max_duration) # Default to full range
128
- )
129
-
130
- # Apply category and duration filters
131
- filtered_df = filtered_df[filtered_df['Visa Category'].isin(selected_categories)]
132
-
133
- # Handle slider filtering, including NaNs
134
- min_select, max_select = duration_range
135
- # Keep rows where duration is within range OR where duration is NaN (not specified)
136
- filtered_df = filtered_df[
137
- (filtered_df['Duration (Days)'].between(min_select, max_select)) |
138
- (filtered_df['Duration (Days)'].isnull())
139
- ]
140
-
141
- # --- Display Results ---
142
-
143
- st.markdown("---")
144
-
145
- # Display summary metrics
146
- col1, col2, col3 = st.columns(3)
147
- col1.metric("Total Countries Found", f"{len(filtered_df)}")
148
-
149
- visa_free_count = len(filtered_df[filtered_df['Visa Category'] == 'βœ… Visa-Free'])
150
- col2.metric("Visa-Free Destinations", f"{visa_free_count}")
151
-
152
- visa_required_count = len(filtered_df[filtered_df['Visa Category'] == '❌ Visa Required'])
153
- col3.metric("Visa Required", f"{visa_required_count}")
154
-
155
- st.markdown("### Visa Requirements Data")
156
-
157
- # Define columns to display
158
- display_cols_outbound = ['Destination', 'Visa Category', 'Requirement', 'Duration (Days)']
159
- display_cols_inbound = ['Source Country', 'Passport', 'Visa Category', 'Requirement', 'Duration (Days)']
160
-
161
- display_columns = display_cols_outbound if travel_direction == 'Outbound' else display_cols_inbound
162
-
163
- st.dataframe(
164
- filtered_df[display_columns].reset_index(drop=True),
165
- use_container_width=True,
166
- hide_index=True
167
- )
168
- else:
169
  st.warning("Could not load visa data to display.")
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import re
5
+ import os
6
+
7
+ # --- Page Configuration ---
8
+ st.set_page_config(
9
+ page_title="Passport Power Explorer",
10
+ page_icon="✈️",
11
+ layout="wide"
12
+ )
13
+
14
+
15
+ @st.cache_data
16
+ def load_and_process_data(filepath):
17
+ """
18
+ Loads visa data from a CSV, cleans it, and extracts structured information.
19
+ Caches the result for performance.
20
+ """
21
+ try:
22
+ df = pd.read_csv(filepath)
23
+ except FileNotFoundError:
24
+ st.error(f"Error: The file was not found at '{filepath}'. Please make sure 'asean_visa_avaibility_playwright.csv' is in the project's src/data directory.")
25
+ return pd.DataFrame()
26
+
27
+ def extract_days(text):
28
+ if not isinstance(text, str):
29
+ return np.nan
30
+ matches = re.findall(r'(\d+)\s*days', text, re.IGNORECASE)
31
+ if matches:
32
+ return int(matches[0])
33
+ return np.nan
34
+
35
+ df['duration_days'] = df['text'].apply(extract_days)
36
+
37
+ # 2. Categorize Visa Type
38
+ def categorize_visa(text):
39
+ if not isinstance(text, str):
40
+ return "Unknown"
41
+ text_lower = text.lower()
42
+ if 'visa-free' in text_lower:
43
+ return "βœ… Visa-Free"
44
+ if 'visa on arrival' in text_lower:
45
+ return "πŸ›¬ Visa on Arrival"
46
+ if 'evisa' in text_lower or 'eta' in text_lower:
47
+ return "πŸ“§ eVisa / eTA"
48
+ if 'visa required' in text_lower:
49
+ return "❌ Visa Required"
50
+ return "πŸ“„ Other / Pre-enrollment"
51
+
52
+ df['visa_category'] = df['text'].apply(categorize_visa)
53
+
54
+ # Clean up column names for display
55
+ df.rename(columns={
56
+ 'text': 'Requirement',
57
+ 'pass': 'Passport',
58
+ 'dest': 'Destination',
59
+ 'source': 'Source Country',
60
+ 'duration_days': 'Duration (Days)',
61
+ 'visa_category': 'Visa Category'
62
+ }, inplace=True)
63
+
64
+ return df
65
+
66
+ # --- Main Application UI ---
67
+
68
+ st.title("✈️ Passport Power & Visa Explorer")
69
+ st.markdown("Analyze inbound and outbound visa requirements for Southeast Asian countries based on the provided dataset.")
70
+
71
+ # Load the data
72
+ # Adjust the path to be relative to the script's location if needed
73
+ # Assuming the script is in src/pages and the CSV is in the root
74
+ # The path should be ../../visa_avaibility_playwright_20251015.csv
75
+ file_path = "src/data/asean_visa_avaibility_playwright.csv"
76
+ visa_df = load_and_process_data(file_path)
77
+
78
+ if not visa_df.empty:
79
+
80
+ # --- Sidebar Filters ---
81
+ st.sidebar.header("πŸ” Filters")
82
+
83
+ # 1. Select Focus Country
84
+ focus_countries = ['Indonesia', 'Vietnam', 'Philippines', 'Thailand']
85
+ selected_country = st.sidebar.selectbox(
86
+ "Select your focus country:",
87
+ options=focus_countries
88
+ )
89
+
90
+ # 2. Select Travel Direction (Inbound/Outbound)
91
+ travel_direction = st.sidebar.radio(
92
+ "Select travel direction:",
93
+ options=['Outbound', 'Inbound'],
94
+ horizontal=True
95
+ )
96
+
97
+ # --- Filtering Logic ---
98
+ if travel_direction == 'Outbound':
99
+ filtered_df = visa_df[visa_df['Source Country'] == selected_country].copy()
100
+ st.header(f"πŸ›‚ Outbound Travel for {selected_country} Passport Holders")
101
+ else: # Inbound
102
+ filtered_df = visa_df[visa_df['Destination'] == selected_country].copy()
103
+ st.header(f"πŸ›¬ Inbound Travel to {selected_country}")
104
+
105
+ # --- Dynamic Filters Based on Data ---
106
+
107
+ # 3. Filter by Visa Category
108
+ visa_categories = sorted(filtered_df['Visa Category'].unique())
109
+ selected_categories = st.sidebar.multiselect(
110
+ "Filter by Visa Category:",
111
+ options=visa_categories,
112
+ default=visa_categories # Default to all selected
113
+ )
114
+
115
+ # 4. Filter by Duration
116
+ min_duration, max_duration = 0, int(filtered_df['Duration (Days)'].max())
117
+
118
+ duration_range = st.sidebar.slider(
119
+ "Filter by Stay Duration (Days):",
120
+ min_value=min_duration,
121
+ max_value=max_duration,
122
+ value=(min_duration, max_duration) # Default to full range
123
+ )
124
+
125
+ # Apply category and duration filters
126
+ filtered_df = filtered_df[filtered_df['Visa Category'].isin(selected_categories)]
127
+
128
+ # Handle slider filtering, including NaNs
129
+ min_select, max_select = duration_range
130
+ # Keep rows where duration is within range OR where duration is NaN (not specified)
131
+ filtered_df = filtered_df[
132
+ (filtered_df['Duration (Days)'].between(min_select, max_select)) |
133
+ (filtered_df['Duration (Days)'].isnull())
134
+ ]
135
+
136
+ # --- Display Results ---
137
+
138
+ st.markdown("---")
139
+
140
+ # Display summary metrics
141
+ col1, col2, col3 = st.columns(3)
142
+ col1.metric("Total Countries Found", f"{len(filtered_df)}")
143
+
144
+ visa_free_count = len(filtered_df[filtered_df['Visa Category'] == 'βœ… Visa-Free'])
145
+ col2.metric("Visa-Free Destinations", f"{visa_free_count}")
146
+
147
+ visa_required_count = len(filtered_df[filtered_df['Visa Category'] == '❌ Visa Required'])
148
+ col3.metric("Visa Required", f"{visa_required_count}")
149
+
150
+ st.markdown("### Visa Requirements Data")
151
+
152
+ # Define columns to display
153
+ display_cols_outbound = ['Destination', 'Visa Category', 'Requirement', 'Duration (Days)']
154
+ display_cols_inbound = ['Source Country', 'Passport', 'Visa Category', 'Requirement', 'Duration (Days)']
155
+
156
+ display_columns = display_cols_outbound if travel_direction == 'Outbound' else display_cols_inbound
157
+
158
+ st.dataframe(
159
+ filtered_df[display_columns].reset_index(drop=True),
160
+ use_container_width=True,
161
+ hide_index=True
162
+ )
163
+ else:
 
 
 
 
 
164
  st.warning("Could not load visa data to display.")
src/pages/03_Document_Generator.py ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import datetime
4
+ import pandas as pd
5
+ import base64
6
+
7
+ import os
8
+ from dotenv import load_dotenv
9
+
10
+ load_dotenv()
11
+
12
+ API_BASE_URL = os.getenv("BASE_URI", "https://localhost:5000")
13
+ TODAY = datetime.date.today()
14
+
15
+ # --- Helper Function ---
16
+ def generate_and_download(endpoint, payload, filename):
17
+ """
18
+ Handles the API POST request, displays the PDF in an iframe,
19
+ and provides a download button.
20
+ """
21
+ try:
22
+ url = f"{API_BASE_URL}{endpoint}"
23
+
24
+ # Display the JSON payload for debugging
25
+ with st.expander("View Request JSON Payload"):
26
+ st.json(payload)
27
+
28
+ response = requests.post(url, json=payload)
29
+
30
+ if response.status_code == 200 and response.headers.get('Content-Type') == 'application/pdf':
31
+ st.success("βœ… PDF Generated Successfully!")
32
+
33
+ # Get the PDF content
34
+ pdf_content = response.content
35
+
36
+ # --- NEW: Display PDF in iframe (using st.markdown) ---
37
+ # Base64 encode the PDF content
38
+ base64_pdf = base64.b64encode(pdf_content).decode('utf-8')
39
+
40
+ # Create the HTML for the iframe
41
+ st.subheader("πŸ“„ PDF Preview")
42
+ pdf_display_html = f'<iframe src="data:application/pdf;base64,{base64_pdf}" width="100%" height="800" type="application/pdf" style="border: 1px solid #ddd; border-radius: 8px;"></iframe>'
43
+ st.markdown(pdf_display_html, unsafe_allow_html=True)
44
+ # --- END NEW ---
45
+
46
+ # Keep the download button as well
47
+ st.download_button(
48
+ label="Download PDF",
49
+ data=pdf_content, # Use the stored content
50
+ file_name=filename,
51
+ mime="application/pdf"
52
+ )
53
+ else:
54
+ st.error(f"❌ Error generating PDF (Status Code: {response.status_code}):")
55
+ try:
56
+ # Try to display the JSON error message from the API
57
+ st.json(response.json())
58
+ except requests.exceptions.JSONDecodeError:
59
+ # Fallback if the error response isn't JSON
60
+ st.text(response.text)
61
+
62
+ except requests.exceptions.ConnectionError:
63
+ st.error(f"❌ Connection Error: Could not connect to the API at {API_BASE_URL}.")
64
+ st.info("Please ensure your local Flask API server is running.")
65
+ except Exception as e:
66
+ st.error(f"An unexpected error occurred: {e}")
67
+
68
+ # --- Streamlit App UI ---
69
+ st.set_page_config(page_title="Visa Letter PDF Generator", layout="wide")
70
+ st.title("🌍 Visa Letter PDF Generator")
71
+ st.caption(f"Frontend for the Visa Letter API (assumed running at `{API_BASE_URL}`)")
72
+
73
+ tab1, tab2, tab3, tab4, tab5 = st.tabs([
74
+ "πŸ‡ͺπŸ‡Ί Schengen Visa",
75
+ "πŸ‡―πŸ‡΅ Japan Multi-Entry",
76
+ "🀝 Sponsorship Letter",
77
+ "STATEMENT Housewife Statement",
78
+ "COLLECTION Passport Collection"
79
+ ])
80
+
81
+ # --- Tab 1: Schengen Visa ---
82
+ with tab1:
83
+ st.header("πŸ‡ͺπŸ‡Ί Schengen Visa Cover Letter")
84
+
85
+ trip_type = st.radio("Select Trip Type", ["Individual", "Group"], horizontal=True)
86
+
87
+ with st.form("schengen_form"):
88
+ col1, col2 = st.columns(2)
89
+
90
+ with col1:
91
+ st.subheader("Trip Details")
92
+ country = st.text_input("Country of Embassy (e.g., Germany)", "Germany")
93
+ city = st.text_input("City of Application (e.g., Jakarta)", "Jakarta")
94
+ purpose = st.text_input("Purpose of Trip (e.g., tourism)", "tourism")
95
+ main_destination = st.text_input("Main Destination", "Germany")
96
+ event = st.text_input("Event (e.g., personal vacation)", "personal vacation")
97
+ other_destinations = st.text_input("Other Destinations (e.g., France and Italy)", "France and Italy")
98
+ travel_start = st.text_input("Travel Start Date", "1st August 2024")
99
+ travel_end = st.text_input("Travel End Date", "16th August 2024")
100
+ duration = st.text_input("Duration", "16 days and 15 nights")
101
+
102
+ with col2:
103
+ st.subheader("Main Applicant Details")
104
+ pa_name = st.text_input("Full Name", "John Doe")
105
+ pa_dob = st.text_input("Date of Birth", "1st January 1985")
106
+ pa_nationality = st.text_input("Nationality", "Indonesian")
107
+ pa_occupation = st.text_input("Occupation", "Software Engineer")
108
+ pa_passport = st.text_input("Passport Number", "A1234567")
109
+
110
+ st.subheader("Contact & Financials")
111
+ trip_highlight = st.text_area("Trip Highlight", "visit cultural landmarks, museums, and enjoy sightseeing in Germany")
112
+ contact_email = st.text_input("Contact Email", "john@example.com")
113
+ contact_phone = st.text_input("Contact Phone", "+62 812 3456 7890")
114
+ job_commitment = st.text_input("Job Commitment", "Software Engineer at PT. Example Indonesia")
115
+ financial_status = st.text_input("Financial Status", "sound")
116
+
117
+ # Group Members Section
118
+ if trip_type == "Group":
119
+ st.subheader("Group Members")
120
+ st.info("Add your travel companions below. Click '+' to add rows.")
121
+ group_members_df = pd.DataFrame([
122
+ {
123
+ "relationship": "Wife", "name": "Jane Doe", "dob": "5th May 1987",
124
+ "occupation": "Teacher", "nationality": "Indonesian", "passport_number": "B7654321"
125
+ },
126
+ {
127
+ "relationship": "Son", "name": "Jack Doe", "dob": "10th August 2010",
128
+ "occupation": "Student", "nationality": "Indonesian", "passport_number": "C9988776"
129
+ }
130
+ ])
131
+ edited_group_members = st.data_editor(
132
+ group_members_df,
133
+ num_rows="dynamic",
134
+ use_container_width=True
135
+ )
136
+
137
+ submit_schengen = st.form_submit_button("Generate Schengen PDF")
138
+
139
+ if submit_schengen:
140
+ personal_details = {
141
+ "name": pa_name,
142
+ "dob": pa_dob,
143
+ "nationality": pa_nationality,
144
+ "occupation": pa_occupation,
145
+ "passport_number": pa_passport
146
+ }
147
+
148
+ payload = {
149
+ "country": country,
150
+ "city": city,
151
+ "purpose": purpose,
152
+ "main_destination": main_destination,
153
+ "event": event,
154
+ "other_destinations": other_destinations,
155
+ "travel_start": travel_start,
156
+ "travel_end": travel_end,
157
+ "duration": duration,
158
+ "personal_details": personal_details,
159
+ "trip_highlight": trip_highlight,
160
+ "contact_email": contact_email,
161
+ "contact_phone": contact_phone,
162
+ "job_commitment": job_commitment,
163
+ "financial_status": financial_status
164
+ }
165
+
166
+ endpoint = "/generate/schengen"
167
+
168
+
169
+ if trip_type == "Group":
170
+ # Convert DataFrame to list of dicts
171
+ payload["group_members"] = edited_group_members.to_dict('records')
172
+ filename = "Schengen_Group_Cover_Letter.pdf"
173
+ else:
174
+ filename = "Schengen_Individual_Cover_Letter.pdf"
175
+
176
+ generate_and_download(endpoint, payload, filename)
177
+
178
+
179
+ # --- Tab 2: Japan Multi-Entry ---
180
+ with tab2:
181
+ st.header("πŸ‡―πŸ‡΅ Japan Multi-Entry Visa Letter")
182
+ with st.form("japan_form"):
183
+ col1, col2 = st.columns(2)
184
+ with col1:
185
+ st.subheader("Applicant Details")
186
+ name = st.text_input("Full Name", "John Doe")
187
+ address = st.text_area("Address", "Gatot Subroto St., Senayan")
188
+ city = st.text_input("City", "Jakarta Selatan")
189
+
190
+ with col2:
191
+ st.subheader("Contact & Location")
192
+ postal_code = st.text_input("Postal Code", "51001")
193
+ email = st.text_input("Email", "john@example.com")
194
+ phone = st.text_input("Phone", "+62 812 3456 7890")
195
+
196
+ submit_japan = st.form_submit_button("Generate Japan PDF")
197
+
198
+ if submit_japan:
199
+ payload = {
200
+ "name": name,
201
+ "address": address,
202
+ "city": city,
203
+ "postal_code": postal_code,
204
+ "email": email,
205
+ "phone": phone
206
+ }
207
+ generate_and_download("/generate/japan-multientry-tourist", payload, "Japan_MultiEntry_Visa_Letter.pdf")
208
+
209
+
210
+ # --- Tab 3: Sponsorship Letter ---
211
+ with tab3:
212
+ st.header("🀝 Sponsorship Letter")
213
+ with st.form("sponsorship_form"):
214
+ col1, col2, col3 = st.columns(3)
215
+
216
+ with col1:
217
+ st.subheader("Sponsor Details")
218
+ sponsor_name = st.text_input("Sponsor Name", "Mr. John Sponsor")
219
+ sponsor_address = st.text_area("Sponsor Address", "123 Sponsor St, Appt 4B")
220
+ sponsor_postal_code = st.text_input("Sponsor City, State, Postal", "New York, NY 10001")
221
+ sponsor_email = st.text_input("Sponsor Email", "john.sponsor@email.com")
222
+ sponsor_contact_number = st.text_input("Sponsor Contact Number", "+1 (555) 123-4567")
223
+
224
+ with col2:
225
+ st.subheader("Embassy Details")
226
+ officer_title = st.text_input("Officer Title", "Visa Officer")
227
+ embassy_name = st.text_input("Embassy Name", "Embassy of [Country]")
228
+ embassy_address = st.text_area("Embassy Address", "456 Embassy Row")
229
+ embassy_city_state_postal = st.text_input("Embassy City, State, Postal", "Washington, D.C. 20008")
230
+
231
+ st.subheader("Applicant Details")
232
+ applicant_name = st.text_input("Applicant Name", "Ms. Jane Applicant")
233
+ applicant_dob = st.text_input("Applicant Date of Birth", "January 15, 1995")
234
+ applicant_passport_no = st.text_input("Applicant Passport Number", "X12345678")
235
+
236
+ with col3:
237
+ st.subheader("Visit Details")
238
+ visa_name = st.text_input("Visa Type (e.g., B-2 Visitor Visa)", "B-2 Visitor Visa")
239
+ sponsor_relationship = st.text_input("Sponsor's Relationship to Applicant", "friend")
240
+ visit_reason = st.text_input("Reason for Visit", "attend my wedding and for tourism")
241
+ destination_country = st.text_input("Destination Country", "the United States")
242
+ visit_start_date = st.text_input("Visit Start Date", "December 1, 2024")
243
+ visit_end_date = st.text_input("Visit End Date", "December 20, 2024")
244
+ visit_purpose_details = st.text_area("Detailed Purpose of Visit", "a personal visit to attend my wedding ceremony on December 5th and to tour New York City")
245
+
246
+ submit_sponsorship = st.form_submit_button("Generate Sponsorship PDF")
247
+
248
+ if submit_sponsorship:
249
+ payload = {
250
+ "sponsor_name": sponsor_name,
251
+ "sponsor_address": sponsor_address,
252
+ "sponsor_postal_code": sponsor_postal_code,
253
+ "sponsor_email": sponsor_email,
254
+ "sponsor_contact_number": sponsor_contact_number,
255
+ "officer_title": officer_title,
256
+ "embassy_name": embassy_name,
257
+ "embassy_address": embassy_address,
258
+ "embassy_city_state_postal": embassy_city_state_postal,
259
+ "applicant_name": applicant_name,
260
+ "applicant_dob": applicant_dob,
261
+ "applicant_passport_no": applicant_passport_no,
262
+ "visa_name": visa_name,
263
+ "sponsor_relationship": sponsor_relationship,
264
+ "visit_reason": visit_reason,
265
+ "destination_country": destination_country,
266
+ "visit_start_date": visit_start_date,
267
+ "visit_end_date": visit_end_date,
268
+ "visit_purpose_details": visit_purpose_details
269
+ }
270
+ generate_and_download("/generate/sponsorship", payload, "Sponsorship_Letter.pdf")
271
+
272
+
273
+ # --- Tab 4: Housewife Statement ---
274
+ with tab4:
275
+ st.header("STATEMENT Housewife Statement Letter")
276
+ with st.form("housewife_form"):
277
+ col1, col2 = st.columns(2)
278
+ with col1:
279
+ applicant_name = st.text_input("Applicant Name", "Mrs. Sarah Wijaya")
280
+ applicant_dob = st.text_input("Applicant Place & Date of Birth", "Jakarta, April 10, 1985")
281
+ applicant_passport = st.text_input("Applicant Passport Number", "B1234567")
282
+ sponsor_name = st.text_input("Sponsor's Name (Husband)", "Mr. Budi Wijaya")
283
+ sponsor_bank_details = st.text_input("Sponsor's Bank Details", "Bank Central Asia (BCA): 123-456-7890")
284
+
285
+ with col2:
286
+ destination_country = st.text_input("Destination Country", "Japan")
287
+ visa_type = st.text_input("Visa Type", "tourism")
288
+ visit_end_date = st.text_input("Visit End Date", "November 20, 2024")
289
+ travel_companions = st.text_input("Travel Companions", "my husband, Budi Wijaya, and my son, Putra Wijaya")
290
+ letter_location = st.text_input("Location of Letter Signing", "Jakarta")
291
+ letter_date = st.text_input("Date of Letter", "October 28, 2024")
292
+
293
+ submit_housewife = st.form_submit_button("Generate Housewife Statement PDF")
294
+
295
+ if submit_housewife:
296
+ payload = {
297
+ "applicant_name": applicant_name,
298
+ "applicant_dob": applicant_dob,
299
+ "applicant_passport": applicant_passport,
300
+ "sponsor_name": sponsor_name,
301
+ "sponsor_bank_details": sponsor_bank_details,
302
+ "destination_country": destination_country,
303
+ "visa_type": visa_type,
304
+ "visit_end_date": visit_end_date,
305
+ "travel_companions": travel_companions,
306
+ "letter_location": letter_location,
307
+ "letter_date": letter_date
308
+ }
309
+ generate_and_download("/generate/housewife-statement", payload, "Housewife_Statement.pdf")
310
+
311
+
312
+ # --- Tab 5: Passport Collection ---
313
+ with tab5:
314
+ st.header("COLLECTION Passport Collection Consent Letter")
315
+
316
+ with st.form("passport_collection_form"):
317
+ col1, col2 = st.columns(2)
318
+ with col1:
319
+ st.subheader("Applicant Details")
320
+ applicant_name = st.text_input("Applicant Name", "Budi Hartono")
321
+ applicant_nik = st.text_input("Applicant NIK (ID Number)", "3171234567890001")
322
+ applicant_address = st.text_area("Applicant Address", "Jl. Kemerdekaan No. 17, Jakarta Pusat")
323
+ passport_no = st.text_input("Applicant Passport Number", "C1234567")
324
+
325
+ with col2:
326
+ st.subheader("Agent/Representative Details")
327
+ agent_name = st.text_input("Agent's Name", "Citra Lestari")
328
+ agent_nik = st.text_input("Agent's NIK (ID Number)", "3171098765432100")
329
+ agent_address = st.text_area("Agent's Address", "Jl. Melati No. 8, Jakarta Selatan")
330
+
331
+ st.subheader("Letter Details")
332
+ letter_location = st.text_input("Location of Letter Signing", "Jakarta")
333
+ letter_date = st.text_input("Date of Letter", "18th July 2024")
334
+
335
+ submit_passport_collection = st.form_submit_button("Generate Passport Collection PDF")
336
+
337
+ if submit_passport_collection:
338
+ payload = {
339
+ "applicant_name": applicant_name,
340
+ "applicant_nik": applicant_nik,
341
+ "applicant_address": applicant_address,
342
+ "agent_name": agent_name,
343
+ "agent_nik": agent_nik,
344
+ "agent_address": agent_address,
345
+ "passport_no": passport_no,
346
+ "letter_location": letter_location,
347
+ "letter_date": letter_date
348
+ }
349
+ generate_and_download("/generate/passport-collection", payload, "Passport_Collection_Letter.pdf")
350
+