File size: 13,105 Bytes
e973372
1290ec4
 
77a6cf5
1290ec4
 
 
e973372
1290ec4
 
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
 
 
 
 
 
 
 
 
 
 
 
 
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
77a6cf5
 
 
1290ec4
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
77a6cf5
 
 
 
1290ec4
77a6cf5
1290ec4
77a6cf5
 
 
1290ec4
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
77a6cf5
 
 
 
 
 
 
1290ec4
c892235
77a6cf5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290ec4
77a6cf5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
import streamlit as st
from PIL import Image
import io
import time
from utils.aadhaar_ocr import extract_aadhaar_details
from utils.pan_ocr import extract_pan_details
from utils.face_match import match_faces

st.set_page_config(page_title="Smart KYC Verification", page_icon="πŸ”", layout="wide")

# Allowed file types and max file size (5MB)
ALLOWED_EXTENSIONS = ["jpg", "jpeg", "png"]
MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB

def show_temp_error(message, duration=5):
    """Show error message for a specified duration (in seconds) and then clear it."""
    placeholder = st.empty()
    placeholder.error(message)
    time.sleep(duration)
    placeholder.empty()

def validate_file(file):
    """
    Validate file extension and file size. Also attempts to open the image.
    Returns a tuple (image, error_message). If valid, error_message is None.
    """
    if not file:
        return None, None
    filename = file.name.lower()
    extension = filename.split('.')[-1]
    if extension not in ALLOWED_EXTENSIONS:
        return None, f"File extension .{extension} is not allowed. Allowed extensions: {ALLOWED_EXTENSIONS}"
    if file.size > MAX_FILE_SIZE:
        return None, f"File size {file.size} bytes exceeds the limit of {MAX_FILE_SIZE} bytes (5MB)."
    try:
        image = Image.open(io.BytesIO(file.getvalue()))
        image.verify()  # Check integrity
        image = Image.open(io.BytesIO(file.getvalue()))
        return image, None
    except Exception as e:
        return None, f"Error processing image: {e}"

# Display general instructions for the user.
st.markdown("## Welcome to Smart KYC Verification")
st.markdown("""
Please follow the steps below to complete your KYC process:
1. **Aadhaar Verification:** Upload your Aadhaar front and back images. Once uploaded, extract and verify the details.
2. **PAN Verification:** Upload your PAN card image and extract the details. Verify the information provided.
3. **Face Verification:** Upload your selfie, and we will match it with your Aadhaar or PAN details.

**Note:** Only valid image files (JPG/JPEG/PNG) up to 5MB are allowed. Follow the instructions and messages displayed on each step.
""")
st.markdown("---")

# Define the order of steps
steps = ["Aadhaar Verification", "PAN Verification", "Face Verification"]

# Initialize session state variables
if "current_step" not in st.session_state:
    st.session_state.current_step = steps[0]  # start at first step

if "aadhaar_data" not in st.session_state:
    st.session_state.aadhaar_data = None
if "pan_data" not in st.session_state:
    st.session_state.pan_data = None
if "face_match_result" not in st.session_state:
    st.session_state.face_match_result = None
if "aadhaar_verified" not in st.session_state:
    st.session_state.aadhaar_verified = False
if "pan_verified" not in st.session_state:
    st.session_state.pan_verified = False
if "selfie_uploaded" not in st.session_state:
    st.session_state.selfie_uploaded = False

# Initialize dynamic keys for file uploaders
if "aadhaar_front_key" not in st.session_state:
    st.session_state.aadhaar_front_key = 0
if "aadhaar_back_key" not in st.session_state:
    st.session_state.aadhaar_back_key = 0
if "pan_card_key" not in st.session_state:
    st.session_state.pan_card_key = 0
if "selfie_key" not in st.session_state:
    st.session_state.selfie_key = 0

# Also, store the uploaded files separately if needed
if "aadhaar_front_file" not in st.session_state:
    st.session_state.aadhaar_front_file = None
if "aadhaar_back_file" not in st.session_state:
    st.session_state.aadhaar_back_file = None
if "pan_card_file" not in st.session_state:
    st.session_state.pan_card_file = None

