From ade0274602df11c9fb9db4a18b3f0c2238d82142 Mon Sep 17 00:00:00 2001 From: Ashish Baravaliya Date: Thu, 11 Jan 2024 10:43:42 -0500 Subject: [PATCH] feat: openai json format added --- .../autoinscribe_integration.py | 27 ++++--- autoinscribe/public/js/contact.js | 36 ++++----- autoinscribe/public/js/lead.js | 74 ++++++++----------- 3 files changed, 67 insertions(+), 70 deletions(-) diff --git a/autoinscribe/autoinscribe/doctype/autoinscribe_integration/autoinscribe_integration.py b/autoinscribe/autoinscribe/doctype/autoinscribe_integration/autoinscribe_integration.py index ce60dc6..f80e019 100644 --- a/autoinscribe/autoinscribe/doctype/autoinscribe_integration/autoinscribe_integration.py +++ b/autoinscribe/autoinscribe/doctype/autoinscribe_integration/autoinscribe_integration.py @@ -6,6 +6,7 @@ from frappe.model.document import Document import base64 import requests +import json from openai import OpenAI from google.cloud import vision from google.oauth2 import service_account @@ -55,10 +56,15 @@ def ask_gpt(self, prompt): } ], model="gpt-3.5-turbo-1106", + response_format={ "type": "json_object" } ) - return chat_completion.choices[0].message.content.strip() + try: + json_data = json.loads(chat_completion.choices[0].message.content) + return json_data + except: + return frappe.throw(_("There was an error extracting text from the image. Please try again"), title=_("Error")) except Exception as e: - frappe.throw(_("Please enter a valid OpenAI API key in AutoInscribe Settings"), title=_("Error")) + return frappe.throw(_("Please enter a valid OpenAI API key in AutoInscribe Settings" + str(e)), title=_("Error")) def extract_text_from_img(self, img_url): '''Extracts and returns first_name, middle_name, last_name, gender, salutation, designation contact_numbers, email_ids, company_name, website, address, mobile_number, phone_number, city, state and country from an image given the image URL''' @@ -105,7 +111,7 @@ def extract_text_from_img(self, img_url): # Extracting detected text if texts: detected_text = texts[0].description - prompt = f"From the following text, identify the first_name, middle_name, last_name, gender, salutation, designation contact_numbers, email_ids, company_name, website, address, mobile_number, phone_number, city, state, country: {detected_text}. Output must be a string containing one key-value pair per line and for absence of values use 'NULL' for value as placeholder. contact_numbers and email_ids must be comma-separated if there are multiple. Guess the salutation and gender. gender can be Male, Female, Transgender or Other. phone_number must be the telephone number whereas mobile_number must be the mobile number. country must have the value as full country name, e.g, US becomes United States, UK becomes United Kingdom." + prompt = f"From the following text, identify the first_name, middle_name, last_name, gender, salutation, designation contact_numbers, email_ids, company_name, website, address, mobile_number, phone_number, city, state, country: {detected_text}. Output must be a string containing one key-value pair per line and for absence of values use 'NULL' for value as placeholder. contact_numbers and email_ids must be as a list. Guess the salutation and gender. gender can be Male, Female, Transgender or Other. phone_number must be the telephone number whereas mobile_number must be the mobile number. country must have the value as full country name, e.g, US becomes United States, UK becomes United Kingdom. In ihe JSON format" reply = self.ask_gpt(prompt) return reply else: @@ -114,14 +120,13 @@ def extract_text_from_img(self, img_url): def create_address(self, address): '''Given an address string, extract city, state, postal_code, country and create an address if country exists & return the inserted doc. Return None otherwise.''' - prompt = f"From the following address text, identify city, state, country and postal_code: {address}. Output must be a string containing one key-value pair per line and for absence of values use 'NULL'. country must have the value as full country name, e.g, US becomes United States, UK becomes United Kingdom" - reply = self.ask_gpt(prompt) - addr_lines = reply.strip().splitlines() - city = addr_lines[0].split(':')[1].strip() - state = addr_lines[1].split(':')[1].strip() - postal_code = addr_lines[3].split(':')[1].strip() - country = addr_lines[2].split(':')[1].strip() - country_exists = frappe.db.exists("Country", {"country_name": country}) + prompt = f"From the following address text, identify city, state, country and postal_code: {address}. Output must be a JSON object and for absence of values use 'NULL'. country must have the value as full country name, e.g, US becomes United States, UK becomes United Kingdom" + addr_data = self.ask_gpt(prompt) + city = addr_data["city"] + state = addr_data["state"] + postal_code = addr_data["postal_code"] + country = addr_data["country"] + country_exists = frappe.db.exists("Country", {"country_name": addr_data["country"]}) address_title = address.strip().rsplit(',', 1)[0].strip() if len(address.strip().rsplit(',', 1)[0].strip()) < 100 else f"{city}, {country}" print(address_title) if country_exists: diff --git a/autoinscribe/public/js/contact.js b/autoinscribe/public/js/contact.js index 2b08187..5fe17b5 100644 --- a/autoinscribe/public/js/contact.js +++ b/autoinscribe/public/js/contact.js @@ -2,6 +2,13 @@ $(document).on("change", 'input[type="file"]', function () { $(".btn.btn-secondary.btn-sm.btn-modal-secondary").click(); }); +const mapFieldValue = (frm, response, field, json_field = null) => { + const value = response[json_field || field]; + if (value !== "NULL") { + frm.set_value(field, value); + } +}; + frappe.ui.form.on("Contact", { custom_upload_image(frm) { if (frm.selected_doc.custom_upload_image) { @@ -16,20 +23,15 @@ frappe.ui.form.on("Contact", { freeze: true, freeze_message: "Transmuting Pixels into Insights... Hold Tight!", callback(res) { - const resArr = res.message.split("\n"); + const data = res.message; + + mapFieldValue(frm, data, "first_name"); + mapFieldValue(frm, data, "middle_name"); + mapFieldValue(frm, data, "last_name"); + mapFieldValue(frm, data, "company_name"); + mapFieldValue(frm, data, "designation"); - const first_name = resArr[0].split(":")[1].trim(); - const middle_name = resArr[1].split(":")[1].trim(); - const last_name = resArr[2].split(":")[1].trim(); - first_name !== "NULL" && frm.set_value("first_name", first_name); - middle_name !== "NULL" && frm.set_value("middle_name", middle_name); - last_name !== "NULL" && frm.set_value("last_name", last_name); - const company_name = resArr[8].split(":")[1].trim(); - company_name !== "NULL" && - frm.set_value("company_name", company_name); - const designation = resArr[5].split(":")[1].trim(); - designation !== "NULL" && frm.set_value("designation", designation); - const email_ids = resArr[7].split(":")[1].trim().split(","); + const email_ids = data.email_ids; email_ids.forEach((email) => { email.trim() !== "NULL" && frm.add_child("email_ids", { @@ -37,7 +39,7 @@ frappe.ui.form.on("Contact", { }); }); frm.refresh_field("email_ids"); - const contact_numbers = resArr[6].split(":")[1].trim().split(","); + const contact_numbers = data.contact_numbers; contact_numbers.forEach((phone_no) => { phone_no.trim() !== "NULL" && frm.add_child("phone_nos", { @@ -46,7 +48,7 @@ frappe.ui.form.on("Contact", { }); frm.refresh_field("phone_nos"); - let gender = resArr[3].split(":")[1].trim(); + let gender = data.gender; gender = gender.charAt(0).toUpperCase() + gender.slice(1); frappe.db.exists("Gender", gender).then((gender_exists) => { if (gender_exists) { @@ -54,7 +56,7 @@ frappe.ui.form.on("Contact", { } }); frm.refresh_field("gender"); - let salutation = resArr[4].split(":")[1].trim(); + let salutation = data.salutation; salutation = salutation.charAt(0).toUpperCase() + salutation.slice( @@ -72,7 +74,7 @@ frappe.ui.form.on("Contact", { }); frm.refresh_field("salutation"); - const address = resArr[10].split(":")[1].trim(); + const address = data.address; if (address !== "NULL") { frappe.call({ method: diff --git a/autoinscribe/public/js/lead.js b/autoinscribe/public/js/lead.js index c6199bd..080cd70 100644 --- a/autoinscribe/public/js/lead.js +++ b/autoinscribe/public/js/lead.js @@ -1,7 +1,14 @@ -$(document).on('change', 'input[type="file"]', function() { - $(".btn.btn-secondary.btn-sm.btn-modal-secondary").click() +$(document).on("change", 'input[type="file"]', function () { + $(".btn.btn-secondary.btn-sm.btn-modal-secondary").click(); }); +const mapFieldValue = (frm, response, field, json_field = null) => { + const value = response[json_field || field]; + if (value !== "NULL") { + frm.set_value(field, value); + } +}; + frappe.ui.form.on("Lead", { custom_upload_business_card(frm) { if (frm.selected_doc.custom_upload_business_card) { @@ -16,27 +23,29 @@ frappe.ui.form.on("Lead", { freeze: true, freeze_message: "Transmuting Pixels into Insights... Hold Tight!", callback(res) { - const resArr = res.message.split("\n"); - - const first_name = resArr[0].split(":")[1].trim(); - const middle_name = resArr[1].split(":")[1].trim(); - const last_name = resArr[2].split(":")[1].trim(); - first_name !== "NULL" && frm.set_value("first_name", first_name); - middle_name !== "NULL" && frm.set_value("middle_name", middle_name); - last_name !== "NULL" && frm.set_value("last_name", last_name); - const company_name = resArr[8].split(":")[1].trim(); - company_name !== "NULL" && - frm.set_value("company_name", company_name); - const designation = resArr[5].split(":")[1].trim(); - designation !== "NULL" && frm.set_value("job_title", designation); - const email_ids = resArr[7].split(":")[1].trim().split(","); - frm.set_value("email_id", email_ids[0] || ""); + const data = res.message; - const mobile_no = resArr[11].split(":")[1].trim(); - mobile_no !== "NULL" && frm.set_value("mobile_no", mobile_no); - const phone = resArr[12].split(":")[1].trim(); - phone !== "NULL" && frm.set_value("phone", phone); + mapFieldValue(frm, data, "first_name"); + mapFieldValue(frm, data, "middle_name"); + mapFieldValue(frm, data, "last_name"); + mapFieldValue(frm, data, "company_name"); + mapFieldValue(frm, data, "job_title", "designation"); + mapFieldValue(frm, data, "mobile_no", "mobile_number"); + mapFieldValue(frm, data, "phone", "phone_number"); + mapFieldValue(frm, data, "website"); + mapFieldValue(frm, data, "city"); + mapFieldValue(frm, data, "state"); + frm.set_value("email_id", data.email_ids[0] || ""); + const country = data.country; + frappe.db.exists("Country", country).then((country_exists) => { + if (country_exists) { + frm.set_value("country", country); + } else { + frm.set_value("country", ""); + } + }); + frm.refresh_field("country"); const possibleGenders = [ "Male", "Female", @@ -46,7 +55,7 @@ frappe.ui.form.on("Lead", { "Transgender", "Other", ]; - let gender = resArr[3].split(":")[1].trim(); + let gender = data.gender; gender = gender.charAt(0).toUpperCase() + gender.slice(1); gender !== "NULL" && possibleGenders.includes(gender) && @@ -64,7 +73,7 @@ frappe.ui.form.on("Lead", { "Master", "Prof", ]; - let salutation = resArr[4].split(":")[1].trim(); + let salutation = data.salutation; salutation = salutation.charAt(0).toUpperCase() + salutation.slice( @@ -77,25 +86,6 @@ frappe.ui.form.on("Lead", { possibleSalutations.includes(salutation) && frm.set_value("salutation", salutation); frm.refresh_field("salutation"); - - let website = resArr[9].split(":")[1].trim(); - frm.set_value("website", website); - - const city = resArr[13].split(":")[1].trim(); - city !== "NULL" && frm.set_value("city", city); - - const state = resArr[14].split(":")[1].trim(); - state !== "NULL" && frm.set_value("state", state); - - const country = resArr[15].split(":")[1].trim(); - frappe.db.exists("Country", country).then((country_exists) => { - if (country_exists) { - frm.set_value("country", country); - } else { - frm.set_value("country", ""); - } - }); - frm.refresh_field("country"); }, }); }