import os import io import openai import datetime import time import gradio as gr import json from jinja2 import Template import requests import fitz from xhtml2pdf import pisa from io import BytesIO #from dotenv import load_dotenv from datetime import datetime #load_dotenv() # Initialize OpenAI openai.api_key = os.environ.get('OPENAI_API_KEY') # Configuration variables airtable_api_key = os.environ.get('AIRTABLE_API_KEY') # Airtable table names prompts_table_name = 'tblYIZEB8m6JkGDEP' users_table_name = 'tblLNe5ZL47SvrAEk' user_log_table_name = 'tblrlTsRrkl6BqMAJ' compliancelog_table_name = 'tblQMXWKGlOonkIw2' policies_table_name = 'tbla6PC65qZfqdJhE' compliance_history_table_name = 'tbltA3vCb2upKVeFT' # Define the style and content for the response field label_text = "Contract Redline" color = "#6562F4" background_color = "white" border_radius = "10px" # response_label = f'

{label_text}

' response_label = f'{label_text}' base_id = 'appcUK3hUWC7GM2Kb' # App name for user login logging app = "Compliance" headers = { "Authorization": f"Bearer {airtable_api_key}", "Content-Type": "application/json", "Accept": "application/json", } def prompt_trim(prompt: str) -> str: lines = prompt.split('\n') trimmed = '\n'.join([l.strip() for l in lines]) return trimmed def get_policy_text(school): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{policies_table_name}' # Parameters for the API request to select only the 'school' field params = { 'filterByFormula': f'school="{school}"', 'fields[]': 'policy_text' } global policy_text policy_text = '' try: # Send a GET request to the Airtable API response = requests.get(airtable_endpoint, headers=headers, params=params) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse the JSON response data = response.json() # Check if there are records in the response if data.get('records'): # Extract the 'school' values from each record policy_text = [record['fields']['policy_text'] for record in data['records']] else: print("No records found in the 'policies' table.") else: print(f"Failed to retrieve data. Status code: {response.status_code}") except Exception as e: print(f"An error occurred: {str(e)}") #print(policy_text) return policy_text def get_schools(): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{policies_table_name}' # Parameters for the API request to select only the 'school' field params = { 'fields[]': 'school', # Replace with the name of your field 'sort[0][field]': 'school', # Sort by the 'school' field 'sort[0][direction]': 'asc', # Sort in ascending order } schools = '' try: # Send a GET request to the Airtable API response = requests.get(airtable_endpoint, headers=headers, params=params) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse the JSON response data = response.json() # Check if there are records in the response if data.get('records'): # Extract the 'school' values from each record schools = [record['fields']['school'] for record in data['records']] else: print("No records found in the 'policies' table.") else: print(f"Failed to retrieve data. Status code: {response.status_code}") except Exception as e: print(f"An error occurred: {str(e)}") return schools def get_prompt(header, template_content): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{prompts_table_name}' params = { 'filterByFormula': "prompt_name='Compliance_v1'", } response = requests.get(airtable_endpoint, headers=headers, params=params) # Check for errors response.raise_for_status() data = response.json() # Check if there is at least one record matching the condition if data.get('records'): # Get the first record (there should be only one) record = data['records'][0]['fields'] # Assign system_prompt and user_prompt to variables header = record.get('system_prompt', '') template_content = record.get('user_prompt', '') return header, template_content def append_to_at_compliancelog(policy_name_dd,contract_text,gpt_response, response_time, question_cost, prompt_tokens, completion_tokens): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{compliancelog_table_name}' # Organize data for Airtable new_fields = { 'policy_name': str(policy_name_dd), 'contract_text': str(contract_text), 'gpt_response': str(gpt_response), 'response_time': str(response_time), 'question_cost': question_cost, 'user_name': str(logged_in_user), 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens } data = { 'fields': new_fields } try: # Post data to Airtable response = requests.post(airtable_endpoint, headers=headers, json=data) # print(response.json()) # Check for errors response.raise_for_status() except requests.exceptions.HTTPError as http_error: # Handle the HTTP error (e.g., log it or display an error message) print(f"HTTP error occurred: {http_error}") except Exception as e: # Handle exceptions, log errors, or raise them as needed print(f"An error occurred: {str(e)}") def format_date(date_str): # Convert YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS.000Z to MM/DD/YYYY HH:MM:SS format try: date_obj = datetime.strptime(date_str, "%Y-%m-%d") return date_obj.strftime("%m/%d/%Y") except ValueError: try: date_obj = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ") return date_obj.strftime("%m/%d/%Y %H:%M") except ValueError: return date_str def get_compliance_history(): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{compliance_history_table_name}' params = { #'filterByFormula': f'school="{policy_name_dd}"', 'fields[]': ['sponsor', 'contract_value', 'student_name', 'student_email', 'start_date', 'end_date', 'status', 'Created'], 'sort[0][field]': 'Created', 'sort[0][direction]': 'desc', } compliance_fields = [ 'sponsor', 'contract_value', 'student_name', 'student_email', 'start_date', 'end_date', 'status', 'Created' ] compliance_records = [] try: # Send a GET request to the Airtable API response = requests.get(airtable_endpoint, headers=headers, params=params) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse the JSON response data = response.json() # Check if there are records in the response if data.get('records'): for record in data['records']: # Use list comprehension to create the record in the correct field order record_data = [ format_date(record['fields'][field]) if field in ['start_date', 'end_date', 'Created'] else record['fields'][field] for field in compliance_fields ] compliance_records.append(record_data) else: print("No records found in the 'compliance history' table.") else: print(f"Failed to retrieve data. Status code: {response.status_code}") except Exception as e: print(f"An error occurred: {str(e)}") #print(compliance_records) return compliance_records def append_to_at_compliance_history(policy_name_dd,contract_redline_html,compliance_comments_tbox,sponsor_tbox,compensation_num,status_ddss,name_tbox,email_tbox,start_date_tbox,end_date_tbox): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{compliance_history_table_name}' # Organize data for Airtable new_fields = { 'school': str(policy_name_dd), 'sponsor': str(sponsor_tbox), 'contract_redline': str(contract_redline_html), 'compliance_comments': str(compliance_comments_tbox), 'contract_value': compensation_num, 'status': str(status_ddss), 'student_name': str(name_tbox), 'student_email': str(email_tbox), 'start_date': str(start_date_tbox), 'end_date': str(end_date_tbox) } data = { 'fields': new_fields } if ( not policy_name_dd or not contract_redline_html or not compliance_comments_tbox or not sponsor_tbox or not compensation_num or not status_ddss or not name_tbox or not email_tbox or not start_date_tbox or not end_date_tbox ): gr.Warning("One or more fields are blank. Contract cannot be saved") return try: # Post data to Airtable response = requests.post(airtable_endpoint, headers=headers, json=data) #print(response.json()) # Check for errors response.raise_for_status() gr.Info("Contract Saved") compliance_history = get_compliance_history() return {compliance_history_df: compliance_history } except requests.exceptions.HTTPError as http_error: # Handle the HTTP error (e.g., log it or display an error message) print(f"HTTP error occurred: {http_error}") except Exception as e: # Handle exceptions, log errors, or raise them as needed print(f"An error occurred: {str(e)}") # Chatbot Function def chatbot(policy_name_dd,contract_text,progress=gr.Progress()): start_time = datetime.now() progress(progress=None) """ time.sleep(10) for i in progress.tqdm(range(100)): time.sleep(1) """ #print(policy_name) #students = get_students(school_selection) get_policy_text(policy_name_dd) #print(policy_text) #print(contract_text) template_content = '' header = '' header, template_content = get_prompt(header, template_content) # print(header) # print(template_content) # Create a Jinja2 template from the content template = Template(template_content) # Render the template with the inputs analysis_input = template.render(contract_text=contract_text,policy_text=policy_text) trimmed_input = prompt_trim(analysis_input) with open('analysis_input.txt', 'w', encoding='utf-8') as out_file: out_file.write(trimmed_input) gpt_model = "gpt-4-1106-preview" response = openai.ChatCompletion.create( model=gpt_model, temperature=0, messages=[ { "role": "system", "content": header }, { "role": "user", "content": analysis_input } ] ) gpt_response = response.choices[0].message["content"] tokens_used = response.usage if gpt_model == "gpt-4": question_cost = (tokens_used.get('total_tokens', 0) / 1000) * .03 prompt_tokens = tokens_used.get('prompt_tokens', ) completion_tokens = tokens_used.get('completion_tokens', 0) else: prompt_tokens = tokens_used.get('prompt_tokens', ) completion_tokens = tokens_used.get('completion_tokens', 0) question_cost = ((prompt_tokens / 1000) * .01) + ((completion_tokens / 1000) * .03) with open('response.txt', 'w', encoding='utf-8') as out_file: out_file.write(gpt_response) end_time = datetime.now() response_time = end_time - start_time data = json.loads(gpt_response.replace("```json", "").replace("```", "").strip()) global student_name, student_email, sponsor_name, start_date, end_date student_name = data['header']['Student Name'] student_email = data['header']['Student Email'] sponsor_name = data['header']['Sponsor Name'] start_date = data['header']['Start Date'] end_date = data['header']['End Date'] # Extracting data from the 'body' node html_content = data['body'] append_to_at_compliancelog(policy_name_dd,contract_text,html_content, response_time, question_cost, prompt_tokens, completion_tokens) return {contract_redline_html: html_content, download_row: gr.Row(visible=True)} def log_login(username): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{user_log_table_name}' # Organize data for Airtable new_fields = { 'user_name': str(username), 'app': str(app) } data = { 'fields': new_fields } try: # Post data to Airtable response = requests.post(airtable_endpoint, headers=headers, json=data) # Check for errors response.raise_for_status() except requests.exceptions.HTTPError as http_error: # Handle the HTTP error (e.g., log it or display an error message) print(f"HTTP error occurred: {http_error}") except Exception as e: # Handle exceptions, log errors, or raise them as needed print(f"An error occurred: {str(e)}") def login_auth(username, password): airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{users_table_name}' # Query the 'users' table to check for a match with the provided username and password params = { 'filterByFormula': f'AND(user_name = "{username}", password = "{password}")' } response = requests.get(airtable_endpoint, headers=headers, params=params) if response.status_code == 200: data = response.json() if data.get('records'): log_login(username) global logged_in_user logged_in_user = username #gr.Info("Login Success") return {login_row: gr.Row(visible=False), app_row: gr.Row(visible=True)} #gr.Info("Login Failed") print(f"Invalid user/password combination") return {login_row: gr.Row(visible=True), app_row: gr.Row(visible=False)} def extract_text_with_spacing(pdf_path): document = fitz.open(pdf_path) all_text = [] for page in document: # Extract text in a dict structure blocks = page.get_text("dict")["blocks"] for b in blocks: if "lines" in b: # Check if the block contains lines of text for line in b["lines"]: span_texts = [span["text"] for span in line["spans"]] all_text.append(" ".join(span_texts)) all_text.append("\n") # Presume a new block is a new paragraph document.close() return "\n".join(all_text) def pdf_to_text(contract_file_cmpt, contract_text_tbox, file_name_tbox): file_text = extract_text_with_spacing(contract_file_cmpt.name) #file_text = extract_text(contract_file_cmpt.name) original_file_name = contract_file_cmpt.name.split("/")[-1] redline_file_name = original_file_name.split(".")[0]+" Redline.pdf" return file_text, redline_file_name, None, None, None def convert_html_to_pdf(source_html, output_filename): # Result file stream result_file = open(output_filename, "w+b") # Convert HTML to PDF pisa_status = pisa.CreatePDF( BytesIO(source_html.encode("UTF-8")), # HTML content dest=result_file) # File handle to receive the result # Close the result file result_file.close() # Return True on success and False on errors return pisa_status.err def download_pdf(compliance_comments,contract_redline_html,file_name_tbox): #config = pdfkit.configuration(wkhtmltopdf="/usr/local/bin/wkhtmltopdf") contract_redline_comments = "

