File size: 8,314 Bytes
d117f2c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
from streamlit_webrtc import webrtc_streamer, VideoProcessorBase, RTCConfiguration
import av
import cv2
from pyzbar import pyzbar
import google.generativeai as genai
from google.generativeai import protos
import threading
import time
import json
import re
from google import genai
from google.genai import types
# ----------------------------
# App Configuration
# ----------------------------
st.set_page_config(
    page_title="Real-Time Drug Code Verifier",
    page_icon="πŸ”",
    layout="wide"
)

# ----------------------------
# API Key Setup
# ----------------------------
# It's recommended to use st.secrets for API keys in a deployed app
GOOGLE_API_KEY = "AIzaSyAXFL0YdFIKUNISOQuV9FH-JTSnMC3PSMA" 

# Load key from secrets
try:
    if not GOOGLE_API_KEY:
        GOOGLE_API_KEY = st.secrets["GOOGLE_API_KEY"]
except (FileNotFoundError, KeyError):
    st.error("πŸ”‘ GOOGLE_API_KEY not found. Please add it to your Streamlit secrets.")
    st.stop()

#.configure(api_key=GOOGLE_API_KEY)
client = genai.Client(api_key=GOOGLE_API_KEY)
# Define the grounding tool
grounding_tool = types.Tool(
    google_search=types.GoogleSearch()
)

# Configure generation settings
config = types.GenerateContentConfig(
    tools=[grounding_tool]
)


# ----------------------------
# Main Gemini Verification Function
# ----------------------------
@st.cache_data(show_spinner=False)
def verify_code_with_gemini(code: str, barcode_type: str):
    """
    Verifies a product code by letting Gemini use its native Google Search tool.
    """
    # Define the built-in Google Search tool using the specific syntax required by the library
 
    
    prompt = f"""
    You are a product verification assistant. A user has scanned a product with the code '{code}' (type: {barcode_type}).
    Your goal is to use your built-in Google Search tool to augment your own knowledge and provide a comprehensive analysis.

    Follow these steps:
    1. Use your search tool to find information about the provided barcode and product type. This will give you real-time context.
    2. Combine the information from the web search with your own general knowledge about products, manufacturers, and barcode standards.
    3. Provide a detailed summary. This should include the likely product name, manufacturer, and a well-reasoned assessment of the code's authenticity. If the search results are inconclusive or suspicious, use your own knowledge to explain why (e.g., "This barcode format is unusual for this type of product," or "No major retailers list this code, which is suspicious.").
    4. From the search results, find the best, most representative image URL for the product. If no good image is found, return an empty string.
    5. IMPORTANT: Your final output MUST be ONLY the raw JSON object. Do not include ```json``` markers or any other explanatory text.

    Example Output:
    {{
      "summary_text": "This EAN-13 code corresponds to 'Product Name' by 'Manufacturer'. The code format is valid and listed by several major retailers in the search results, suggesting it is authentic. No recalls or warnings were found.",
      "image_url": "https://example.com/product_image.jpg"
    }}
    """
    response = None # Initialize response to None
    try:
        st.write("🧠 Generating content with Gemini and Google Search...")
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=prompt,
            config=config,
        )        
        st.write("βœ… Gemini response received. Parsing JSON...")
        # Extract JSON from the response text, which might be wrapped in markdown
        raw_text = response.text
        json_match = re.search(r'\{.*\}', raw_text, re.DOTALL)
        
        if json_match:
            json_str = json_match.group(0)
            result_data = json.loads(json_str)
            st.write("πŸ‘ JSON parsed successfully!")
            return result_data
        else:
            st.write("❌ No JSON object found in the response.")
            return {
                "summary_text": "Verification failed: The AI did not return a valid JSON object.",
                "image_url": "",
                "raw_response": raw_text
            }

    except Exception as e:
        st.write(f"❌ An error occurred: {e}")
        raw_response_text = response.text if response else "No response from model."
        return {
            "summary_text": f"An error occurred during verification. Please check the details below.",
            "image_url": "",
            "error_details": str(e),
            "raw_response": raw_response_text
        }

# ----------------------------
# Video Processing Class
# ----------------------------
class QRCodeScanner(VideoProcessorBase):
    def __init__(self):
        self.result = None
        self.lock = threading.Lock()

    def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
        image = frame.to_ndarray(format="bgr24")
        decoded_objects = pyzbar.decode(image)

        for obj in decoded_objects:
            code_data = obj.data.decode("utf-8")
            code_type = obj.type
            
            with self.lock:
                self.result = {"data": code_data, "type": code_type}
            
            (x, y, w, h) = obj.rect
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
            text = f"Detected: {code_data}"
            cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
            break

        return av.VideoFrame.from_ndarray(image, format="bgr24")

# ----------------------------
# Streamlit UI
# ----------------------------
st.title("πŸ” Real-Time Drug Code Verifier with AI Search")
st.markdown("Point a product's barcode or QR code at the camera. The app will use Gemini AI with Google Search to verify its authenticity.")

if "code_found" not in st.session_state:
    st.session_state.update({"code_found": False, "last_code_data": "", "last_code_type": ""})

if not st.session_state["code_found"]:
    st.subheader("πŸ“· Camera Feed")
    webrtc_ctx = webrtc_streamer(
        key="scanner",
        video_processor_factory=QRCodeScanner,
        rtc_configuration=RTCConfiguration({"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]}),
        media_stream_constraints={"video": True, "audio": False},
        async_processing=True,
    )
    st.info("The camera will stop automatically once a code is detected.")

    if webrtc_ctx.video_processor:
        while True:
            with webrtc_ctx.video_processor.lock:
                result = webrtc_ctx.video_processor.result
            if result:
                st.session_state.update(code_found=True, last_code_data=result["data"], last_code_type=result["type"])
                st.rerun()
            time.sleep(0.2)
else:
    st.success("βœ… Code captured successfully! The camera has been turned off.")
    
    col1, col2 = st.columns([1, 2])

    with col1:
        st.subheader("πŸ“¦ Detected Code")
        st.code(f"Data: {st.session_state['last_code_data']}\nType: {st.session_state['last_code_type']}", language="text")

        if st.button("πŸ”„ Scan Another Product"):
            st.session_state.update({"code_found": False, "last_code_data": "", "last_code_type": ""})
            st.rerun()

    with col2:
        st.subheader("πŸ€– Gemini AI Verification")
        with st.spinner("πŸ” Using Gemini with Google Search to verify..."):
            verification_result = verify_code_with_gemini(
                st.session_state['last_code_data'],
                st.session_state['last_code_type']
            )
            
        # Display the summary text
        st.info(verification_result.get("summary_text", "No summary available."))
        
        # Display the image if a URL was found
        image_url = verification_result.get("image_url")
        if image_url:
            st.image(image_url, caption="Product Image (from web search)")
        
        # Display error details if they exist
        if "error_details" in verification_result:
            st.error("An error occurred during verification:")
            st.code(f"Error: {verification_result['error_details']}\n\nRaw AI Response:\n{verification_result['raw_response']}", language="text")