| import os |
|
|
| import pypdfium2 as pdfium |
| import gradio as gr |
|
|
| from langchain.chat_models import ChatOpenAI |
| from src.summarization import ( |
| parallel_summarization, |
| PARALLEL_SUMMARIZATION_MAPPING, |
| ) |
| from src.legal_implications import parallel_legal_implications |
| from src.mailing_utils import update_email_content, construct_url |
| import urllib |
|
|
|
|
| def _file_render_helper(file): |
| pdf = pdfium.PdfDocument(file.name) |
| images = [] |
| for page_index in range(len(pdf)): |
| page = pdf.get_page(page_index) |
| bitmap = page.render( |
| scale=200 / 72, |
| rotation=0, |
| |
| ) |
| images.append( |
| (bitmap.to_pil(), f"{file.name.split('/')[-1]} Seite {page_index+1}") |
| ) |
| return images |
|
|
|
|
| |
| def render_file(file): |
| images = _file_render_helper(file) |
| return gr.update( |
| value=images, |
| ) |
|
|
|
|
| def render_files(files): |
| all_images = [] |
| for file in files: |
| images = _file_render_helper(file) |
| all_images.extend(images) |
|
|
| return gr.update( |
| value=all_images, |
| ) |
|
|
|
|
| def create_email_textbox() -> gr.Textbox: |
| return gr.Textbox( |
| label="Email Instructions", |
| placeholder="Write Email Instructions here.", |
| value=( |
| "Dear Recipient\n\n" |
| "Please find the summarization of the uploaded document below.\n\n" |
| "<TEXT_FROM_LLM>\n\n" |
| "Kind regards,\n" |
| "Your Legal Assistant" |
| ), |
| lines=9, |
| ) |
|
|
|
|
| def switch_buttons(interactive: bool): |
| """This switches the buttons to interactive or not interactive. |
| |
| Args: |
| interactive (bool): Whether the buttons should be interactive or not. |
| """ |
| return ( |
| gr.update( |
| interactive=interactive, |
| ), |
| gr.update( |
| interactive=interactive, |
| ), |
| gr.update( |
| interactive=interactive, |
| ), |
| ) |
|
|
|
|
| def update_email_url(address: str, subject: str, email_instructions_summary: str): |
| body = urllib.parse.quote(email_instructions_summary) |
| return gr.update(link=construct_url(address=address, subject=subject, body=body)) |
|
|
|
|
| def update_email_instructions_summary(email_wrapping_content: str, summary: str): |
| return gr.update( |
| value=update_email_content( |
| email_wrapping_content=email_wrapping_content, summary=summary |
| ) |
| ) |
|
|
|
|
| def load_summary_section(llm: ChatOpenAI): |
| """Load the summary section |
| |
| Args: |
| llm (ChatOpenAI): Language model. |
| |
| Returns: |
| gr.Blocks: The summarization section |
| """ |
|
|
| with gr.Blocks( |
| theme="soft", |
| ) as summary_section: |
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=1): |
| file_upload_summary = gr.File( |
| file_count="single", |
| file_types=[".pdf", ".txt"], |
| label="Upload PDF", |
| ) |
| summary_parallel_button = gr.Button("Summarize", interactive=False) |
| clear_button = gr.Button("Clear All") |
| with gr.Column(scale=2): |
| sections_to_select = [ |
| i for i in PARALLEL_SUMMARIZATION_MAPPING.keys() if "II." not in i |
| ] |
| summary_sections_dropdown = gr.Dropdown( |
| sections_to_select, |
| value=sections_to_select, |
| interactive=True, |
| multiselect=True, |
| label="Sections for Summarization", |
| info="Select the sections you want to include in the summarization.", |
| ) |
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=1): |
| summary_show_pdf = gr.Gallery(label="Uploaded PDF").style( |
| object_fit="contain" |
| ) |
| with gr.Column(scale=1): |
| summary_output = gr.Textbox(label="Summary", lines=9).style( |
| show_copy_button=True |
| ) |
|
|
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=1): |
| recipient_email_summary = gr.Textbox( |
| label="Recipient Email", placeholder="Enter Email" |
| ) |
| subject_email_summary = gr.Textbox( |
| label="Subject", placeholder="Enter Subject" |
| ) |
| send_email_button = gr.Button( |
| "TEST email", link="mailto:", interactive=False, variant="primary" |
| ) |
| with gr.Column(scale=3): |
| email_instructions_summary = create_email_textbox() |
|
|
| |
| file_upload_summary.upload( |
| switch_buttons, |
| [gr.State(True)], |
| [summary_parallel_button, gr.State(None), gr.State(None)], |
| queue=False, |
| ).then(fn=render_file, inputs=[file_upload_summary], outputs=[summary_show_pdf]) |
|
|
| summary_parallel_button.click( |
| switch_buttons, |
| [gr.State(False)], |
| [summary_parallel_button, gr.State(None), gr.State(None)], |
| queue=False, |
| ).then( |
| parallel_summarization, |
| [file_upload_summary, summary_sections_dropdown, gr.State([llm])], |
| [summary_output], |
| queue=False, |
| ).then( |
| fn=update_email_instructions_summary, |
| inputs=[ |
| email_instructions_summary, |
| summary_output, |
| ], |
| outputs=[email_instructions_summary], |
| queue=False, |
| ).then( |
| fn=update_email_url, |
| inputs=[ |
| recipient_email_summary, |
| subject_email_summary, |
| email_instructions_summary, |
| ], |
| outputs=[send_email_button], |
| queue=False, |
| ).then( |
| switch_buttons, |
| [gr.State(True)], |
| [summary_parallel_button, send_email_button, gr.State(None)], |
| queue=False, |
| ).then |
|
|
| |
| clear_button.click(lambda: None, None, summary_output, queue=False).then( |
| lambda: None, None, file_upload_summary, queue=False |
| ).then(lambda: None, None, summary_show_pdf, queue=False).then( |
| lambda: None, None, send_email_button, queue=False |
| ).then( |
| lambda: None, None, email_instructions_summary, queue=False |
| ).then( |
| lambda: None, None, recipient_email_summary, queue=False |
| ) |
|
|
| recipient_email_summary.input( |
| fn=update_email_url, |
| inputs=[ |
| recipient_email_summary, |
| subject_email_summary, |
| email_instructions_summary, |
| ], |
| outputs=[send_email_button], |
| queue=False, |
| ) |
| subject_email_summary.input( |
| fn=update_email_url, |
| inputs=[ |
| recipient_email_summary, |
| subject_email_summary, |
| email_instructions_summary, |
| ], |
| outputs=[send_email_button], |
| queue=False, |
| ) |
|
|
| return summary_section |
|
|
|
|
| def load_legal_implications_section(llm: ChatOpenAI, summarization_kwargs: dict = {}): |
| """Load the legal implications section |
| |
| Args: |
| llm (ChatOpenAI): Language model. |
| summarization_kwargs (dict, optional): Keyword arguments for the summarization. Defaults to {}. |
| |
| Returns: |
| gr.Block: Legal Implications Section |
| """ |
| with gr.Blocks(theme="soft") as legal_implications_section: |
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=3): |
| file_upload_legal_implications = gr.File( |
| file_count="multiple", |
| file_types=[".pdf", ".txt"], |
| label="Upload PDF", |
| ) |
| with gr.Column(scale=1): |
| extract_legal_implications_button = gr.Button( |
| "Extract Legal Implications", interactive=False |
| ) |
| clear_legal_implications_button = gr.Button("Clear All") |
|
|
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=1): |
| legal_implications_show_pdf = gr.Gallery(label="Uploaded PDF").style( |
| object_fit="contain" |
| ) |
| with gr.Column(scale=1): |
| legal_implications_output = gr.Textbox( |
| label="Legal Implications", lines=9 |
| ).style(show_copy_button=True) |
|
|
| with gr.Row().style(equal_height=True): |
| with gr.Column(scale=1): |
| recipiant_email_legal_implications = gr.Textbox( |
| label="Recipient Email", placeholder="Enter Email" |
| ) |
| subject_email_legal_implications = gr.Textbox( |
| label="Subject", placeholder="Enter Subject" |
| ) |
| send_email_button_legal_implications = gr.Button( |
| "Open Email", link="mailto:", interactive=False |
| ) |
| with gr.Column(scale=3): |
| email_instructions_legal_implications = create_email_textbox() |
|
|
| |
| file_upload_legal_implications.upload( |
| switch_buttons, |
| [gr.State(True)], |
| [extract_legal_implications_button, gr.State(None), gr.State(None)], |
| queue=False, |
| ).then( |
| fn=render_files, |
| inputs=[file_upload_legal_implications], |
| outputs=[legal_implications_show_pdf], |
| ) |
|
|
| extract_legal_implications_button.click( |
| switch_buttons, |
| [gr.State(False)], |
| [extract_legal_implications_button, gr.State(None), gr.State(None)], |
| queue=False, |
| ).then( |
| parallel_legal_implications, |
| [ |
| file_upload_legal_implications, |
| gr.State([llm]), |
| gr.State(summarization_kwargs), |
| ], |
| [legal_implications_output], |
| queue=False, |
| ).then( |
| switch_buttons, |
| [gr.State(True)], |
| [ |
| extract_legal_implications_button, |
| send_email_button_legal_implications, |
| gr.State(None), |
| ], |
| queue=False, |
| ) |
| |
| clear_legal_implications_button.click( |
| lambda: None, None, legal_implications_output, queue=False |
| ).then(lambda: None, None, file_upload_legal_implications, queue=False).then( |
| lambda: None, None, legal_implications_show_pdf, queue=False |
| ).then( |
| lambda: None, None, send_email_button_legal_implications, queue=False |
| ).then( |
| lambda: None, None, email_instructions_legal_implications, queue=False |
| ).then( |
| lambda: None, None, recipiant_email_legal_implications, queue=False |
| ) |
|
|
|
|
| def run_summarization_model_gradio( |
| llm: ChatOpenAI, |
| share_gradio_via_link: bool = False, |
| summarization_kwargs: dict = {}, |
| run_local: bool = False, |
| ): |
| """Run the Summarization assistant with gradio |
| |
| Args: |
| llm (ChatOpenAI): Language model. |
| share_gradio_via_link (bool, optional): Whether to launch the gradio app via a public link. Defaults to False. |
| summarization_kwargs (dict, optional): Keyword arguments for the summarization. Defaults to {}. |
| run_local (bool, optional): Whether to run the gradio app locally. Defaults to False. |
| |
| """ |
| title = "Legal Document Assistant" |
| description = ( |
| f"This is a proof of concept. Don't upload any confidential documents." |
| ) |
|
|
| with gr.Blocks( |
| theme="soft", |
| title=title, |
| ) as webui: |
| with gr.Row().style(equal_height=True): |
| Header_box = generate_title(title=title, description=description) |
| with gr.Tab("Summarize Verdict"): |
| load_summary_section(llm=llm) |
| with gr.Tab("Legal Implications"): |
| load_legal_implications_section( |
| llm=llm, summarization_kwargs=summarization_kwargs |
| ) |
|
|
| webui.queue() |
|
|
| if run_local: |
| webui.launch(share=share_gradio_via_link) |
| else: |
| basic_auth = ( |
| "lenox", |
| os.environ["PROTOTYPE_PASSWORD"], |
| ) |
| webui.launch(auth=basic_auth) |
|
|
|
|
| def generate_title(title: str, description: str): |
| """THIS IS AN EXAMPLE HTML CODE FOR A TITLE""" |
| return gr.HTML( |
| ( |
| """ |
| <html> |
| <head> |
| <style> |
| .awesome-title { |
| background: linear-gradient(27deg, rgba(252,92,125,1) 19%, rgba(79,70,229,1) 45%); |
| color: #FFFFFF; |
| text-align: center; |
| padding: 20px; |
| border-radius: 10px; |
| height: 10%; |
| box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.1); |
| } |
| |
| .awesome-title h1 { |
| font-family: 'Arial', sans-serif; |
| font-size: 32px; |
| margin: 0; |
| } |
| |
| .awesome-title p { |
| font-family: 'Arial', sans-serif; |
| font-size: 16px; |
| margin: 10px 0 0; |
| } |
| </style> |
| </head> |
| <body> |
| """ |
| + f""" |
| <div class="awesome-title"> |
| <img src="https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/64e3560ad5e75575cd641c9c/WpgaNwGDfaTMjsimt8i87.png" alt="Lenox AI" style="height: 80%; position:absolute;"> |
| <h1>{title}</h1> |
| <p>{description}</p> |
| </div> |
| </body> |
| </html> |
| """ |
| ).strip(), |
| ) |
|
|