File size: 7,405 Bytes
7b76e52
 
 
 
 
 
 
 
332b35d
 
6cb3b07
31b039e
7b76e52
c6b7e23
7b76e52
332b35d
 
7b76e52
332b35d
 
 
7b76e52
c6b7e23
7b76e52
c6b7e23
332b35d
7b76e52
332b35d
 
7b76e52
332b35d
 
 
 
 
 
 
c6b7e23
332b35d
 
c6b7e23
 
332b35d
 
 
 
 
 
 
c6b7e23
 
 
7b76e52
332b35d
7b76e52
 
 
332b35d
 
c6b7e23
332b35d
 
c6b7e23
 
 
 
 
 
752af65
7b76e52
 
332b35d
 
 
 
7b76e52
332b35d
 
 
 
 
c6b7e23
332b35d
 
c6b7e23
 
332b35d
 
 
c6b7e23
 
 
332b35d
 
 
7b76e52
332b35d
7b76e52
 
332b35d
 
c6b7e23
 
332b35d
 
c6b7e23
7b76e52
 
c6b7e23
 
7b76e52
 
 
c6b7e23
 
 
 
 
 
 
 
 
 
 
 
 
 
7b76e52
 
c6b7e23
 
 
 
 
 
 
 
 
7b76e52
c6b7e23
 
61d4d78
7b76e52
 
 
 
 
 
 
c6b7e23
7b76e52
 
c6b7e23
7b76e52
 
 
 
332b35d
7b76e52
 
 
 
c6b7e23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332b35d
61d4d78
c6b7e23
 
 
 
 
 
 
 
 
 
 
 
 
7b76e52
 
752af65
61d4d78
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
import streamlit as st
import base64
import requests
from PIL import Image, ImageDraw
from io import BytesIO
import fitz  # PyMuPDF
import time

# Configuration - Get API key from Streamlit secrets
GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"]
GEMINI_MODEL = "gemini-2.0-flash"
DOCUMENT_TYPES = ["Land Records", "Caste Certificates", "Property Registrations", "Others"]

# Initialize session state (excluding widget-controlled keys)
def initialize_session_state():
    if "chat_history" not in st.session_state:
        st.session_state["chat_history"] = []
    if "processed_doc" not in st.session_state:
        st.session_state["processed_doc"] = None
    if "doc_preview" not in st.session_state:
        st.session_state["doc_preview"] = None

# Reset session state (excluding widget-controlled keys)
def reset_session_state():
    for key in ["chat_history", "processed_doc", "doc_preview"]:
        st.session_state.pop(key, None)

# Encode uploaded file to base64
def encode_file(uploaded_file):
    try:
        file_bytes = uploaded_file.getvalue()
        
        if uploaded_file.type == "application/pdf":
            pdf = fitz.open(stream=BytesIO(file_bytes))
            page = pdf[0]
            pix = page.get_pixmap()
            img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
        elif uploaded_file.type.startswith("image/"):
            img = Image.open(BytesIO(file_bytes))
        elif uploaded_file.type == "text/plain":
            text = file_bytes.decode("utf-8")
            img = Image.new("RGB", (800, 600), color=(73, 109, 137))
            d = ImageDraw.Draw(img)
            d.text((10, 10), text, fill=(255, 255, 0))
        else:
            st.error("Unsupported file format")
            return None

        img_byte_arr = BytesIO()
        img.save(img_byte_arr, format="JPEG")
        return base64.b64encode(img_byte_arr.getvalue()).decode("utf-8")
    
    except Exception as e:
        st.error(f"File processing error: {str(e)}")
        return None

