Spaces:
Runtime error
Runtime error
import streamlit as st | |
#from fpdf import FPDF | |
import base64 | |
import openai | |
from streamlit_quill import st_quill | |
import os | |
from io import BytesIO | |
from docx import Document | |
import yagmail | |
import re | |
#import re | |
import html2text | |
from docx import Document | |
from docx.shared import Pt | |
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT | |
from docx.oxml.ns import qn | |
from docx.oxml import OxmlElement | |
from bs4 import BeautifulSoup | |
from html2docx import HTML2Docx | |
import streamlit as st | |
import streamlit.components.v1 as components | |
import streamlit as st | |
from captcha.image import ImageCaptcha | |
import random, string | |
# define the constant | |
length_captcha = 4 | |
width = 380 | |
height = 200 | |
def read_index_html(): | |
with open("index.html") as f: | |
return f.read() | |
custom_css = """ | |
<style> | |
body { | |
background-color: #F8F9F9; | |
} | |
h1 { | |
color: #2980B9; | |
} | |
h2 { | |
color: #21618C; | |
} | |
h3 { | |
color: #1C2833; | |
} | |
input, textarea { | |
background-color: #F2F3F4; | |
border-radius: 5px; | |
} | |
button { | |
background-color: #2980B9; | |
color: white; | |
font-weight: bold; | |
border-radius: 5px; | |
} | |
a { | |
color: #2980B9; | |
} | |
.streamlit-button { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.streamlit-button:hover { | |
background-color: #21618C; | |
} | |
</style> | |
""" | |
# custom_css = """ | |
# <style> | |
# body { | |
# background-color: #F8F9F9; | |
# } | |
# h1 { | |
# color: #2980B9; | |
# } | |
# h2 { | |
# color: #21618C; | |
# } | |
# h3 { | |
# color: #1C2833; | |
# } | |
# input, textarea { | |
# background-color: #F2F3F4; | |
# border-radius: 5px; | |
# } | |
# button { | |
# background-color: #2980B9; | |
# color: white; | |
# font-weight: bold; | |
# border-radius: 5px; | |
# } | |
# a { | |
# color: #2980B9; | |
# } | |
# .streamlit-button { | |
# display: flex; | |
# justify-content: center; | |
# align-items: center; | |
# color: white; | |
# } | |
# .streamlit-button:hover { | |
# background-color: #21618C; | |
# } | |
# .stTextInput > div > div > input { | |
# border: 1px solid #C0C0C0; | |
# border-radius: 5px; | |
# } | |
# </style> | |
# """ | |
os.environ["OPENAI_API_KEY"] = 'sk-E' | |
openai.api_key = os.getenv("OPENAI_API_KEY") | |
# define the function for the captcha control | |
def captcha_control(): | |
# control if the captcha is correct | |
if 'controllo' not in st.session_state or st.session_state['controllo'] == False: | |
#st.title("Please verify the Captcha to proceed") | |
st.markdown("<h1 style='text-align: center;'>Please verify the Captcha to proceed</h1>", unsafe_allow_html=True) | |
# define the session state for control if the captcha is correct | |
st.session_state['controllo'] = False | |
# define the session state for the captcha text because it doesn't change during refreshes | |
if 'Captcha' not in st.session_state: | |
st.session_state['Captcha'] = ''.join(random.choices(string.ascii_uppercase + string.digits, k=length_captcha)) | |
print("the captcha is: ", st.session_state['Captcha']) | |
# # setup the captcha widget | |
# image = ImageCaptcha(width=width, height=height) | |
# data = image.generate(st.session_state['Captcha']) | |
# st.image(data) | |
# capta2_text = st.text_input('Enter captcha text', max_chars=4) | |
# setup the captcha widget | |
# image = ImageCaptcha(width=width, height=height) | |
# data = image.generate(st.session_state['Captcha']) | |
# st.image(data) | |
# # Create a centered column with the same width as the captcha image | |
# left_col, center_col, right_col = st.columns([150, width, 150]) | |
# capta2_text = center_col.text_input('Enter captcha text', max_chars=4) | |
# Create a centered column with the same width as the captcha image for the captcha image | |
image = ImageCaptcha(width=width, height=height) | |
data = image.generate(st.session_state['Captcha']) | |
left_col_img, center_col_img, right_col_img = st.columns([150, width, 150]) | |
center_col_img.image(data) | |
# Create a centered column with the same width as the captcha image for the text input | |
left_col_input, center_col_input, right_col_input = st.columns([150, width, 150]) | |
capta2_text = center_col_input.text_input('Enter captcha text', max_chars=4) | |
# Create a centered column with the same width as the captcha image for the button | |
left_col_btn, center_col_btn, right_col_btn = st.columns([150, width, 150]) | |
if center_col_btn.button("Verify the code"): | |
#if st.button("Verify the code"): | |
print(capta2_text, st.session_state['Captcha']) | |
capta2_text = capta2_text.replace(" ", "") | |
# if the captcha is correct, the controllo session state is set to True | |
if st.session_state['Captcha'].lower() == capta2_text.lower().strip(): | |
del st.session_state['Captcha'] | |
st.session_state['controllo'] = True | |
st.experimental_rerun() | |
else: | |
# if the captcha is wrong, the controllo session state is set to False and the captcha is regenerated | |
st.error("π¨ The captcha code is incorrect, please try again.") | |
#st.write("π¨ The captcha code is incorrect, please try again.") | |
del st.session_state['Captcha'] | |
del st.session_state['controllo'] | |
st.experimental_rerun() | |
else: | |
# wait for the button click | |
st.stop() | |
def get_chatgpt_response(messages): | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=messages | |
) | |
return response['choices'][0]['message']['content'] | |
def update_chat(messages, role, content): | |
messages.append({"role": role, "content": content}) | |
return messages | |
def process_text(inputs): | |
global messages | |
processed_text = "" | |
for key, value in inputs.items(): | |
processed_text += f"{key}: {value}\n\n" | |
info= str(processed_text) | |
messages=[ | |
{"role": "system", "content": "You are a obituary writer given information in the from of json"}, | |
{"role": "user", "content": "Please write custom obituary based on this information. Make sure you write little long obituary using the information provided. Here is information: \n{}".format(info)} | |
] | |
model_response = get_chatgpt_response(messages) | |
return model_response | |
from html2docx import html2docx | |
from io import BytesIO | |
def save_as_doc(text, html_content): | |
doc_title = "Custom Obituary" | |
buf = html2docx(html_content, title=doc_title) | |
filename = f"{doc_title}.docx" | |
with open(filename, "wb") as f: | |
f.write(buf.getvalue()) | |
with open(filename, "rb") as f: | |
base64_content = base64.b64encode(f.read()).decode("utf-8") | |
href = f'<a href="data:application/octet-stream;base64,{base64_content}" download="{filename}" id="download-docx-link">Download</a>' | |
st.markdown(href, unsafe_allow_html=True) | |
os.remove(filename) | |
def form_page(): | |
st.markdown("### Free Obituary Writing Assistant :pencil:") | |
st.write("Complete any applicable fields below. If you don't know the answers, that's OK you can add them later") | |
inputs = { | |
"Full name, including any nicknames": "", | |
"Age at the time of passing": "", | |
"Date and place of birth": "", | |
"Date and place of passing": "", | |
"Family members who have preceded them in death": "", | |
"Surviving family members": "", | |
"Education, career, hobbies and interests": "", | |
"Accomplishments or contributions they made to their community or society": "", | |
"Personal traits that made them special": "", | |
"Service or memorial arrangements": "", | |
"Any personal message or special requests you would like to include": "", | |
"Additional information, like childhood or special bond": "", | |
} | |
for key in inputs: | |
inputs[key] = st.text_input(key) | |
if st.button("Create Obituary"): | |
global messages | |
with st.spinner('Generating obituary...'): | |
output_text = process_text(inputs) | |
messages = update_chat(messages, "assistant", output_text) | |
st.session_state.output_text = output_text | |
st.session_state.messages = messages | |
#st.write(output_text) | |
st.session_state.form = True | |
if st.session_state.form: | |
output_placeholder = st.empty() | |
#output_placeholder.write(st.session_state.output_text) | |
#output_placeholder.markdown(f'<div style="background-color: #6495ED; color: white; padding: 10px; border-radius: 5px;">{st.session_state.output_text}</div>', unsafe_allow_html=True) | |
output_placeholder.markdown(f'<div style="background-color: #AED6F1; color: black; padding: 10px; border-radius: 5px;">{st.session_state.output_text}</div>', unsafe_allow_html=True) | |
if "additional_info" not in st.session_state: | |
st.session_state.additional_info = "" | |
if "additional_info_key" not in st.session_state: | |
st.session_state.additional_info_key = "additional_info_input_1" | |
additional_info_placeholder = st.empty() | |
additional_info = additional_info_placeholder.text_input("What else would you like to add?", value=st.session_state.additional_info, key=st.session_state.additional_info_key) | |
if st.button("I want to add more information"): | |
messages = st.session_state.messages | |
with st.spinner('Generating obituary...'): | |
if additional_info: | |
message = "can you please re-write this obituary by using earlier information and new information. Please make sure you write obituary little long. new information is here: " + additional_info | |
messages = update_chat(messages, "user", message) | |
output_text = get_chatgpt_response(messages) | |
messages = update_chat(messages, "assistant", output_text) | |
st.session_state.output_text = output_text | |
#output_placeholder.write(output_text) | |
#output_placeholder.markdown(f'<div style="background-color: #6495ED; color: white; padding: 10px; border-radius: 5px;">{output_text}</div>', unsafe_allow_html=True) | |
output_placeholder.markdown(f'<div style="background-color: #AED6F1; color: black; padding: 10px; border-radius: 5px;">{output_text}</div>', unsafe_allow_html=True) | |
st.session_state.additional_info = "" | |
st.session_state.additional_info_key = f"additional_info_input_{int(st.session_state.additional_info_key.split('_')[-1]) + 1}" | |
additional_info_placeholder.text_input("What else would you like to add?", value=st.session_state.additional_info, key=st.session_state.additional_info_key) | |
if st.button("I want to export and edit manually"): | |
st.session_state.export_manually = True | |
st.session_state.form = False | |
st.experimental_rerun() | |
# if not st.session_state.form: | |
# if st.button("I want to export and edit manually"): | |
# st.session_state.form = True | |
# else: | |
# if st.button("Go Back to Form"): | |
# st.session_state.form = False | |
def send_email(email, subject, content): | |
sender_email = "[email protected]" # Replace with your email | |
sender_password = "acolructdnephudf" # Replace with your email password | |
yag = yagmail.SMTP(sender_email, sender_password) | |
yag.send(to=email, subject=subject, contents=content) | |
def validate_email(email): | |
email_regex = r"[^@]+@[^@]+\.[^@]+" | |
return re.match(email_regex, email) is not None | |
def editor_page(): | |
#form_page() | |
st.markdown("<h1 style='text-align: center; color: Red;'>Obituary Draft</h1>", unsafe_allow_html=True) | |
st.write("Use the editor below to edit the obituary:") | |
quill_text = st.session_state.output_text | |
edited_text = st_quill(quill_text, html=True) | |
st.session_state.edited_text = edited_text | |
#st.session_state.edited_html = edited_text['html'] | |
if st.button("Save as DOCX"): | |
html_content = st.session_state.edited_text | |
save_as_doc(st.session_state.edited_text, html_content) | |
st.write("The custom obituary has been saved as a Word document.") | |
if "email_obituary" not in st.session_state: | |
st.session_state.email_obituary = False | |
if st.button("Email Obituary"): | |
st.session_state.email_obituary = not st.session_state.email_obituary | |
if st.session_state.email_obituary: | |
recipient_email = st.text_input("Enter your email address:", key="recipient_email") | |
if st.button("Send", key="send_email_button"): | |
if recipient_email and validate_email(recipient_email): | |
with st.spinner('Sending...'): | |
send_email(recipient_email, "Your Custom Obituary", st.session_state.edited_text) | |
st.success("Obituary sent to your email!") | |
else: | |
st.error("Please enter a valid email address.") | |
st.markdown(""" | |
<style> | |
#toolbar { | |
background-color: #f3f3f3; | |
border-radius: 5px; | |
padding: 5px; | |
} | |
.ql-container { | |
border-radius: 5px; | |
border: 1px solid #ccc; | |
height: 700px; | |
} | |
.ql-editor { | |
height: 100%; | |
} | |
{edited_text.get('css')} | |
</style> | |
""", unsafe_allow_html=True) | |
PAGES = { | |
"Form Page": form_page, | |
"Editor Page": editor_page, | |
} | |
def app(): | |
#st.markdown(custom_css, unsafe_allow_html=True) | |
# custom_css = """ | |
# <style> | |
# /* Input box boundary */ | |
# .stTextInput > div > div > input { | |
# border: 1px solid #C0C0C0; | |
# border-radius: 5px; | |
# } | |
# </style> | |
# """ | |
st.markdown(custom_css, unsafe_allow_html=True) | |
# button_text_style = """ | |
# <style> | |
# .stButton > button { | |
# color: white !important; | |
# } | |
# /* Button hover color */ | |
# .stButton > button:hover { | |
# background-color: #45a049; | |
# } | |
# .stTextInput > div > div > input { | |
# border: 1px solid #C0C0C0; | |
# border-radius: 5px; | |
# } | |
# </style> | |
# """ | |
# st.markdown(button_text_style, unsafe_allow_html=True) | |
button_text_style = """ | |
<style> | |
.stButton > button { | |
color: white !important; | |
} | |
.stButton > button:hover { | |
background-color: #45a049; | |
color: red !important; | |
} | |
.stTextInput > div > div > input { | |
border: 1px solid #C0C0C0; | |
border-radius: 5px; | |
} | |
/* Background color for buttons */ | |
.stButton > button { | |
background-color: #ff0290; | |
color: white; | |
} | |
</style> | |
""" | |
st.markdown(button_text_style, unsafe_allow_html=True) | |
hide_streamlit_style = """ | |
<style> | |
#MainMenu {visibility: hidden;} | |
footer {visibility: hidden;} | |
</style> | |
""" | |
st.markdown(hide_streamlit_style, unsafe_allow_html=True) | |
hide_decoration_bar_style = ''' | |
<style> | |
header {visibility: hidden;} | |
</style> | |
''' | |
st.markdown(hide_decoration_bar_style, unsafe_allow_html=True) | |
#reduce top margin | |
reduce_header_height_style = """ | |
<style> | |
div.block-container {padding-top:0.01rem;} | |
</style> | |
""" | |
st.markdown(reduce_header_height_style, unsafe_allow_html=True) | |
if 'controllo' not in st.session_state or st.session_state['controllo'] == False: | |
captcha_control() | |
else: | |
if "form" not in st.session_state: | |
st.session_state.form = False | |
if "export_manually" not in st.session_state: | |
st.session_state.export_manually = False | |
if not st.session_state.export_manually: | |
form_page() | |
components.html( | |
read_index_html(), | |
height=0, | |
width=0, | |
) | |
else: | |
editor_page() | |
components.html( | |
read_index_html(), | |
height=0, | |
width=0, | |
) | |
if __name__ == "__main__": | |
app() | |