|
import gradio as gr |
|
import pandas as pd |
|
|
|
from fastapi import FastAPI |
|
from gradio.routes import App as GradioApp |
|
from introduck.inference import extract_contacts_from_text |
|
from introduck.utils import validate_email |
|
from introduck.utils import validate_multiple_emails |
|
from typing import Any |
|
|
|
_INTRO_SUBJECT_EXAMPLE: str = "Could you make an intro?" |
|
_INTRO_MESSAGE_EXAMPLE: str = """\ |
|
Hey, |
|
|
|
hope you are doing well! :-) |
|
|
|
Could you, please, make me an intro to one of them? |
|
- <person1@example.com> |
|
- <person2@acme.corp> |
|
- etc. |
|
|
|
Relevant info: |
|
- <add your one sentence summary here>; |
|
- Raising <add your fundraising amount here>; |
|
- We are backed by <add your existing investor names here>; |
|
- Team: |
|
+ <add team members> |
|
- Traction highlights: |
|
+ <highlights list> |
|
|
|
Best, |
|
<your name>\ |
|
""" |
|
|
|
|
|
def _analyze_message( |
|
sender: str, |
|
recipients: str, |
|
subject: str, |
|
body: str |
|
) -> (pd.DataFrame, dict): |
|
default_outputs = None, None |
|
|
|
|
|
if sender: |
|
sender = validate_email(email=sender) |
|
if not sender: |
|
return default_outputs |
|
|
|
|
|
if recipients: |
|
recipients = validate_multiple_emails(emails=recipients) |
|
if not recipients: |
|
return default_outputs |
|
|
|
if not subject: |
|
return default_outputs |
|
|
|
if not body: |
|
return default_outputs |
|
|
|
payload: str = "" |
|
payload += f"From: {sender or '*'}\n" |
|
payload += f"To: {recipients or '*'}\n" |
|
payload += f"Subject: {subject or '*'}\n\n" |
|
payload += f"{body or '***'}\n" |
|
|
|
outputs: list[dict[str, Any]] = extract_contacts_from_text(payload=payload) |
|
|
|
return pd.DataFrame(outputs), {"text": payload, "entities": outputs} |
|
|
|
|
|
def _use_message_template() -> (str, str): |
|
return _INTRO_SUBJECT_EXAMPLE, _INTRO_MESSAGE_EXAMPLE |
|
|
|
|
|
def _validate_message( |
|
sender: str, |
|
recipients: str, |
|
subject: str, |
|
body: str |
|
) -> dict: |
|
errors: list[str] = [] |
|
|
|
|
|
if sender: |
|
sender = validate_email(email=sender) |
|
if not sender: |
|
errors.append("- sender email is not valid;") |
|
|
|
|
|
if recipients: |
|
recipients = validate_multiple_emails(emails=recipients) |
|
if not recipients: |
|
errors.append("- one or more recipient emails are not valid;") |
|
|
|
if not subject: |
|
errors.append("- subject can't be empty;") |
|
|
|
if not body: |
|
errors.append("- message can't be empty;") |
|
|
|
new_value: str = "" |
|
if errors: |
|
errors_list: str = "\n".join(errors) |
|
new_value = f"```\nPlease, fix this errors:\n{errors_list}\n```" |
|
|
|
new_visibility: bool = len(errors) > 0 |
|
|
|
return gr.update(value=new_value, visible=new_visibility) |
|
|
|
|
|
def create_playground_route() -> FastAPI: |
|
|
|
|
|
css_workaround: str = """ |
|
#htxt span { |
|
font-family: monospace; |
|
white-space: pre; |
|
} |
|
""" |
|
|
|
copyright_string: str = "Introduck LLC, 2022" |
|
title: str = "Introduck Playground" |
|
|
|
base_blocks: gr.Blocks = gr.Blocks( |
|
analytics_enabled=False, |
|
title=title, |
|
css=css_workaround) |
|
|
|
with base_blocks: |
|
gr.Markdown(f"# {title}<br/>") |
|
|
|
gr.Markdown("## New intro request") |
|
|
|
email_sender_input: gr.Textbox = gr.Textbox( |
|
label="From (optional):", |
|
lines=1, |
|
max_lines=1, |
|
placeholder="founder@acme.com") |
|
|
|
email_recipients_input: gr.Textbox = gr.Textbox( |
|
label="To (optional):", |
|
lines=1, |
|
max_lines=1, |
|
placeholder="jane@vc2.com, john@vc01.com") |
|
|
|
email_subject_input: gr.Textbox = gr.Textbox( |
|
show_label=False, |
|
lines=1, |
|
max_lines=1, |
|
placeholder="Subject...", |
|
interactive=True) |
|
|
|
email_body_input: gr.Textbox = gr.Textbox( |
|
show_label=False, |
|
lines=5, |
|
max_lines=42, |
|
placeholder="Type a message...", |
|
interactive=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
email_errors_output: gr.Markdown = gr.Markdown( |
|
value="", |
|
visible=False) |
|
|
|
with gr.Row(): |
|
email_template_button: gr.Button = gr.Button( |
|
value="Use template", |
|
variant="secondary") |
|
|
|
email_submit_button: gr.Button = gr.Button( |
|
value="Submit", |
|
variant="primary") |
|
|
|
gr.Markdown("""\ |
|
**NOTE:** This email form is used to extract useful information from |
|
intro requests. We assure you that no data will be shared publicly |
|
and only a small group of people will get access to this data in |
|
order to label it and create new datasets for model training. By |
|
clicking **"Submit"** you automatically agree to this terms.\ |
|
""") |
|
|
|
with gr.Tabs(selected="default"): |
|
with gr.TabItem(label="Contacts", id="default"): |
|
contacts_output: gr.Dataframe = gr.Dataframe(max_rows=16) |
|
|
|
with gr.TabItem(label="RFC822-ish"): |
|
rfc822_output: gr.HighlightedText = gr.HighlightedText( |
|
label="RFC822-ish message (for debugging purposes):", |
|
show_legend=False, |
|
elem_id="htxt") |
|
|
|
gr.Markdown("## FAQ") |
|
|
|
with gr.Group(): |
|
with gr.Accordion("Is it cool?"): |
|
gr.Markdown("Yes!") |
|
|
|
with gr.Accordion("Is it free?"): |
|
gr.Markdown("Yes!") |
|
|
|
gr.Markdown("""\ |
|
[Contact us](mailto:hello@introduck.ai) / |
|
[Terms of Service](https://introduck.ai/terms) / |
|
[Privacy Policy](https://introduck.ai/privacy) |
|
""") |
|
|
|
gr.Markdown(f"**©** {copyright_string}") |
|
|
|
|
|
|
|
email_submit_button.click( |
|
fn=_analyze_message, |
|
inputs=[ |
|
email_sender_input, |
|
email_recipients_input, |
|
email_subject_input, |
|
email_body_input], |
|
outputs=[ |
|
contacts_output, |
|
rfc822_output]) |
|
|
|
email_submit_button.click( |
|
fn=_validate_message, |
|
inputs=[ |
|
email_sender_input, |
|
email_recipients_input, |
|
email_subject_input, |
|
email_body_input], |
|
outputs=[email_errors_output]) |
|
|
|
email_template_button.click( |
|
fn=_use_message_template, |
|
inputs=[], |
|
outputs=[email_subject_input, email_body_input]) |
|
|
|
return GradioApp.create_app(blocks=base_blocks) |
|
|