File size: 7,913 Bytes
9e71d08
 
 
 
eef4067
e73f742
48fbaef
e73f742
 
 
 
 
 
 
 
 
 
 
 
9e71d08
22c5be7
 
 
 
 
 
 
 
 
 
 
 
49420ef
9e71d08
 
22c5be7
 
9e71d08
22c5be7
cd68e25
 
 
 
 
18f6ecd
f93e87a
9e71d08
22c5be7
49420ef
ca26e93
49420ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e71d08
49420ef
22c5be7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e71d08
22c5be7
 
9e71d08
22c5be7
461bb9b
9e71d08
d681a96
 
 
22c5be7
9e71d08
 
 
 
 
22c5be7
 
 
 
 
 
 
 
 
 
 
 
42332dc
 
 
 
 
4100b29
42332dc
 
f4e1edf
42332dc
 
 
 
 
 
 
 
 
 
 
995d63d
42332dc
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
import streamlit as st
from pypdf import PdfReader
import os
from gemini_call import GeminiQanA
from docx import Document
from pathlib import Path
from extract_text import extract_text_pypdf

def load_css(file_name):
    """Loads a CSS file and injects it into the Streamlit app."""
    try:
        css_path = Path(__file__).parent / file_name
        with open(css_path) as f:
            st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
        # st.info(f"Loaded CSS: {file_name}") # Optional: uncomment for debugging
    except FileNotFoundError:
        st.error(f"CSS file not found: {file_name}. Make sure it's in the same directory as app.py.")
    except Exception as e:
        st.error(f"Error loading CSS file {file_name}: {e}")

from extract_text import extract_text_pypdf

@st.cache_resource()
def load_resources():
    text_from_pdf: str = ""
    file_name = 'CFR-2019-title21-vol2.pdf'
    
    text_from_pdf = extract_text_pypdf(file_name)
    
    with st.spinner("Reading document..."):
        chatbot = GeminiQanA(text_from_pdf)
        
    return chatbot , file_name

if __name__ == "__main__":
    # Setup env variables
    os.environ['GOOGLE_API_KEY'] = st.secrets['GOOGLE_API_KEY']
    st.set_page_config(page_title=None, page_icon=None, layout="centered", initial_sidebar_state="expanded", menu_items=None)
    
    st.markdown("""
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
""", unsafe_allow_html=True)
    load_css("style.css")
    st.markdown("<br></br>",unsafe_allow_html=True)
    # Streamlit UI
    st.title("📄 FDA Question Answering Demo")
    
    st.write('''This demo showcases an AI-powered system designed to interpret and answer questions based on Title 21 of the Code of Federal Regulations, Part 1 (21 CFR 1). These regulations, governed by the U.S. Food and Drug Administration (FDA), cover general enforcement provisions related to food, drugs, and cosmetics. The system enables users to navigate complex regulatory text efficiently, providing accurate, context-aware answers to compliance and procedural queries.''')
    # Display logo
    st.sidebar.write('Click the button bellow to download the sample document')
    # Load the chatbot resources AND get the PDF path
    chatbot, pdf_file_path_for_download = load_resources()

    # --- Add PDF Download Button to Sidebar ---
    if os.path.exists(pdf_file_path_for_download):
        try:
            with open(pdf_file_path_for_download, "rb") as pdf_file:
                pdf_bytes = pdf_file.read()
            
            st.sidebar.download_button(
                label="Download Full PDF Document",
                data=pdf_bytes,
                file_name=os.path.basename(pdf_file_path_for_download), # Use basename to get just the filename
                mime="application/pdf",
                key='pdf_download' # Optional: add a key
            )
        except Exception as e:
            st.sidebar.error(f"Error reading PDF for download: {e}")
    else:
        # This case should ideally be caught by load_resources, but added as a safeguard
        st.sidebar.warning(f"PDF file '{pdf_file_path_for_download}' not found for download.")

    st.sidebar.markdown("---") # Add another separator

    # Sample questions for the combobox
    sample_questions = [
        "How is \"slack-fill\" defined, and what are the exceptions to considering it misbranding?",
        "What is the difference between the principal display panel and the information panel on a food package?",
        "What criteria determine the minimum type size for information on a food label? Are there any exemptions?",
        "Under what circumstances is a food considered an \"imitation\" and what labeling requirements apply?",
        "How must ingredients be listed on a food label? What exceptions are there to the descending order of predominance rule?",
        "What are the requirements for declaring the net quantity of contents on a food label? What are some examples?",
        "How are the terms \"fresh,\" \"freshly frozen,\" \"fresh frozen,\" and \"frozen fresh\" defined for food labeling purposes?",
        "What exemptions exist for certain foods from the nutrition labeling requirements?",
        "What are the requirements for calorie labeling of foods sold in vending machines?",
        "What specific labeling requirements apply to spices, flavorings, colorings, and chemical preservatives?",
        "What is the required statement regarding iodine content for salt?",
        "How is the percentage juice declaration determined for beverages containing fruit or vegetable juice?",
        "What are the specific labeling requirements for dietary supplements?",
        "What are the guidelines for voluntary nutrition labeling of raw fruits, vegetables, and fish?",
        "What are the requirements for making nutrient content claims such as \"good source\", \"high\", and \"light\"?",
        "What are the general requirements for making health claims on food labels?",
        "What are the specific health claims authorized for calcium, vitamin D, and osteoporosis?",
        "What are the specific health claims related to soluble fiber and coronary heart disease?",
        "Under what conditions can the terms \"gluten-free,\" \"no gluten,\" \"free of gluten,\" and \"without gluten\" be used on food labels?",
        "What is the process for a state or locality to petition for exemption from federal preemption of their food labeling requirements?",
        "How can states enforce federal food regulations?"
    ]

    # Sidebar combobox to select a sample question
    selected_question = st.sidebar.selectbox("Select a sample question:", sample_questions)

    # Autofill the selected question into the text input
    question = st.text_input("**Ask a question about the document:**", value=selected_question)

    if "messages" not in st.session_state:
        st.session_state.messages = []
        
    # Handle user question and AI response
    if st.button("Ask AI") and question:
        st.session_state.messages.append({"role": "user", "content": question})
        with st.spinner("Fetching response from assistant..."):
            answer = chatbot.answer_question(question)
        st.session_state.messages.append({"role": "assistant", "content": answer})

    # Display previous messages in descending order
    for i in range(len(st.session_state.messages)-1, -1, -2):  # Start from the latest message and step by -2
        # Display assistant message (if available)
        if i-1 >= 0 and st.session_state.messages[i-1]["role"] == "user":
            with st.chat_message("user"):
                st.markdown(st.session_state.messages[i-1]["content"])
                
        if i >= 0 and st.session_state.messages[i]["role"] == "assistant":
            with st.chat_message("assistant"):
                st.markdown(st.session_state.messages[i]["content"])

import streamlit.components.v1 as components
components.html(
    """
    <script>
      function sendHeightWhenReady() {
        const el = window.parent.document.getElementsByClassName('stMain')[0];
        if (el) {
          const height = el.scrollHeight;
          console.log("Sending height to parent:", height);
          window.parent.parent.postMessage({ type: 'setHeight', height: height }, '*');
        } else {
          // Retry in 100ms until the element appears
          setTimeout(sendHeightWhenReady, 1000);
        }
      }

      window.onload = sendHeightWhenReady;
      window.addEventListener('resize', sendHeightWhenReady);
      setInterval(sendHeightWhenReady, 1000);
    </script>
    """,height=0
)