open-notebook/stream_app/source.py
2024-10-21 14:56:10 -03:00

161 lines
5.1 KiB
Python

from pathlib import Path
import streamlit as st
import streamlit_scrollable_textbox as stx # type: ignore
from humanize import naturaltime
from loguru import logger
from streamlit_tags import st_tags # type: ignore
from open_notebook.domain import Asset, Source
from open_notebook.graphs.content_process import graph
from open_notebook.utils import token_cost, token_count
from .consts import context_icons
uploads_dir = Path("./.uploads")
uploads_dir.mkdir(parents=True, exist_ok=True)
@st.dialog("Source", width="large")
def source_panel(source_id):
source: Source = Source.get(source_id)
if not source:
st.error("Source not found")
return
title = st.empty()
if source.title:
title.subheader(source.title)
st.caption(f"Created {naturaltime(source.created)}")
# st.markdown(f"**URL:** {source.url}, **File:** {source.file_path}")
summary = st.empty()
for insight in source.insights:
summary.write(insight.insight_type)
summary.write(insight.content)
topics = source.topics or []
if len(topics) > 0:
st_tags(
label="",
text="Press enter to add more",
value=source.topics,
suggestions=source.topics,
maxtags=10,
key="1",
)
if st.button("Delete", icon="🗑️"):
source.delete()
st.rerun()
cost = token_cost(token_count(source.full_text)) * 1.2
if st.button(f"Summarize (about ${cost:.4f})", icon="📝"):
source.summarize()
st.rerun(scope="fragment")
cost_embedding = token_cost(token_count(source.full_text), 0.02)
if st.button(f"Embed (${cost_embedding:.4f})", icon="📝"):
source.vectorize()
st.success("Embedding complete")
st.subheader("Content")
stx.scrollableTextbox(source.full_text, height=300)
@st.dialog("Add a Source", width="large")
def add_source(session_id):
source_link = None
source_file = None
source_text = None
source_type = st.radio("Type", ["Link", "Upload", "Text"])
req = {}
if source_type == "Link":
source_link = st.text_input("Link")
req["url"] = source_link
elif source_type == "Upload":
source_file = st.file_uploader("Upload")
if source_file is not None:
# Get the file name and extension
file_name = source_file.name
file_extension = Path(file_name).suffix
# Generate a unique file name
base_name = Path(file_name).stem
counter = 1
new_path = uploads_dir / file_name
while new_path.exists():
new_file_name = f"{base_name}_{counter}{file_extension}"
new_path = uploads_dir / new_file_name
counter += 1
req["file_path"] = str(new_path)
# Save the file
with open(new_path, "wb") as f:
f.write(source_file.getbuffer())
else:
source_text = st.text_area("Text")
req["content"] = source_text
if st.button("Process", key="add_source"):
logger.debug("Adding source")
with st.status("Processing...", expanded=True):
st.write("Processing document...")
result = graph.invoke(req)
st.write("Saving..")
source = Source(
asset=Asset(url=req.get("url"), file_path=req.get("file_path")),
)
source.save()
source.save_chunks(result["content"])
source.add_to_notebook(st.session_state[session_id]["notebook"].id)
st.write("Summarizing...")
source.summarize()
st.rerun()
# else:
# st.stop()
def source_card(session_id, source):
icon = "🔗"
context_state = st.selectbox(
"Context",
label_visibility="collapsed",
options=context_icons,
index=0,
key=f"source_{source.id}",
)
with st.expander(f"**{source.title}**"):
st.markdown(f"{icon} Updated: {naturaltime(source.updated)}")
st.markdown("**" + ", ".join(source.topics) + "**")
for insight in source.insights:
st.write(insight.insight_type)
st.write(insight.content)
with st.popover("Actions"):
if st.button("Edit Source", icon="📝", key=source.id):
result = source_panel(source.id)
st.write(result)
if st.button("Delete", icon="🗑️", key=f"delete_options_{source.id}"):
source.delete()
st.rerun()
st.session_state[session_id]["context_config"][source.id] = context_state
def source_list_item(source_id, score=None):
source: Source = Source.get(source_id)
if not source:
st.error("Source not found")
return
icon = "🔗"
with st.expander(
f"{icon} [{score:.2f}] **{source.title}** {naturaltime(source.updated)}"
):
for insight in source.insights:
st.markdown(f"**{insight.insight_type}**")
st.write(insight.content)
if st.button("Edit source", icon="📝", key=f"x_edit_source_{source.id}"):
source_panel(source_id=source.id)