hackathon / src /streamlit_app.py
thieuluan's picture
init first spec
191645f
Raw
History Blame Contribute Delete
3.36 kB
import streamlit as st
import os
import tempfile
from uuid import uuid4
from concurrent.futures import ThreadPoolExecutor, Future
from ingestion import ingest_pdf
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv(), override=False)
st.set_page_config(page_title="PDF Ingestion", layout="wide")
if "session_id" not in st.session_state:
st.session_state.session_id = str(uuid4())
if "ingestion_future" not in st.session_state:
st.session_state.ingestion_future = None
if "last_output" not in st.session_state:
st.session_state.last_output = None
st.title("Ingestion Layer")
st.caption("Upload a PDF to extract, normalize, chunk, and persist for later embedding.")
with st.sidebar:
st.header("Settings")
parser = st.selectbox("Parser", ["pypdf", "pdfplumber"], index=0)
chunk_size = st.number_input("Chunk size (chars)", min_value=500, max_value=10000, value=4000, step=100)
overlap = st.number_input("Overlap (chars)", min_value=0, max_value=2000, value=400, step=50)
uploaded = st.file_uploader("Upload PDF", type=["pdf"])
def _run_ingestion(tmp_path: str, sid: str, parser: str, chunk_size: int, overlap: int):
return ingest_pdf(tmp_path, sid, parser=parser, chunk_size=chunk_size, overlap=overlap)
col1, col2 = st.columns([2, 1])
with col1:
if uploaded is not None and st.button("Start Ingestion", type="primary"):
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
tmp.write(uploaded.read())
tmp_path = tmp.name
executor = ThreadPoolExecutor(max_workers=1)
future: Future = executor.submit(_run_ingestion, tmp_path, st.session_state.session_id, parser, int(chunk_size), int(overlap))
st.session_state.ingestion_future = future
st.info("Ingestion started. Processing in background...")
future: Future = st.session_state.ingestion_future
if future is not None:
if future.done():
try:
chunks, out_path = future.result()
st.session_state.last_output = (len(chunks), out_path)
st.success(f"Ingestion complete: {len(chunks)} chunks written to {out_path}")
if chunks:
st.subheader("Preview (first chunk)")
st.code(chunks[0].content[:2000])
except Exception as e:
st.error(f"Ingestion failed: {e}")
finally:
st.session_state.ingestion_future = None
else:
st.status("Processing...", state="running")
with col2:
st.subheader("Session")
st.code(st.session_state.session_id)
if st.session_state.last_output:
cnt, path = st.session_state.last_output
st.metric("Chunks", cnt)
st.write("Output:")
st.code(path)
if uploaded is not None and st.button("Retry with fallback parser"):
fb = "pdfplumber" if parser == "pypdf" else "pypdf"
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
tmp.write(uploaded.read())
tmp_path = tmp.name
executor = ThreadPoolExecutor(max_workers=1)
future: Future = executor.submit(_run_ingestion, tmp_path, st.session_state.session_id, fb, int(chunk_size), int(overlap))
st.session_state.ingestion_future = future
st.info(f"Retrying with {fb}...")