Contract Redline:


"+contract_redline_html + "

Compliance Comments:


"+compliance_comments #global pdf_download #pdf_download = pdfkit.from_string(contract_redline_comments,file_name_tbox,configuration=config) convert_html_to_pdf(contract_redline_comments, file_name_tbox) return {pdf_download_file: file_name_tbox} def change_tab(contract_text): if ( not contract_text ): gr.Warning("Contract Text is blank.") return False return gr.Tabs(selected=1) def update_tboxes(): return {sponsor_tbox: sponsor_name, name_tbox: student_name, email_tbox: student_email, start_date_tbox: start_date, end_date_tbox: end_date} def policy_name_change(policy_name_dd): gr.Info(f'Policy Name Changed to {policy_name_dd}') # Gradio UI CIMStheme = gr.themes.Soft().set( button_primary_background_fill='#6562F4', ) schools = get_schools() #compliance_history = get_compliance_history(["Wake Forest University"]) #compliance_history = get_compliance_history() #policy_text = get_policy_text("LSU") #for testing the function call #contract_redline = "

Campaign:

Engagement Name: Applebee's Fall Burger Promo

Engagement Id: 7015j000001DvCAAA0

Sponsor: Applebee's

Start Date: 2023-10-28

End Date: 2023-11-11

Engagement Description

