Sayandip commited on
Commit
357d7d8
·
verified ·
1 Parent(s): 992fc2e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -171
app.py CHANGED
@@ -1,174 +1,150 @@
1
- import os
2
- import base64
3
  import streamlit as st
 
 
 
 
 
4
  from docx import Document
5
- import openpyxl
6
- from pdfminer.high_level import extract_text
7
- import csv
8
  from pptx import Presentation
9
- from io import StringIO
10
- from bs4 import BeautifulSoup
11
- import re
12
- import google.generativeai as genai
13
-
14
- # Setup
15
- st.set_page_config(page_title="Gemini Q&A App", layout="centered")
16
- st.title("🤖 Q&A - Document & Image")
17
-
18
- # Initialize chat history
19
- if "chat_history" not in st.session_state:
20
- st.session_state.chat_history = []
21
-
22
- # Optional: Clear history button
23
- if st.button("🧹 Clear Chat History"):
24
- st.session_state.chat_history = []
25
-
26
- # Load API key
27
- GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY") or st.secrets.get("GOOGLE_API_KEY")
28
- if not GOOGLE_API_KEY:
29
- st.error("GOOGLE_API_KEY not found in environment or Streamlit secrets.")
30
- st.stop()
31
-
32
- genai.configure(api_key=GOOGLE_API_KEY)
33
- model = genai.GenerativeModel(model_name="gemini-2.0-flash")
34
-
35
- # Helper: Extract text from various documents
36
- def load_and_extract_text(file_path):
37
- try:
38
- ext = file_path.split('.')[-1].lower()
39
-
40
- if ext == 'docx':
41
- doc = Document(file_path)
42
- return '\n'.join(p.text for p in doc.paragraphs)
43
-
44
- elif ext == 'xlsx':
45
- workbook = openpyxl.load_workbook(file_path)
46
- return '\n'.join(
47
- ' '.join(str(cell.value) for cell in row if cell.value is not None)
48
- for sheet in workbook for row in sheet.iter_rows()
49
- )
50
-
51
- elif ext == 'pdf':
52
- return extract_text(file_path)
53
-
54
- elif ext == 'csv':
55
- with open(file_path, 'r', encoding='utf-8') as f:
56
- reader = csv.reader(f)
57
- return '\n'.join(' '.join(row) for row in reader)
58
-
59
- elif ext == 'txt':
60
- with open(file_path, 'r', encoding='utf-8') as f:
61
- return f.read()
62
-
63
- elif ext == 'pptx':
64
- prs = Presentation(file_path)
65
- return '\n'.join(
66
- shape.text for slide in prs.slides for shape in slide.shapes if hasattr(shape, 'text')
67
- )
68
-
69
- elif ext == 'tex':
70
- with open(file_path, 'r', encoding='utf-8') as f:
71
- content = f.read()
72
- content = re.sub(r'\\[a-zA-Z]+\*?(?:\[[^\]]*\])?(?:\{[^}]*\})*', '', content)
73
- content = re.sub(r'%.*', '', content)
74
- return content.strip()
75
-
76
- elif ext in ['html', 'htm']:
77
- with open(file_path, 'r', encoding='utf-8') as f:
78
- soup = BeautifulSoup(f, 'html.parser')
79
- for script_or_style in soup(['script', 'style']):
80
- script_or_style.decompose()
81
- return soup.get_text(separator='\n', strip=True)
82
-
83
- else:
84
- return "Unsupported file format."
85
-
86
- except Exception as e:
87
- return f"Error processing file: {e}"
88
-
89
- # Multi-file uploader
90
- uploaded_files = st.file_uploader(
91
- "Upload one or more documents or images",
92
- type=["docx", "xlsx", "pdf", "csv", "txt", "pptx", "tex", "html", "htm", "jpg", "jpeg", "png"],
93
- accept_multiple_files=True
94
- )
95
-
96
- # Question input
97
- question = st.text_input("💬 Enter your question:")
98
-
99
- # Processing
100
- if uploaded_files and question:
101
- combined_context = ""
102
- image_contents = []
103
-
104
- for uploaded_file in uploaded_files:
105
- file_ext = uploaded_file.name.split('.')[-1].lower()
106
-
107
- if file_ext in ['jpg', 'jpeg', 'png']:
108
- image_bytes = uploaded_file.read()
109
- encoded_image = base64.b64encode(image_bytes).decode("utf-8")
110
- image_contents.append({
111
- "inline_data": {
112
- "mime_type": uploaded_file.type,
113
- "data": encoded_image
114
- }
115
- })
116
- st.image(image_bytes, caption=uploaded_file.name, use_container_width=True)
117
- continue
118
-
119
- temp_file_path = "temp." + file_ext
120
- with open(temp_file_path, "wb") as temp_file:
121
- temp_file.write(uploaded_file.read())
122
-
123
- extracted_text = load_and_extract_text(temp_file_path)
124
- os.remove(temp_file_path)
125
-
126
- if "Error" in extracted_text or "Unsupported" in extracted_text:
127
- st.error(f"{uploaded_file.name}: {extracted_text}")
128
- else:
129
- combined_context += f"\n\n---\nDocument: {uploaded_file.name}\n\n{extracted_text}"
130
-
131
- if combined_context.strip() or image_contents:
132
- with st.spinner("Generating answer..."):
133
- try:
134
- content_blocks = []
135
-
136
- # Add prior Q&A as part of the context
137
- if st.session_state.chat_history:
138
- history_text = "\n\n".join(
139
- f"Q: {entry['question']}\nA: {entry['answer']}"
140
- for entry in st.session_state.chat_history
141
- )
142
- content_blocks.append({"text": f"Previous conversation:\n{history_text}"})
143
-
144
- # Add file text content
145
- if combined_context.strip():
146
- content_blocks.append({"text": f"Context:\n{combined_context}"})
147
-
148
- # Add image blocks
149
- content_blocks.extend(image_contents)
150
-
151
- # Add current question
152
- content_blocks.append({"text": f"Question: {question}"})
153
-
154
- response = model.generate_content(contents=content_blocks)
155
- st.success("💡 Answer:")
156
- st.write(response.text)
157
-
158
- # Save to session history
159
- st.session_state.chat_history.append({
160
- "question": question,
161
- "answer": response.text
162
- })
163
-
164
- except Exception as e:
165
- st.error(f"Error generating answer: {e}")
166
- else:
167
- st.warning("No valid documents or images processed.")
168
-
169
- # Optional: Show full conversation history
170
- if st.session_state.chat_history:
171
- st.markdown("### 🗂️ Chat History")
172
- for i, entry in enumerate(st.session_state.chat_history, 1):
173
- st.markdown(f"**Q{i}:** {entry['question']}")
174
- st.markdown(f"**A{i}:** {entry['answer']}")
 
 
 
