diff --git a/README.md b/README.md
index d3a2767..53f52ac 100644
--- a/README.md
+++ b/README.md
@@ -15,10 +15,13 @@ AutoInscribe is a tool for simplifying OCR that is built using [Frappe Framework
-## Pre-Requisites to be installed
+## Pre-Requisites
1. [Frappe Framework](https://frappeframework.com) - v15 or above
2. [ERPNext](https://erpnext.com/) - v14 or above
+3. [OpenAI Account](https://platform.openai.com/) - First, create an OpenAI account or sign in. Next, navigate to the API key page and "Create new secret key", optionally naming the key.
+4. [Google Vision API](https://console.cloud.google.com/marketplace/product/google/vision.googleapis.com) - Login to your Google Cloud Console and create a new project or select the existing one from under the Project tab. When the project is opened, click Navigation Menu and select “API & Services > Dashboard”. Now you need to enable Cloud Vision API. To do this, click the “ENABLE APIS AND SERVICES” button. In the search bar, search for Cloud Vision API and click it to enable. Now you need to create Google Cloud Vision key. To do this, click Navigation menu, select “IAM & admin > Service accounts”. In the window that opens, click “Create Service Account”.
+Set up the name, ID and optionally add the description. In the next step, set up a role or leave it by default and click “Continue”. In the last step, optionally grant users access to this service account and create the key. In the menu “Service accounts for project “Project Name”, click “Actions > Create key”. In the window that opens, select “JSON” as the key format and click “Create”. You will be prompted to automatically download the key.
diff --git a/autoinscribe/autoinscribe/doctype/autoinscribe_settings/autoinscribe_settings.json b/autoinscribe/autoinscribe/doctype/autoinscribe_settings/autoinscribe_settings.json
index 442c511..c1c10a1 100644
--- a/autoinscribe/autoinscribe/doctype/autoinscribe_settings/autoinscribe_settings.json
+++ b/autoinscribe/autoinscribe/doctype/autoinscribe_settings/autoinscribe_settings.json
@@ -7,11 +7,13 @@
"field_order": [
"openai_gpt_key",
"vision_client_email",
+ "column_break_ymha",
"vision_project_id",
"vision_token_uri"
],
"fields": [
{
+ "description": "Key is encrypted for security reasons",
"fieldname": "openai_gpt_key",
"fieldtype": "Password",
"in_list_view": 1,
@@ -36,12 +38,16 @@
"fieldtype": "Data",
"label": "Vision Token URI",
"reqd": 1
+ },
+ {
+ "fieldname": "column_break_ymha",
+ "fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2023-12-22 13:23:45.489945",
+ "modified": "2024-01-03 16:24:32.354396",
"modified_by": "Administrator",
"module": "AutoInscribe",
"name": "AutoInscribe Settings",
@@ -60,5 +66,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
- "states": []
+ "states": [],
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/autoinscribe/fixtures/client_script.json b/autoinscribe/fixtures/client_script.json
index 7cad506..becbcde 100644
--- a/autoinscribe/fixtures/client_script.json
+++ b/autoinscribe/fixtures/client_script.json
@@ -4,10 +4,10 @@
"doctype": "Client Script",
"dt": "Contact",
"enabled": 1,
- "modified": "2023-12-22 10:44:28.411551",
+ "modified": "2024-01-02 16:56:34.580365",
"module": "AutoInscribe",
"name": "Extract Text From Image & Fill Contact Details",
- "script": "frappe.ui.form.on('Contact', {\n custom_upload_image(frm) {\n if(frm.selected_doc.custom_upload_image) {\n frappe.call({\n method: \"autoinscribe.inscribe.api.extract_text_from_img\",\n args: {\n 'img_url': window.location.href.split('/app')[0] + frm.selected_doc.custom_upload_image\n },\n callback(res) {\n const resArr = res.message.split('\\n')\n\n const first_name = resArr[0].split(':')[1].trim()\n const middle_name = resArr[1].split(':')[1].trim()\n const last_name = resArr[2].split(':')[1].trim()\n first_name !== \"NULL\" && frm.set_value('first_name', first_name)\n middle_name !== \"NULL\" && frm.set_value('middle_name', middle_name)\n last_name !== \"NULL\" && frm.set_value('last_name', last_name)\n const company_name = resArr[8].split(':')[1].trim()\n company_name !== \"NULL\" && frm.set_value('company_name', company_name)\n const designation = resArr[5].split(':')[1].trim()\n designation !== \"NULL\" && frm.set_value('designation', designation)\n const email_ids = resArr[7].split(':')[1].trim().split(',')\n email_ids.forEach(email => {\n email.trim() !== \"NULL\" && frm.add_child('email_ids', {\n email_id: email.trim()\n })\n })\n frm.refresh_field('email_ids')\n const contact_numbers = resArr[6].split(':')[1].trim().split(',')\n contact_numbers.forEach(phone_no => {\n phone_no.trim() !== \"NULL\" && frm.add_child('phone_nos', {\n phone: phone_no.trim()\n })\n })\n frm.refresh_field('phone_nos')\n \n let gender = resArr[3].split(':')[1].trim()\n gender = gender.charAt(0).toUpperCase() + gender.slice(1)\n frappe.db.exists(\"Gender\", gender).then(gender_exists => {\n if(gender_exists) {\n frm.set_value(\"gender\", gender)\n } \n })\n frm.refresh_field('gender')\n let salutation = resArr[4].split(':')[1].trim()\n salutation = salutation.charAt(0).toUpperCase() + salutation.slice(1, salutation[salutation.length-1] === '.' ? salutation.length-1 : salutation.length)\n frappe.db.exists(\"Salutation\", salutation).then(salutation_exists => {\n if (salutation_exists) {\n frm.set_value(\"salutation\", salutation)\n }\n })\n frm.refresh_field('salutation')\n \n const address = resArr[10].split(':')[1].trim()\n if (address !== \"NULL\") {\n frappe.call({\n method: \"autoinscribe.inscribe.api.create_address\",\n args: {\n 'address': address\n },\n callback(res) {\n if(res.message) {\n frm.set_value('address', `${address}-Office`)\n }\n }\n }) \n }\n }\n })\n }\n }\n})",
+ "script": "let once_refreshed = false\nlet error_encountered = false\n\nfrappe.ui.form.on('Contact', {\n custom_upload_image(frm) {\n if(frm.selected_doc.custom_upload_image) {\n frappe.call({\n method: \"autoinscribe.inscribe.api.extract_text_from_img\",\n args: {\n 'img_url': window.location.href.split('/app')[0] + frm.selected_doc.custom_upload_image\n },\n callback(res) {\n const resArr = res.message.split('\\n')\n\n const first_name = resArr[0].split(':')[1].trim()\n const middle_name = resArr[1].split(':')[1].trim()\n const last_name = resArr[2].split(':')[1].trim()\n first_name !== \"NULL\" && frm.set_value('first_name', first_name)\n middle_name !== \"NULL\" && frm.set_value('middle_name', middle_name)\n last_name !== \"NULL\" && frm.set_value('last_name', last_name)\n const company_name = resArr[8].split(':')[1].trim()\n company_name !== \"NULL\" && frm.set_value('company_name', company_name)\n const designation = resArr[5].split(':')[1].trim()\n designation !== \"NULL\" && frm.set_value('designation', designation)\n const email_ids = resArr[7].split(':')[1].trim().split(',')\n email_ids.forEach(email => {\n email.trim() !== \"NULL\" && frm.add_child('email_ids', {\n email_id: email.trim()\n })\n })\n frm.refresh_field('email_ids')\n const contact_numbers = resArr[6].split(':')[1].trim().split(',')\n contact_numbers.forEach(phone_no => {\n phone_no.trim() !== \"NULL\" && frm.add_child('phone_nos', {\n phone: phone_no.trim()\n })\n })\n frm.refresh_field('phone_nos')\n \n let gender = resArr[3].split(':')[1].trim()\n gender = gender.charAt(0).toUpperCase() + gender.slice(1)\n frappe.db.exists(\"Gender\", gender).then(gender_exists => {\n if(gender_exists) {\n frm.set_value(\"gender\", gender)\n } \n })\n frm.refresh_field('gender')\n let salutation = resArr[4].split(':')[1].trim()\n salutation = salutation.charAt(0).toUpperCase() + salutation.slice(1, salutation[salutation.length-1] === '.' ? salutation.length-1 : salutation.length)\n frappe.db.exists(\"Salutation\", salutation).then(salutation_exists => {\n if (salutation_exists) {\n frm.set_value(\"salutation\", salutation)\n }\n })\n frm.refresh_field('salutation')\n \n const address = resArr[10].split(':')[1].trim()\n if (address !== \"NULL\") {\n frappe.call({\n method: \"autoinscribe.inscribe.api.create_address\",\n args: {\n 'address': address\n },\n callback(res) {\n if(res.message) {\n frm.set_value('address', `${address}-Office`)\n }\n }\n }) \n }\n },\n error: function(r) {\n error_encountered = true\n },\n })\n }\n },\n refresh(frm) {\n if (error_encountered && !once_refreshed) {\n frappe.msgprint(\"Please enter a valid OpenAI API key in AutoInscribe Settings\", title=\"Missing OpenAI API Key\", indicator=\"red\")\n once_refreshed = true\n }\n }\n})",
"view": "Form"
},
{
@@ -15,10 +15,10 @@
"doctype": "Client Script",
"dt": "Lead",
"enabled": 1,
- "modified": "2023-12-22 10:44:04.681492",
+ "modified": "2024-01-02 16:51:45.882969",
"module": "AutoInscribe",
"name": "Extract Text From Image & Fill Lead Details",
- "script": "frappe.ui.form.on('Lead', {\n custom_upload_business_card(frm) {\n if(frm.selected_doc.custom_upload_business_card) {\n frappe.call({\n method: \"autoinscribe.inscribe.api.extract_text_from_img\",\n args: {\n 'img_url': window.location.href.split('/app')[0] + frm.selected_doc.custom_upload_business_card\n },\n callback(res) {\n const resArr = res.message.split('\\n')\n\n const first_name = resArr[0].split(':')[1].trim()\n const middle_name = resArr[1].split(':')[1].trim()\n const last_name = resArr[2].split(':')[1].trim()\n first_name !== \"NULL\" && frm.set_value('first_name', first_name)\n middle_name !== \"NULL\" && frm.set_value('middle_name', middle_name)\n last_name !== \"NULL\" && frm.set_value('last_name', last_name)\n const company_name = resArr[8].split(':')[1].trim()\n company_name !== \"NULL\" && frm.set_value('company_name', company_name)\n const designation = resArr[5].split(':')[1].trim()\n designation !== \"NULL\" && frm.set_value('job_title', designation)\n const email_ids = resArr[7].split(':')[1].trim().split(',')\n frm.set_value('email_id', email_ids[0] || '')\n\n const mobile_no = resArr[11].split(':')[1].trim()\n mobile_no !== \"NULL\" && frm.set_value('mobile_no', mobile_no)\n const phone = resArr[12].split(':')[1].trim()\n phone !== \"NULL\" && frm.set_value('phone', phone)\n \n const possibleGenders = [\"Male\", \"Female\", \"Prefer not to say\", \"Non-Conforming\", \"Genderqueer\", \"Transgender\", \"Other\"]\n let gender = resArr[3].split(':')[1].trim()\n gender = gender.charAt(0).toUpperCase() + gender.slice(1)\n gender !== \"NULL\" && possibleGenders.includes(gender) && frm.set_value(\"gender\", gender)\n frm.refresh_field('gender')\n \n const possibleSalutations = [\"Mr\", \"Ms\", \"Mx\", \"Dr\", \"Mrs\", \"Madam\", \"Miss\", \"Master\", \"Prof\"]\n let salutation = resArr[4].split(':')[1].trim()\n salutation = salutation.charAt(0).toUpperCase() + salutation.slice(1, salutation[salutation.length-1] === '.' ? salutation.length-1 : salutation.length)\n salutation !== \"NULL\" && possibleSalutations.includes(salutation) && frm.set_value(\"salutation\", salutation)\n frm.refresh_field('salutation')\n \n let website = resArr[9].split(':')[1].trim()\n frm.set_value(\"website\", website)\n \n const city = resArr[13].split(':')[1].trim()\n city !== \"NULL\" && frm.set_value('city', city)\n \n const state = resArr[14].split(':')[1].trim()\n state !== \"NULL\" && frm.set_value('state', state)\n \n const country = resArr[15].split(':')[1].trim()\n frappe.db.exists(\"Country\", country).then(country_exists => {\n if (country_exists) {\n frm.set_value(\"country\", country)\n } else {\n frm.set_value(\"country\", \"\")\n }\n })\n frm.refresh_field('country')\n }\n })\n }\n }\n})",
+ "script": "frappe.ui.form.on('Lead', {\n custom_upload_business_card(frm) {\n if(frm.selected_doc.custom_upload_business_card) {\n frappe.call({\n method: \"autoinscribe.inscribe.api.extract_text_from_img\",\n args: {\n 'img_url': window.location.href.split('/app')[0] + frm.selected_doc.custom_upload_business_card\n },\n callback(res) {\n const resArr = res.message.split('\\n')\n\n const first_name = resArr[0].split(':')[1].trim()\n const middle_name = resArr[1].split(':')[1].trim()\n const last_name = resArr[2].split(':')[1].trim()\n first_name !== \"NULL\" && frm.set_value('first_name', first_name)\n middle_name !== \"NULL\" && frm.set_value('middle_name', middle_name)\n last_name !== \"NULL\" && frm.set_value('last_name', last_name)\n const company_name = resArr[8].split(':')[1].trim()\n company_name !== \"NULL\" && frm.set_value('company_name', company_name)\n const designation = resArr[5].split(':')[1].trim()\n designation !== \"NULL\" && frm.set_value('job_title', designation)\n const email_ids = resArr[7].split(':')[1].trim().split(',')\n frm.set_value('email_id', email_ids[0] || '')\n\n const mobile_no = resArr[11].split(':')[1].trim()\n mobile_no !== \"NULL\" && frm.set_value('mobile_no', mobile_no)\n const phone = resArr[12].split(':')[1].trim()\n phone !== \"NULL\" && frm.set_value('phone', phone)\n \n const possibleGenders = [\"Male\", \"Female\", \"Prefer not to say\", \"Non-Conforming\", \"Genderqueer\", \"Transgender\", \"Other\"]\n let gender = resArr[3].split(':')[1].trim()\n gender = gender.charAt(0).toUpperCase() + gender.slice(1)\n gender !== \"NULL\" && possibleGenders.includes(gender) && frm.set_value(\"gender\", gender)\n frm.refresh_field('gender')\n \n const possibleSalutations = [\"Mr\", \"Ms\", \"Mx\", \"Dr\", \"Mrs\", \"Madam\", \"Miss\", \"Master\", \"Prof\"]\n let salutation = resArr[4].split(':')[1].trim()\n salutation = salutation.charAt(0).toUpperCase() + salutation.slice(1, salutation[salutation.length-1] === '.' ? salutation.length-1 : salutation.length)\n salutation !== \"NULL\" && possibleSalutations.includes(salutation) && frm.set_value(\"salutation\", salutation)\n frm.refresh_field('salutation')\n \n let website = resArr[9].split(':')[1].trim()\n frm.set_value(\"website\", website)\n \n const city = resArr[13].split(':')[1].trim()\n city !== \"NULL\" && frm.set_value('city', city)\n \n const state = resArr[14].split(':')[1].trim()\n state !== \"NULL\" && frm.set_value('state', state)\n \n const country = resArr[15].split(':')[1].trim()\n frappe.db.exists(\"Country\", country).then(country_exists => {\n if (country_exists) {\n frm.set_value(\"country\", country)\n } else {\n frm.set_value(\"country\", \"\")\n }\n })\n frm.refresh_field('country')\n },\n })\n }\n },\n})",
"view": "Form"
}
]
\ No newline at end of file
diff --git a/autoinscribe/inscribe/api.py b/autoinscribe/inscribe/api.py
index 4a9ba07..43cb306 100644
--- a/autoinscribe/inscribe/api.py
+++ b/autoinscribe/inscribe/api.py
@@ -37,16 +37,19 @@ def get_vision_token_uri():
@frappe.whitelist()
def ask_gpt(prompt):
- chat_completion = gpt_client.chat.completions.create(
- messages=[
- {
- "role": "user",
- "content": prompt,
- }
- ],
- model="gpt-3.5-turbo-1106",
- )
- return chat_completion.choices[0].message.content.strip()
+ try:
+ chat_completion = gpt_client.chat.completions.create(
+ messages=[
+ {
+ "role": "user",
+ "content": prompt,
+ }
+ ],
+ model="gpt-3.5-turbo-1106",
+ )
+ return chat_completion.choices[0].message.content.strip()
+ except Exception as e:
+ frappe.throw("Please enter a valid OpenAI API key in AutoInscribe Settings")
@frappe.whitelist()
diff --git a/screenshots/autoinscribe-settings.png b/screenshots/autoinscribe-settings.png
index 218d27c..46ff18c 100644
Binary files a/screenshots/autoinscribe-settings.png and b/screenshots/autoinscribe-settings.png differ