The goal of the engagement is to Increase Sales by having the Student-Athlete Social Media Post. For the Social Media Post, the sponsor is requesting the student athlete take a photo in front of the football stadium in eating a Applebee's burger in your team jersey. The Media rights for the content will be 90 Days.

Engagement Compensation.

For successful completion of the engagement the student-athlete will receive payment in the form of Cash.

Part or all of the payment will be in cash, paid via PayPal.

The total value of compensation will be 250.

" #pdf_download = pdfkit.from_string(contract_redline, False) #print(pdf_download) logged_in_user = 'admin' file_text = '' contract_text = '' policy_text = '' compliance_comments = '' file_name = 'redline.pdf' pdf_download = '' with gr.Blocks(CIMStheme) as iface: with gr.Row(visible=False) as app_row: with gr.Column(): with gr.Row(): with gr.Column(scale=2): gr.Image(label="Logo", value="Nili_v2_Character.png", width=100, height=100, show_download_button=False, interactive=False, show_label=False, elem_id="logo", container=False) with gr.Column(scale=2): gr.Markdown(value="

NILI Compliance Desktop

") with gr.Column(scale=2): gr.Markdown("") with gr.Tabs() as tabs: with gr.Tab(label="Contract Upload", id=0) as upload_tab: with gr.Row(): with gr.Column(variant='panel',scale=1): contract_file_cmpt = gr.File(label="Select Contract File",file_count="single",file_types=[".pdf"],height=150) with gr.Column(variant='panel',scale=4): with gr.Row(): with gr.Column(variant='panel'): contract_text_tbox = gr.Textbox(label="Contract Text",interactive=True,info="Upload .pdf or paste in text. Shift-Enter to add a line") with gr.Row(): with gr.Column(scale=1): upload_btn = gr.components.Button(value="Upload Contract", size='sm', variant="primary") with gr.Column(scale=2): gr.Markdown("") with gr.Column(scale=1): redline_btn = gr.components.Button(value="Redline Contract", size='sm', variant="primary") with gr.Column(scale=2): gr.Markdown("") with gr.Tab(label="Contract Redline", id=1) as redline_tab: with gr.Row(variant='panel'): with gr.Column(): sponsor_tbox = gr.Textbox(label="Sponsor:", interactive=True) compensation_num = gr.Number(label="Contract Value",value=0) status_ddss = gr.Dropdown(["Pending","Approved","Rejected"],multiselect=False,label="Status", value="Pending") with gr.Column(): name_tbox = gr.Textbox(label="Name:", interactive=True) email_tbox = gr.Textbox(label="Email:", interactive=True, type='email',placeholder='xxxxxxx@xxxxxx.xxx') with gr.Column(): start_date_tbox = gr.Textbox(label="Start Date:", interactive=True, placeholder='MM/DD/YYYY') end_date_tbox = gr.Textbox(label="End Date:", interactive=True, placeholder='MM/DD/YYYY') with gr.Row(): with gr.Column(variant='panel'): gr.components.Markdown(response_label) contract_redline_html = gr.HTML(label="Contract Redline") compliance_comments_tbox = gr.Textbox(interactive=True,label='Compliance Comments') with gr.Row(): with gr.Column(): save_btn = gr.Button(value="Save Contract", size='sm', variant="primary") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Row(visible=False) as download_row: with gr.Column(variant='panel'): file_name_tbox = gr.Textbox(interactive=False,label='File Name',visible=False) pdf_download_file = gr.File() download_btn = gr.Button(value="Create Redline PDF", size='sm', variant="primary") upload_btn.click(pdf_to_text,inputs=[contract_file_cmpt,contract_text_tbox,file_name_tbox],outputs=[contract_text_tbox,file_name_tbox,contract_redline_html,compliance_comments_tbox,pdf_download_file]) download_btn.click(download_pdf,inputs=[compliance_comments_tbox,contract_redline_html,file_name_tbox],outputs=pdf_download_file) with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Tab(label="History", id=3) as history_tab: with gr.Row(): with gr.Column(variant='panel'): compliance_history_df = gr.Dataframe(get_compliance_history, headers=["Sponsor", "Contract Value", "Student Name", "Student Email", "Start Date", "End Date", "Status","Created"], datatype=["str", "number", "str", "str", "date", "date", "str","date"], label="Contract History", interactive=False ) with gr.Tab(label="Settings", id=4) as settings_tab: with gr.Row(): with gr.Column(variant='panel',scale=1): policy_name_dd = gr.Dropdown(schools, multiselect=False,label="NIL Policy Selection", value="Wake Forest University") policy_name_dd.change(policy_name_change,inputs=policy_name_dd,outputs=None) redline_btn.click(change_tab, inputs=contract_text_tbox, outputs=tabs).success(chatbot,inputs=[policy_name_dd,contract_text_tbox], outputs=[contract_redline_html,download_row]).then(update_tboxes,inputs=None, outputs=[sponsor_tbox,name_tbox,email_tbox,start_date_tbox,end_date_tbox]) save_btn.click(append_to_at_compliance_history,inputs=[policy_name_dd,contract_redline_html,compliance_comments_tbox,sponsor_tbox,compensation_num,status_ddss,name_tbox,email_tbox,start_date_tbox,end_date_tbox],outputs=compliance_history_df) with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Column(): gr.Markdown("") with gr.Row(visible=True) as login_row: with gr.Column(): with gr.Row(): with gr.Column(scale=2): gr.Markdown("") with gr.Column(scale=1): with gr.Row(): gr.Image(label="Logo", value="Nili_v2_Character.png", width=100, height=100, show_download_button=False, interactive=False, show_label=False, elem_id="logo", container=False) with gr.Row(): gr.Markdown(value="

NILI Login

") with gr.Column(scale=2): gr.Markdown("") with gr.Row(): with gr.Column(scale=2): gr.Markdown("") with gr.Column(scale=1, variant='panel'): username_tbox = gr.Textbox(label="User Name", interactive=True) password_tbox = gr.Textbox(label="Password", interactive=True, type='password') submit_btn = gr.Button(value='Submit', variant='primary', size='sm') submit_btn.click(login_auth, inputs=[username_tbox, password_tbox], outputs=[login_row,app_row]) with gr.Column(scale=2): gr.Markdown("") with gr.Row(): with gr.Column(scale=4): gr.HTML('
© 2023 Collegiate Influencer Marketing Systems, Inc.
CIMS.AI, CIMS.AI logo, NILI, NILI logo, and EzNIL are trademarks of Collegiate Influencer Marketing Systems, Inc.
') iface.queue() #iface.queue(concurrency_count=20).launch(auth=login_auth, auth_message= "Enter your username and password that you received from CIMS.AI. To request a login, please email 'info@cims.ai'") iface.launch()