# Sidebar Navigation with current step pre-selected
st.sidebar.title("Smart KYC Verification")
page = st.sidebar.radio(
    "Select Step",
    steps,
    index=steps.index(st.session_state.current_step),
    disabled=True  # disable manual navigation to enforce flow
)

# Helper: redirect to a given step and rerun
def redirect_to_step(step):
    st.session_state.current_step = step
    st.rerun()

# ===================================
# Step 1: Aadhaar Verification
# ===================================
if st.session_state.current_step == "Aadhaar Verification":
    st.title("Step 1: Aadhaar Verification")
    
    if st.session_state.aadhaar_verified:
        st.success("Aadhaar Verification Completed!")
        with st.expander("Aadhaar Details"):
            st.json(st.session_state.aadhaar_data)
        if st.button("Proceed to PAN Verification"):
            redirect_to_step("PAN Verification")
    else:
        col1, col2 = st.columns(2)
        with col1:
            aadhaar_front_file = st.file_uploader(
                "Upload Aadhaar Front",
                type=ALLOWED_EXTENSIONS,
                key=f"aadhaar_front_{st.session_state.aadhaar_front_key}"
            )
        with col2:
            aadhaar_back_file = st.file_uploader(
                "Upload Aadhaar Back",
                type=ALLOWED_EXTENSIONS,
                key=f"aadhaar_back_{st.session_state.aadhaar_back_key}"
            )
        
        with col1:
            if aadhaar_front_file:
                image_front, error_front = validate_file(aadhaar_front_file)
                if error_front:
                    show_temp_error(f"Aadhaar Front: {error_front}")
                else:
                    st.session_state.aadhaar_front_file = aadhaar_front_file
                    st.image(image_front, caption="Aadhaar Front", width=300)
                
        with col2:
            if aadhaar_back_file:
                image_back, error_back = validate_file(aadhaar_back_file)
                if error_back:
                    show_temp_error(f"Aadhaar Back: {error_back}")
                else:
                    st.session_state.aadhaar_back_file = aadhaar_back_file
                    st.image(image_back, caption="Aadhaar Back", width=300)

        if aadhaar_front_file and aadhaar_back_file and st.session_state.aadhaar_data is None:
            if st.button("Extract Aadhaar Details"):
                with st.spinner("Extracting Aadhaar details..."):
                    try:
                        data = extract_aadhaar_details(aadhaar_front_file, aadhaar_back_file)
                        if "error" in data:
                            show_temp_error(f"Aadhaar OCR Error: {data['error']}")
                        else:
                            st.session_state.aadhaar_data = data
                            st.success("Aadhaar details extracted successfully!")
                    except Exception as e:
                        show_temp_error(f"Failed to process Aadhaar: {e}")
                        
        if st.session_state.aadhaar_data:
            with st.expander("Aadhaar Details"):
                st.json(st.session_state.aadhaar_data)
            col_btn = st.columns([1,7,1.21])
            with col_btn[0]:
                if st.button("Correct"):
                    st.session_state.aadhaar_verified = True
                    st.success("Aadhaar details verified!")
                    redirect_to_step("PAN Verification")
            with col_btn[2]:
                if st.button("Not Correct"):
                    st.session_state.aadhaar_data = None
                    st.session_state.aadhaar_front_file = None
                    st.session_state.aadhaar_back_file = None
                    st.session_state.aadhaar_verified = False
                    st.session_state.aadhaar_front_key += 1
                    st.session_state.aadhaar_back_key += 1
                    st.warning("Aadhaar data cleared. Please re-upload Aadhaar images.")
                    redirect_to_step("Aadhaar Verification")