1
  import streamlit as st
2
+ import os
3
+ import pandas as pd
4
+ import fitz # PyMuPDF
5
+ from google import genai
6
+ from google.genai import types
7
  from docx import Document
 
 
 
8
  from pptx import Presentation
9
+ from reportlab.lib.pagesizes import A4
10
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
11
+ from reportlab.lib.styles import getSampleStyleSheet
12
+
13
+ # Set Gemini API Key
14
+ os.environ["GEMINI_API_KEY"] = "AIzaSyAQLUStrjXv2_zrAjssapa_sYXQWOqVeiE" # Ensure this is set securely in Hugging Face environment
15
+ client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
16
+
17
+ # Function to extract text from different file formats
18
+ def extract_text_from_docx(docx_file):
19
+ document = Document(docx_file)
20
+ return "\n".join([para.text for para in document.paragraphs])
21
+
22
+ def extract_text_from_csv(csv_file):
23
+ df = pd.read_csv(csv_file)
24
+ return df.to_string(index=False)
25
+
26
+ def extract_text_from_xlsx(xlsx_file):
27
+ df = pd.read_excel(xlsx_file)
28
+ return df.to_string(index=False)
29
+
30
+ def extract_text_from_pptx(pptx_file):
31
+ prs = Presentation(pptx_file)
32
+ text_runs = []
33
+ for slide in prs.slides:
34
+ for shape in slide.shapes:
35
+ if hasattr(shape, "text"):
36
+ text_runs.append(shape.text)
37
+ return "\n".join(text_runs)
38
+
39
+ def extract_text_from_pdf(pdf_file):
40
+ doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
41
+ text = ""
42
+ for page in doc:
43
+ text += page.get_text()
44
+ return text
45
+
46
+ def export_conversation_to_pdf(conversation_history):
47
+ pdf_path = "conversation_clean.pdf"
48
+ doc = SimpleDocTemplate(pdf_path, pagesize=A4)
49
+ styles = getSampleStyleSheet()
50
+ elements = []
51
+
52
+ for i, (user_q, gemini_a) in enumerate(conversation_history):
53
+ elements.append(Paragraph(f"<b>Q{i+1}:</b> {user_q}", styles["Normal"]))
54
+ elements.append(Spacer(1, 8))
55
+ elements.append(Paragraph(f"<b>A{i+1}:</b> {gemini_a.replace(chr(10), '<br/>')}", styles["Normal"]))
56
+ elements.append(Spacer(1, 16))
57
+
58
+ doc.build(elements)
59
+ return pdf_path
60
+
61
+ def main():
62
+ st.set_page_config(page_title="Gemini Chat QA", layout="wide")
63
+ st.title("📄 Chat with Your Document using Gemini (Sayandip+Dhiraj+Fazal)")
64
+
65
+ if "conversation" not in st.session_state:
66
+ st.session_state.conversation = []
67
+ if "document_text" not in st.session_state:
68
+ st.session_state.document_text = ""
69
+ if "chat_active" not in st.session_state:
70
+ st.session_state.chat_active = True
71
+
72
+ uploaded_file = st.file_uploader("Upload a file (.txt, .docx, .csv, .xlsx, .pptx, .pdf):",
73
+ type=["txt", "docx", "csv", "xlsx", "pptx", "pdf"])
74
+
75
+ if uploaded_file and not st.session_state.document_text:
76
+ filetype = uploaded_file.name.split(".")[-1].lower()
77
+ try:
78
+ if filetype == "txt":
79
+ st.session_state.document_text = uploaded_file.read().decode("utf-8")
80
+ elif filetype == "docx":
81
+ st.session_state.document_text = extract_text_from_docx(uploaded_file)
82
+ elif filetype == "csv":
83
+ st.session_state.document_text = extract_text_from_csv(uploaded_file)
84
+ elif filetype == "xlsx":
85
+ st.session_state.document_text = extract_text_from_xlsx(uploaded_file)
86
+ elif filetype == "pptx":
87
+ st.session_state.document_text = extract_text_from_pptx(uploaded_file)
88
+ elif filetype == "pdf":
89
+ st.session_state.document_text = extract_text_from_pdf(uploaded_file)
90
+ else:
91
+ st.error("Unsupported file format.")
92
+ except Exception as e:
93
+ st.error(f"Failed to extract text: {e}")
94
+
95
+ if st.session_state.document_text:
96
+ st.markdown("### 💬 Conversation")
97
+ for user_q, gemini_a in st.session_state.conversation:
98
+ st.markdown(f"**You:** {user_q}")
99
+ st.markdown(f"**Gemini:**\\n\\n{gemini_a}")
100
+
101
+ if st.session_state.chat_active:
102
+ with st.form(key="chat_form", clear_on_submit=True):
103
+ user_input = st.text_input("Ask a question about the document (type 'exit' to stop):")
104
+ submit = st.form_submit_button("Send")
105
+
106
+ if submit and user_input:
107
+ if user_input.strip().lower() == "exit":
108
+ st.session_state.chat_active = False
109
+ st.success("Chat ended. Reload to start again.")
110
+ else:
111
+ with st.spinner("Gemini is thinking..."):
112
+ contents = [
113
+ types.Content(
114
+ role="user",
115
+ parts=[
116
+ types.Part.from_text(text=st.session_state.document_text),
117
+ types.Part.from_text(text=user_input),
118
+ types.Part.from_text(text="If needed, search the web for more context.")
119
+ ]
120
+ )
121
+ ]
122
+ tools = [types.Tool(google_search=types.GoogleSearch())]
123
+ generate_config = types.GenerateContentConfig(
124
+ tools=tools,
125
+ response_mime_type="text/plain",
126
+ )
127
+
128
+ response_text = ""
129
+ for chunk in client.models.generate_content_stream(
130
+ model="gemini-2.0-flash",
131
+ contents=contents,
132
+ config=generate_config,
133
+ ):
134
+ response_text += chunk.text
135
+
136
+ st.session_state.conversation.append((user_input, response_text))
137
+ st.rerun()
138
+
139
+ if st.session_state.conversation:
140
+ pdf_path = export_conversation_to_pdf(st.session_state.conversation)
141
+ with open(pdf_path, "rb") as f:
142
+ st.download_button(
143
+ label="📥 Download Cleaned Conversation as PDF",
144
+ data=f,
145
+ file_name="clean_conversation.pdf",
146
+ mime="application/pdf"
147
+ )
148
+
149
+ if __name__ == "__main__":
150
+ main()