# Query Gemini API
def query_gemini(prompt, image_b64=None):
    url = f"https://generativelanguage.googleapis.com/v1/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}"
    
    parts = [{"text": prompt}]
    if image_b64:
        parts.append({
            "inline_data": {
                "mime_type": "image/jpeg",
                "data": image_b64
            }
        })
    
    try:
        response = requests.post(
            url,
            json={"contents": [{"parts": parts}]},
            headers={"Content-Type": "application/json"},
            timeout=30
        )
        if response.status_code != 200:
            st.error(f"API Request failed with status code: {response.status_code}")
            return None
        
        data = response.json()
        if "error" in data:
            st.error(f"API Error: {data['error'].get('message', 'Unknown error')}")
            return None
            
        if not data.get("candidates"):
            st.error("No response candidates found in API response")
            return None
            
        candidate = data["candidates"][0]
        return candidate.get("content", {}).get("parts", [{}])[0].get("text", "No response text found")
    
    except requests.exceptions.RequestException as e:
        st.error(f"API Request failed: {str(e)}")
        return None
    except Exception as e:
        st.error(f"Unexpected error: {str(e)}")
        return None

# Process the uploaded document
def process_document():
    uploaded_file = st.session_state.get("uploaded_file")
    if not uploaded_file:
        st.error("Please upload a document first.")
        return
    
    try:
        with st.spinner("Analyzing document..."):
            # Encode file to base64
            image_b64 = encode_file(uploaded_file)
            if not image_b64:
                return

            # Store preview image
            if uploaded_file.type == "application/pdf":
                pdf = fitz.open(stream=BytesIO(uploaded_file.getvalue()))
                page = pdf[0]
                pix = page.get_pixmap()
                st.session_state.doc_preview = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
            else:
                st.session_state.doc_preview = Image.open(uploaded_file)

            # Classify document
            classify_prompt = (
                f"Classify this document into one of these categories: {', '.join(DOCUMENT_TYPES)}. "
                "Respond only with the category name."
            )
            doc_type = query_gemini(classify_prompt, image_b64)
            
            # Extract details
            extract_prompt = (
                "Extract key details including:\n"
                "- Names\n"
                "- Dates\n"
                "- Identification numbers\n"
                "- Locations\n"
                "Format as a bullet-point list."
            )
            details = query_gemini(extract_prompt, image_b64)

            # Verify authenticity
            verify_prompt = "Analyze this document for signs of tampering. Provide verification status in short(2 Lines)."
            verification = query_gemini(verify_prompt, image_b64)

            st.session_state.processed_doc = {
                "type": doc_type or "Unclassified",
                "details": details or "No details extracted",
                "verification": verification or "Verification failed",
            }

            st.success("Document processing complete!")
            time.sleep(1)
    
    except Exception as e:
        st.error(f"Document processing failed: {str(e)}")
        st.session_state.processed_doc = None

# Main app function
def main():
    st.set_page_config(page_title="DocVerify AI", layout="wide")
    initialize_session_state()
    
    # Sidebar Controls
    with st.sidebar:
        st.header("Document Controls")
        # The file uploader widget manages its own state with key "uploaded_file"
        st.file_uploader(
            "Upload Document",
            type=["pdf", "jpg", "jpeg", "png", "txt"],
            key="uploaded_file",
            on_change=process_document,
            help="Supported formats: PDF, JPG, PNG, TXT"
        )
        
        if st.button("New Document"):
            reset_session_state()
            st.experimental_rerun()
        
        if st.session_state.get("processed_doc"):
            st.divider()
            st.subheader("Document Summary")
            st.markdown(f"**Type:** {st.session_state.processed_doc['type']}")
            st.markdown(f"**Verification Status:** {st.session_state.processed_doc['verification']}")

    # Main Interface
    st.title("📄 Automated Document Verifier")
    
    if st.session_state.get("processed_doc") and st.session_state.get("doc_preview"):
        col1, col2 = st.columns([1, 2])
        with col1:
            st.subheader("Document Preview")
            st.image(st.session_state.doc_preview, use_column_width=True)
        
        with col2:
            st.subheader("Extracted Details")
            st.markdown(st.session_state.processed_doc["details"])
            
            st.subheader("Verification Analysis")
            st.markdown(st.session_state.processed_doc["verification"])
    else:
        st.info("Please upload a document to begin verification analysis")

if __name__ == "__main__":
    main()