# ===================================
# Step 2: PAN Verification (Accessible only after Aadhaar Verification)
# ===================================
elif st.session_state.current_step == "PAN Verification":
    if not st.session_state.aadhaar_verified:
        st.warning("Please complete Aadhaar verification first!")
        redirect_to_step("Aadhaar Verification")
        st.stop()

    st.title("Step 2: PAN Verification")
    
    if st.session_state.pan_verified:
        st.success("PAN Verification Completed!")
        with st.expander("PAN Details"):
            st.json(st.session_state.pan_data)
        if st.button("Proceed to Face Verification"):
            redirect_to_step("Face Verification")
    else:
        pan_card_file = st.file_uploader(
            "Upload PAN Card",
            type=ALLOWED_EXTENSIONS,
            key=f"pan_card_{st.session_state.pan_card_key}"
        )
        if pan_card_file:
            image_pan, error_pan = validate_file(pan_card_file)
            if error_pan:
                show_temp_error(f"PAN Card: {error_pan}")
            else:
                st.session_state.pan_card_file = pan_card_file
                st.image(image_pan, caption="PAN Card", width=300)
        if pan_card_file and st.session_state.pan_data is None:
            if st.button("Extract PAN Details"):
                with st.spinner("Extracting PAN details..."):
                    try:
                        data = extract_pan_details(pan_card_file)
                        if "error" in data:
                            show_temp_error(f"PAN OCR Error: {data['error']}")
                        else:
                            st.session_state.pan_data = data
                            st.success("PAN details extracted successfully!")
                    except Exception as e:
                        show_temp_error(f"Failed to process PAN: {e}")
        if st.session_state.pan_data:
            with st.expander("PAN Details"):
                st.json(st.session_state.pan_data)
            col_btn = st.columns([1,7,1.21])
            with col_btn[0]:
                if st.button("Correct"):
                    st.session_state.pan_verified = True
                    st.success("PAN details verified!")
                    redirect_to_step("Face Verification")
            with col_btn[2]:
                if st.button("Not Correct"):
                    st.session_state.pan_data = None
                    st.session_state.pan_card_file = None
                    st.session_state.pan_verified = False
                    st.session_state.pan_card_key += 1
                    st.warning("PAN data cleared. Please re-upload PAN image.")
                    redirect_to_step("PAN Verification")

# ===================================
# Step 3: Face Verification (Accessible only after PAN Verification)
# ===================================
elif st.session_state.current_step == "Face Verification":
    if not st.session_state.pan_verified:
        st.warning("Please complete PAN verification first!")
        redirect_to_step("PAN Verification")
        st.stop()

    st.title("Step 3: Face Verification")
    if st.session_state.face_match_result:
        st.info(st.session_state.face_match_result)
    selfie_file = st.file_uploader(
        "Upload Your Selfie",
        type=ALLOWED_EXTENSIONS,
        key=f"selfie_{st.session_state.selfie_key}"
    )
    if selfie_file:
        image_selfie, error_selfie = validate_file(selfie_file)
        if error_selfie:
            show_temp_error(f"Selfie: {error_selfie}")
        else:
            st.image(image_selfie, caption="Uploaded Selfie", width=300)
            st.session_state.selfie_uploaded = True

    if st.session_state.selfie_uploaded:
        if st.button("Match Faces"):
            if selfie_file and (st.session_state.aadhaar_data or st.session_state.pan_data):
                try:
                    aadhaar_match = match_faces(st.session_state.aadhaar_front_file, selfie_file) if st.session_state.aadhaar_data else False
                    pan_match = match_faces(st.session_state.pan_card_file, selfie_file) if st.session_state.pan_data else False

                    if aadhaar_match or pan_match:
                        st.session_state.face_match_result = "KYC Verified: Face matched successfully!"
                        st.success(st.session_state.face_match_result)
                        st.balloons()
                        st.info("Redirecting to main page in 5 seconds...")
                        # Auto-redirect to main page after 5 seconds using meta refresh
                        st.markdown("<meta http-equiv='refresh' content='5;url=/'/>", unsafe_allow_html=True)
                    else:
                        st.session_state.face_match_result = "KYC Failed: Face does not match. Please re-upload your selfie."
                        show_temp_error(st.session_state.face_match_result)
                        st.session_state.selfie_uploaded = False
                        st.session_state.selfie_key += 1
                        redirect_to_step("Face Verification")
                except Exception as e:
                    show_temp_error(f"Face matching failed: {e}")

st.sidebar.info("The current step is locked. Complete each step to proceed. Previous steps are frozen.")