File size: 6,102 Bytes
070969f 8a35079 070969f bb234b1 a076cb9 8a35079 070969f 8a35079 8549931 8a35079 1709b38 992fc2e 1709b38 8a35079 070969f 8a35079 070969f bc96f9a 070969f 992fc2e 070969f 8a35079 070969f 8a35079 070969f 8a35079 070969f 8a35079 8b8ce1f 8a35079 070969f a076cb9 8a35079 4d48556 a076cb9 4d48556 070969f 992fc2e fb7c648 a076cb9 070969f 8a35079 43e1234 992fc2e fb7c648 8a35079 43e1234 8a35079 070969f 8a35079 fb7c648 8a35079 fb7c648 992fc2e 1709b38 992fc2e fb7c648 992fc2e fb7c648 992fc2e 813036b b5a4f73 992fc2e fb7c648 1709b38 fb7c648 1709b38 992fc2e 1709b38 992fc2e | 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 | import os
import base64
import streamlit as st
from docx import Document
import openpyxl
from pdfminer.high_level import extract_text
import csv
from pptx import Presentation
from io import StringIO
from bs4 import BeautifulSoup
import re
import google.generativeai as genai
# Setup
st.set_page_config(page_title="Gemini Q&A App", layout="centered")
st.title("🤖 Q&A - Document & Image")
# Initialize chat history
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
# Optional: Clear history button
if st.button("🧹 Clear Chat History"):
st.session_state.chat_history = []
# Load API key
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY") or st.secrets.get("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
st.error("GOOGLE_API_KEY not found in environment or Streamlit secrets.")
st.stop()
genai.configure(api_key=GOOGLE_API_KEY)
model = genai.GenerativeModel(model_name="gemini-2.0-flash")
# Helper: Extract text from various documents
def load_and_extract_text(file_path):
try:
ext = file_path.split('.')[-1].lower()
if ext == 'docx':
doc = Document(file_path)
return '\n'.join(p.text for p in doc.paragraphs)
elif ext == 'xlsx':
workbook = openpyxl.load_workbook(file_path)
return '\n'.join(
' '.join(str(cell.value) for cell in row if cell.value is not None)
for sheet in workbook for row in sheet.iter_rows()
)
elif ext == 'pdf':
return extract_text(file_path)
elif ext == 'csv':
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
return '\n'.join(' '.join(row) for row in reader)
elif ext == 'txt':
with open(file_path, 'r', encoding='utf-8') as f:
return f.read()
elif ext == 'pptx':
prs = Presentation(file_path)
return '\n'.join(
shape.text for slide in prs.slides for shape in slide.shapes if hasattr(shape, 'text')
)
elif ext == 'tex':
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
content = re.sub(r'\\[a-zA-Z]+\*?(?:\[[^\]]*\])?(?:\{[^}]*\})*', '', content)
content = re.sub(r'%.*', '', content)
return content.strip()
elif ext in ['html', 'htm']:
with open(file_path, 'r', encoding='utf-8') as f:
soup = BeautifulSoup(f, 'html.parser')
for script_or_style in soup(['script', 'style']):
script_or_style.decompose()
return soup.get_text(separator='\n', strip=True)
else:
return "Unsupported file format."
except Exception as e:
return f"Error processing file: {e}"
# Multi-file uploader
uploaded_files = st.file_uploader(
"Upload one or more documents or images",
type=["docx", "xlsx", "pdf", "csv", "txt", "pptx", "tex", "html", "htm", "jpg", "jpeg", "png"],
accept_multiple_files=True
)
# Question input
question = st.text_input("💬 Enter your question:")
# Processing
if uploaded_files and question:
combined_context = ""
image_contents = []
for uploaded_file in uploaded_files:
file_ext = uploaded_file.name.split('.')[-1].lower()
if file_ext in ['jpg', 'jpeg', 'png']:
image_bytes = uploaded_file.read()
encoded_image = base64.b64encode(image_bytes).decode("utf-8")
image_contents.append({
"inline_data": {
"mime_type": uploaded_file.type,
"data": encoded_image
}
})
st.image(image_bytes, caption=uploaded_file.name, use_container_width=True)
continue
temp_file_path = "temp." + file_ext
with open(temp_file_path, "wb") as temp_file:
temp_file.write(uploaded_file.read())
extracted_text = load_and_extract_text(temp_file_path)
os.remove(temp_file_path)
if "Error" in extracted_text or "Unsupported" in extracted_text:
st.error(f"{uploaded_file.name}: {extracted_text}")
else:
combined_context += f"\n\n---\nDocument: {uploaded_file.name}\n\n{extracted_text}"
if combined_context.strip() or image_contents:
with st.spinner("Generating answer..."):
try:
content_blocks = []
# Add prior Q&A as part of the context
if st.session_state.chat_history:
history_text = "\n\n".join(
f"Q: {entry['question']}\nA: {entry['answer']}"
for entry in st.session_state.chat_history
)
content_blocks.append({"text": f"Previous conversation:\n{history_text}"})
# Add file text content
if combined_context.strip():
content_blocks.append({"text": f"Context:\n{combined_context}"})
# Add image blocks
content_blocks.extend(image_contents)
# Add current question
content_blocks.append({"text": f"Question: {question}"})
response = model.generate_content(contents=content_blocks)
st.success("💡 Answer:")
st.write(response.text)
# Save to session history
st.session_state.chat_history.append({
"question": question,
"answer": response.text
})
except Exception as e:
st.error(f"Error generating answer: {e}")
else:
st.warning("No valid documents or images processed.")
# Optional: Show full conversation history
if st.session_state.chat_history:
st.markdown("### 🗂️ Chat History")
for i, entry in enumerate(st.session_state.chat_history, 1):
st.markdown(f"**Q{i}:** {entry['question']}")
st.markdown(f"**A{i}:** {entry['answer']}") |