|
import re |
|
import html |
|
import uuid |
|
import urllib |
|
|
|
import streamlit as st |
|
|
|
from notebook_helpers import * |
|
from text_utils import * |
|
|
|
import config |
|
|
|
|
|
st.set_page_config(layout="wide") |
|
|
|
|
|
|
|
|
|
|
|
html_content = """ |
|
<style> |
|
.tooltip { |
|
position: relative; |
|
display: inline-block; |
|
cursor: pointer; |
|
} |
|
|
|
.tooltip .tooltiptext { |
|
font-weight: normal; |
|
visibility: hidden; |
|
width: 320px; |
|
background-color: #eadef9; |
|
color: black; |
|
text-align: left; |
|
border-radius: 6px; |
|
padding: 0.6em; |
|
position: absolute; |
|
z-index: 1; |
|
top: 100%; |
|
left: 50%; |
|
margin-left: -60px; |
|
opacity: 20%; |
|
transition: opacity 0.3s; |
|
} |
|
|
|
.tooltip:hover .tooltiptext { |
|
visibility: visible; |
|
opacity: 1; |
|
} |
|
</style> |
|
""" |
|
st.markdown(html_content, unsafe_allow_html=True) |
|
|
|
def javascript(source: str) -> None: |
|
div_id = uuid.uuid4() |
|
|
|
st.markdown(f""" |
|
<div style="display:none" id="{div_id}"> |
|
<iframe src="javascript: \ |
|
var script = document.createElement('script'); \ |
|
script.type = 'text/javascript'; \ |
|
script.text = {html.escape(repr(source))}; \ |
|
var div = window.parent.document.getElementById('{div_id}'); \ |
|
div.appendChild(script); \ |
|
div.parentElement.parentElement.parentElement.style.display = 'none'; \ |
|
"/> |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
|
|
|
if "urls_input" not in st.session_state: |
|
st.session_state["urls_input"] = normalize_text(default_urls_input) |
|
|
|
tab1, tab2, tab3 = st.tabs([ |
|
"Danh sách các liên kết", |
|
"Chỉnh sửa danh sách các liên kết", |
|
"Tổng hợp, tương tác với tất cả nội dung" |
|
]) |
|
|
|
|
|
with tab3: |
|
if "prompt" not in st.session_state: |
|
st.session_state["prompt"] = "Tóm tắt ngắn gọn 10 chính ý từ các văn bản được cung cấp, mỗi ý chính một gạch đầu dòng." |
|
|
|
if not got_all_urls(st.session_state["urls_input"]): |
|
st.write("Bạn phải duyệt từng liên kết để lấy và kiểm tra nội dung trước khi xem bản tổng hợp này.") |
|
|
|
else: |
|
prompt = st.text_area( |
|
f"Yêu cầu của bạn", |
|
value = st.session_state["prompt"], |
|
height = 6, |
|
key = f"DocChat" |
|
) |
|
|
|
if st.button("Tạo nội dung tổng hợp"): |
|
st.session_state["prompt"] = prompt |
|
print(">>> prompt", st.session_state["prompt"]) |
|
st.session_state["response"] = docchat(st.session_state["urls_input"], st.session_state["prompt"]) |
|
st.rerun() |
|
|
|
if "response" in st.session_state: |
|
st.write(st.session_state["response"]) |
|
|
|
|
|
with tab2: |
|
edited_urls_input = st.text_area( |
|
"Thêm hoặc bớt các liên kết", |
|
value=st.session_state["urls_input"], |
|
height=500, |
|
key=f"edit_urls_input" |
|
) |
|
|
|
if st.button("Cập nhật thay đổi"): |
|
st.session_state["urls_input"] = normalize_text(edited_urls_input) |
|
st.session_state['selected_url'] = None |
|
st.success("Đã lưu thay đổi!") |
|
st.rerun() |
|
|
|
|
|
with tab1: |
|
|
|
col1, col2 = st.columns([3, 6]) |
|
|
|
urls = get_urls(st.session_state["urls_input"]) |
|
|
|
|
|
with col1: |
|
|
|
|
|
for idx, url in enumerate(urls): |
|
url_preview = url[:50] + "..." |
|
if st.button(url_preview, key = idx): |
|
st.session_state['selected_url'] = url |
|
|
|
|
|
|
|
with col2: |
|
|
|
if 'selected_url' not in st.session_state or st.session_state["selected_url"] is None: |
|
"Nhấn vào url để hiển thị nội dung" |
|
|
|
else: |
|
selected_url = st.session_state['selected_url'] |
|
fresh_text = url_content(selected_url) |
|
_, chunks = add_chunk_markers(fresh_text, para = True) |
|
|
|
|
|
st.markdown(selected_url) |
|
|
|
|
|
text = url_content(selected_url) |
|
llm_generated = get_llm_gen_contents(selected_url) |
|
|
|
if "summary" in llm_generated: |
|
summ = llm_generated["summary"] |
|
|
|
|
|
summ = re.sub(r'<cite>((?:\[\d+\])+)</cite>', r' \1', summ) |
|
summ_sub = rf'<strong><a href="#" sourceid="chunk_\1" target="" class="cite tooltip">[\1]\ |
|
<span class="tooltiptext">__chunk_\1_text__</span></a></strong>' |
|
|
|
summ = re.sub(r'\[(\d+)\]', summ_sub, summ) |
|
for idx, chunk in enumerate(chunks): |
|
chunk = re.sub(r'https?://', '', chunk, flags = re.IGNORECASE | re.MULTILINE) |
|
summ = summ.replace(f"__chunk_{idx}_text__", f"{chunk}") |
|
|
|
st.write(summ, unsafe_allow_html = True) |
|
|
|
|
|
tab1, tab2, tab3, tab4, tab5 = st.tabs([ |
|
"Xem nội dung", |
|
"Bản tinh gọn", |
|
"Chỉnh sửa nội dung", |
|
"Cào lại nội dung", |
|
"Xóa nội dung", |
|
]) |
|
|
|
|
|
|
|
with tab1: |
|
|
|
marked_chunks = [ f'<span id="chunk_{i}" class="source">{c}</span>' for i, c in enumerate(chunks) ] |
|
|
|
content = "\n\n".join(marked_chunks) |
|
|
|
st.write(content, unsafe_allow_html = True) |
|
|
|
|
|
|
|
javascript(""" |
|
function removeHilite() { |
|
document.querySelectorAll('.hilite').forEach(element => { |
|
element.classList.remove('hilite'); |
|
element.setAttribute("style", "background: #FFFFFF;") |
|
}); |
|
} |
|
|
|
setTimeout(() => { |
|
|
|
console.log("BẮT ĐẦU NHÚNG JS"); |
|
removeHilite(); |
|
|
|
document.querySelectorAll('.cite').forEach(element => { |
|
|
|
console.log('Element:', element); |
|
element.addEventListener('click', () => { |
|
|
|
let chunkId = element.getAttribute("sourceid"); |
|
removeHilite(); |
|
|
|
let hiliteElem = document.getElementById(chunkId); |
|
console.log('Element to hilite:', chunkId, hiliteElem); |
|
|
|
hiliteElem.classList.add('hilite'); |
|
hiliteElem.setAttribute("style", "background: #eadef9;") |
|
|
|
// Scroll into view |
|
hiliteElem.scrollIntoView({ behavior: "smooth", block: "center" }); |
|
}); |
|
}); |
|
|
|
}, 200); |
|
""".strip()) |
|
|
|
|
|
|
|
with tab2: |
|
|
|
clean_view = get_clean_view(selected_url) |
|
if clean_view is None: |
|
st.write("Hệ thống đang tạo nội dung, vui lòng chờ ...") |
|
|
|
if st.button("Reload"): |
|
st.rerun() |
|
else: |
|
st.write(clean_view) |
|
|
|
if st.button("Dùng bản tinh gọn làm nội dung"): |
|
url_content(selected_url, update_text = clean_view) |
|
st.success("Đã lưu thay đổi!") |
|
st.rerun() |
|
|
|
|
|
|
|
with tab3: |
|
|
|
fresh_text = url_content(selected_url) |
|
|
|
edited_text = st.text_area( |
|
f"*Lưu ý: Văn bản không được dài quá {config.text_max_words} từ, nếu quá sẽ tự động cắt bỏ*", |
|
value =fresh_text, |
|
height = 500, |
|
key = f"edit_{selected_url}" |
|
) |
|
|
|
if st.button("Lưu thay đổi"): |
|
url_content(selected_url, update_text = edited_text) |
|
st.success("Đã lưu thay đổi!") |
|
st.rerun() |
|
|
|
|
|
|
|
with tab4: |
|
|
|
if st.button("Bạn chắc chắn muốn cào lại nội dung?"): |
|
reset_content(selected_url) |
|
st.rerun() |
|
|
|
|
|
|
|
with tab5: |
|
|
|
if st.button("Bạn chắc chắn muốn xóa nội dung?"): |
|
urls_input = st.session_state["urls_input"] |
|
urls_input = urls_input.replace(selected_url, "") |
|
|
|
st.session_state["urls_input"] = normalize_text(urls_input) |
|
st.session_state['selected_url'] = None |
|
|
|
st.success("Đã xóa nội dung!") |
|
st.rerun() |
|
|