From f281a663dbbd7a3be75c70f033354c6a1d96a629 Mon Sep 17 00:00:00 2001 From: Alex Litchfield Date: Wed, 20 Sep 2023 14:52:53 -0400 Subject: [PATCH 01/16] Variable Type changes --- .gitignore | 4 ++-- autofill/autofillScript.ts | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 31b57b4..dbfcafb 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,8 @@ extension/* # Node # dependencies -react-chrome-extension/node_modules -react-chrome-extension/.pnp +node_modules +.pnp # testing react-chrome-extension/coverage diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index a4a2c6f..4460871 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,8 +1,12 @@ // This file will be run on the content page, and should include all the logic for inserting text into form items. -const usernameField = document.querySelector('input[name="username"]'); -const passwordField = document.querySelector('input[name="password"]'); +const firstNameField = document.querySelector('input[name="First Name"]'); +const lastNameField = document.querySelector('input[name="Last Name"]'); +const emailField = document.querySelector('input[name="Email"]'); +//Figure out how to do a phone number field -if (usernameField) (usernameField as HTMLInputElement).value = "yourUsername"; -if (passwordField) (passwordField as HTMLInputElement).value = "yourPassword"; +if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; +if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; +if (emailField) (emailField as HTMLInputElement).value = "yourEmail"; +//Figure out how to do a phone number field export {} From 861761b20409c44f115eb9d4ef3bb0738585b56e Mon Sep 17 00:00:00 2001 From: Alex Litchfield Date: Wed, 20 Sep 2023 14:52:53 -0400 Subject: [PATCH 02/16] Variable Type changes --- autofill/autofillScript.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index a4a2c6f..4460871 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,8 +1,12 @@ // This file will be run on the content page, and should include all the logic for inserting text into form items. -const usernameField = document.querySelector('input[name="username"]'); -const passwordField = document.querySelector('input[name="password"]'); +const firstNameField = document.querySelector('input[name="First Name"]'); +const lastNameField = document.querySelector('input[name="Last Name"]'); +const emailField = document.querySelector('input[name="Email"]'); +//Figure out how to do a phone number field -if (usernameField) (usernameField as HTMLInputElement).value = "yourUsername"; -if (passwordField) (passwordField as HTMLInputElement).value = "yourPassword"; +if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; +if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; +if (emailField) (emailField as HTMLInputElement).value = "yourEmail"; +//Figure out how to do a phone number field export {} From 67794060059c43f0ce5fea49ad88cf9709247671 Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 22 Sep 2023 17:43:03 -0400 Subject: [PATCH 03/16] Added tests for universal autofill via keyword, checkboxes, dropdowns --- autofill/autofillScript.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 4460871..54b3b1f 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,12 +1,25 @@ // This file will be run on the content page, and should include all the logic for inserting text into form items. const firstNameField = document.querySelector('input[name="First Name"]'); const lastNameField = document.querySelector('input[name="Last Name"]'); -const emailField = document.querySelector('input[name="Email"]'); -//Figure out how to do a phone number field +// Gets all input fields that contain keyword "email" +const emailField = document.querySelectorAll('input[id*="email"]'); + +//Figure out how to do a phone number field if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; -if (emailField) (emailField as HTMLInputElement).value = "yourEmail"; + +// Sets all email fields to "yourEmail" as long as field ID contains "email" +for (let i = 0; i < emailField.length; i++) + if (emailField[i]) (emailField[i] as HTMLInputElement).value = "yourEmail"; //Figure out how to do a phone number field +// Trigger agree to terms and conditions. Tested on "https://store.steampowered.com/join" but should work on any site with a checkbox with the word "agree" in the name. Proof of concept for checkboxes +const agreeToTerms = document.querySelector('input[name*="agree"]'); +if (agreeToTerms) (agreeToTerms as HTMLInputElement).checked = true; + +// Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns +const dropdown = document.querySelector('select');; +if (dropdown) (dropdown as HTMLSelectElement).value = "ALB"; + export {} From b623ee54208e88945fa75e8c959f0cc4f0599dae Mon Sep 17 00:00:00 2001 From: Alex Litchfield Date: Wed, 20 Sep 2023 14:52:53 -0400 Subject: [PATCH 04/16] Variable Type changes --- autofill/autofillScript.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index a4a2c6f..4460871 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,8 +1,12 @@ // This file will be run on the content page, and should include all the logic for inserting text into form items. -const usernameField = document.querySelector('input[name="username"]'); -const passwordField = document.querySelector('input[name="password"]'); +const firstNameField = document.querySelector('input[name="First Name"]'); +const lastNameField = document.querySelector('input[name="Last Name"]'); +const emailField = document.querySelector('input[name="Email"]'); +//Figure out how to do a phone number field -if (usernameField) (usernameField as HTMLInputElement).value = "yourUsername"; -if (passwordField) (passwordField as HTMLInputElement).value = "yourPassword"; +if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; +if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; +if (emailField) (emailField as HTMLInputElement).value = "yourEmail"; +//Figure out how to do a phone number field export {} From c551cfb053382d527124c8b558d37be1cdfdf66c Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 22 Sep 2023 17:43:03 -0400 Subject: [PATCH 05/16] Added tests for universal autofill via keyword, checkboxes, dropdowns --- autofill/autofillScript.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 4460871..54b3b1f 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,12 +1,25 @@ // This file will be run on the content page, and should include all the logic for inserting text into form items. const firstNameField = document.querySelector('input[name="First Name"]'); const lastNameField = document.querySelector('input[name="Last Name"]'); -const emailField = document.querySelector('input[name="Email"]'); -//Figure out how to do a phone number field +// Gets all input fields that contain keyword "email" +const emailField = document.querySelectorAll('input[id*="email"]'); + +//Figure out how to do a phone number field if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; -if (emailField) (emailField as HTMLInputElement).value = "yourEmail"; + +// Sets all email fields to "yourEmail" as long as field ID contains "email" +for (let i = 0; i < emailField.length; i++) + if (emailField[i]) (emailField[i] as HTMLInputElement).value = "yourEmail"; //Figure out how to do a phone number field +// Trigger agree to terms and conditions. Tested on "https://store.steampowered.com/join" but should work on any site with a checkbox with the word "agree" in the name. Proof of concept for checkboxes +const agreeToTerms = document.querySelector('input[name*="agree"]'); +if (agreeToTerms) (agreeToTerms as HTMLInputElement).checked = true; + +// Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns +const dropdown = document.querySelector('select');; +if (dropdown) (dropdown as HTMLSelectElement).value = "ALB"; + export {} From 97cc32ca4c46a2512d4e6970ae7a1195bc0794c2 Mon Sep 17 00:00:00 2001 From: Ariel Montero Date: Sat, 23 Sep 2023 00:07:03 -0400 Subject: [PATCH 06/16] add loop and funcrionautofill fields based on its closest label Created a function to find the closest label to the passed input field. Then used a loop to iterate through all the input fields and fill them with their closest label. Still very buggy and in testing phase. --- autofill/autofillScript.ts | 42 +++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 54b3b1f..4fe660f 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,3 +1,18 @@ +// Very basic function to find closest label to input field. Used for testing below +function labelDist(labels: Element[], input: Element): Element { + let minDist = Number.MAX_VALUE; + let minLabel = labels[0]; + for (let i = 0; i < labels.length; i++) { + let dist = Math.abs(labels[i].getBoundingClientRect().top - input.getBoundingClientRect().top); + if (dist < minDist) { + minDist = dist; + minLabel = labels[i]; + } + } + return minLabel; +} + + // This file will be run on the content page, and should include all the logic for inserting text into form items. const firstNameField = document.querySelector('input[name="First Name"]'); const lastNameField = document.querySelector('input[name="Last Name"]'); @@ -5,14 +20,13 @@ const lastNameField = document.querySelector('input[name="Last Name"]'); // Gets all input fields that contain keyword "email" const emailField = document.querySelectorAll('input[id*="email"]'); -//Figure out how to do a phone number field if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; // Sets all email fields to "yourEmail" as long as field ID contains "email" -for (let i = 0; i < emailField.length; i++) +/*for (let i = 0; i < emailField.length; i++) if (emailField[i]) (emailField[i] as HTMLInputElement).value = "yourEmail"; -//Figure out how to do a phone number field + */ // Trigger agree to terms and conditions. Tested on "https://store.steampowered.com/join" but should work on any site with a checkbox with the word "agree" in the name. Proof of concept for checkboxes const agreeToTerms = document.querySelector('input[name*="agree"]'); @@ -22,4 +36,26 @@ if (agreeToTerms) (agreeToTerms as HTMLInputElement).checked = true; const dropdown = document.querySelector('select');; if (dropdown) (dropdown as HTMLSelectElement).value = "ALB"; + + +// Testing, fill all input fields with its own label text + +// Get all labels, convert to array +const labels = document.querySelectorAll('label'); +const labelArray = Array.from(labels); + +// Get all input fields +const inputs = document.querySelectorAll('input'); + +let label; + +// For each input field, find closest label and set input field to label text. Currently bugged for non labeled input fields +for (let i = 0; i < inputs.length; i++) { + label = labelDist(labelArray, inputs[i]); + label = label?.textContent; + if (label) (inputs[i] as HTMLInputElement).value = label; + +} + + export {} From 3b561a386a8db475d62d3a27803cf97a32ab0da3 Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 29 Sep 2023 17:11:54 -0400 Subject: [PATCH 07/16] Starts to combine LLM and injection New scripts to find fields and uses LLM to fill them --- .env | 2 + .env.example | 2 + autofill/autofillScript.ts | 127 +++++- autofill/llm.ts | 3 + package-lock.json | 883 +++++++++++++++++++++++++++++++++++++ package.json | 3 + tsconfig.json | 2 +- webpack.config.js | 5 +- 8 files changed, 1022 insertions(+), 5 deletions(-) create mode 100644 .env create mode 100644 .env.example create mode 100644 autofill/llm.ts diff --git a/.env b/.env new file mode 100644 index 0000000..4cfd813 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +# Enter your openai key here +OPENAI_API_KEY=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 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2fe936a --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +# Enter your openai key here +OPENAI_API_KEY=Your_OpenAI_api_key_here diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 4fe660f..5077955 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,4 +1,4 @@ -// Very basic function to find closest label to input field. Used for testing below +/*// Very basic function to find closest label to input field. Used for testing below function labelDist(labels: Element[], input: Element): Element { let minDist = Number.MAX_VALUE; let minLabel = labels[0]; @@ -24,9 +24,8 @@ if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName" if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; // Sets all email fields to "yourEmail" as long as field ID contains "email" -/*for (let i = 0; i < emailField.length; i++) +for (let i = 0; i < emailField.length; i++) if (emailField[i]) (emailField[i] as HTMLInputElement).value = "yourEmail"; - */ // Trigger agree to terms and conditions. Tested on "https://store.steampowered.com/join" but should work on any site with a checkbox with the word "agree" in the name. Proof of concept for checkboxes const agreeToTerms = document.querySelector('input[name*="agree"]'); @@ -59,3 +58,125 @@ for (let i = 0; i < inputs.length; i++) { export {} +*/ + +import { AIMessage, BaseMessage, ChatMessage, HumanMessage, SystemMessage } from "langchain/schema"; +import { chatModel } from "./llm"; +import{ backOff }from "exponential-backoff"; + + + +// Very basic function to find closest label to input field. Used for testing below +function labelDist(labels: Element[], input: Element): Element { + let minDist = Number.MAX_VALUE; + let minLabel = labels[0]; + for (let i = 0; i < labels.length; i++) { + let dist = Math.abs(labels[i].getBoundingClientRect().top - input.getBoundingClientRect().top); + if (dist < minDist) { + minDist = dist; + minLabel = labels[i]; + } + } + return minLabel; +} + +function fieldDist(fields: Element[], input: Element): Element { + let minDist = Number.MAX_VALUE; + let minField = fields[0]; + for (let i = 0; i < fields.length; i++) { + let dist = Math.abs(fields[i].getBoundingClientRect().top - input.getBoundingClientRect().top); + if (dist < minDist) { + minDist = dist; + minField = fields[i]; + } + } + return minField; +} + +function labelDict(labels: Element[], fields: Element[], map: Map){ + let emptyElement = document.createElement("input"); + for (let i = 0; i < fields.length; i++){ + let label = labelDist(labels, fields[i]); + if(fields[i] == fieldDist(fields, label)){ + map.set(fields[i], label); + } + else{ + map.set(fields[i], map.get(fields[i-1] || emptyElement)); + } + } +} + +const user = { + name: "samir sam beall", + email: "samir.beall@gmail.com", + address: "1999 Burdett Ave, Troy, NY 12180", + phone_number: "(123) 456-78910", + zip: "12180", + none: "none" +}; + +async function main (){ + + let labelMap = new Map(); + labelDict(Array.from(document.querySelectorAll('label')), Array.from(document.querySelectorAll('input')), labelMap); + + let template_text = "I will give you an input field and you choose which response best fits the fields label. The data you will select form exclusively comes from: "; + + template_text += JSON.stringify(user) + + console.log(template_text); + + let messages = [new SystemMessage({ content: template_text })]; + + messages.push(new HumanMessage({content: "First Name"})); + messages.push(new AIMessage({content: "Samir"})); + + messages.push(new HumanMessage({content: "Address"})); + messages.push(new AIMessage({content: "1999 Burdette Ave"})); + // + messages.push(new HumanMessage({content: "Middle Name"})); + messages.push(new AIMessage({content: "Sam"})); + + const inputFields = document.querySelectorAll('input'); + const questionsAndFields: { question: string, field: HTMLInputElement }[] = []; + + inputFields.forEach((inputField: HTMLInputElement) => { + const label = document.querySelector(`label[for="${inputField.id}"]`); + if (label) { + questionsAndFields.push({ + question: label.textContent || '', + field: inputField + }); + } + }); + + console.log(questionsAndFields); + + messages.push(new HumanMessage({content: "placeholder"})) + + + + for (const qf of questionsAndFields){ + + console.log("querying chat") + messages[7] = new HumanMessage({content: qf.question}); + + let chatModelResult = chatModel.predictMessages(messages); + + chatModelResult.then((resolvedResponse: BaseMessage) => { + console.log("chat result: ") + console.log(chatModelResult); + + qf.field.value = resolvedResponse.content; + }) + // messages.push(chatModelResult); + + } + + console.log(messages); +} + +main(); + + +export {} \ No newline at end of file diff --git a/autofill/llm.ts b/autofill/llm.ts new file mode 100644 index 0000000..798cf07 --- /dev/null +++ b/autofill/llm.ts @@ -0,0 +1,3 @@ +import { ChatOpenAI } from "langchain/chat_models/openai"; + +export const chatModel = new ChatOpenAI({openAIApiKey: process.env.OPENAI_API_KEY, temperature: 0}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5f02a38..7e61e71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,9 @@ "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", "bootstrap": "^5.3.2", + "dotenv-webpack": "^8.0.1", + "exponential-backoff": "^3.1.1", + "langchain": "^0.0.154", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", @@ -68,6 +71,26 @@ "node": ">=6.0.0" } }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.6.2.tgz", + "integrity": "sha512-fB9PUj9RFT+XjkL+E9Ol864ZIJi+1P8WnbHspN3N3/GK2uSzjd0cbVIKTGgf4v3N8MwaQu+UWnU7C4BG/fap/g==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { + "version": "18.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.0.tgz", + "integrity": "sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw==" + }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -5353,6 +5376,28 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.3.tgz", "integrity": "sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==" }, + "node_modules/@types/node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -5477,6 +5522,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" }, + "node_modules/@types/uuid": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz", + "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==" + }, "node_modules/@types/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", @@ -5911,6 +5961,17 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -6009,6 +6070,17 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -6679,6 +6751,30 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -6715,6 +6811,11 @@ "node": ">=8" } }, + "node_modules/binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -7004,6 +7105,14 @@ "node": ">=10" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", @@ -7529,6 +7638,14 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -7966,6 +8083,14 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decimal.js": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", @@ -8158,6 +8283,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8310,11 +8444,41 @@ "node": ">=10" } }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-defaults/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "node_modules/dotenv-webpack": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz", + "integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==", + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -9289,6 +9453,14 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -9459,6 +9631,16 @@ "node": ">=8" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, + "node_modules/expr-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expr-eval/-/expr-eval-2.0.2.tgz", + "integrity": "sha512-4EMSHGOPSwAfBiibw3ndnP0AvjDWLsMvGOvWEZ2F96IGk0bIVdjQisOHxReSkE13mHcfbuCiXw+G4y0zv6N8Eg==" + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -9732,6 +9914,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", @@ -9946,6 +10136,23 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10583,6 +10790,14 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -10752,6 +10967,11 @@ "node": ">= 10" } }, + "node_modules/is-any-array": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz", + "integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==" + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -10836,6 +11056,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -15523,6 +15748,14 @@ "jiti": "bin/jiti.js" } }, + "node_modules/js-tiktoken": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.7.tgz", + "integrity": "sha512-biba8u/clw7iesNEWLOLwrNGoBP2lA+hTaBLs/D45pJdUPFXyxD6nhcDVtADChghv4GgyAiMKYMiRx7x6h7Biw==", + "dependencies": { + "base64-js": "^1.5.1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -15719,6 +15952,453 @@ "node": ">= 8" } }, + "node_modules/langchain": { + "version": "0.0.154", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.0.154.tgz", + "integrity": "sha512-BnUvUZ9OBL/0BM4jhy53H8RF8+AmisrJq3tvNks6U/ueFC9ZKG9r4U9zqjwM2dTaWjW+oN3ig83Ioa9Y7d6ZFw==", + "dependencies": { + "@anthropic-ai/sdk": "^0.6.2", + "ansi-styles": "^5.0.0", + "binary-extensions": "^2.2.0", + "camelcase": "6", + "decamelize": "^1.2.0", + "expr-eval": "^2.0.2", + "flat": "^5.0.2", + "js-tiktoken": "^1.0.7", + "js-yaml": "^4.1.0", + "jsonpointer": "^5.0.1", + "langchainhub": "~0.0.6", + "langsmith": "~0.0.31", + "ml-distance": "^4.0.0", + "object-hash": "^3.0.0", + "openai": "~4.4.0", + "openapi-types": "^12.1.3", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0", + "yaml": "^2.2.1", + "zod": "^3.21.4", + "zod-to-json-schema": "^3.20.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@aws-crypto/sha256-js": "^5.0.0", + "@aws-sdk/client-dynamodb": "^3.310.0", + "@aws-sdk/client-kendra": "^3.352.0", + "@aws-sdk/client-lambda": "^3.310.0", + "@aws-sdk/client-s3": "^3.310.0", + "@aws-sdk/client-sagemaker-runtime": "^3.310.0", + "@aws-sdk/client-sfn": "^3.310.0", + "@aws-sdk/credential-provider-node": "^3.388.0", + "@aws-sdk/protocol-http": "^3.374.0", + "@aws-sdk/signature-v4": "^3.374.0", + "@azure/storage-blob": "^12.15.0", + "@clickhouse/client": "^0.0.14", + "@cloudflare/workers-types": "^4.20230904.0", + "@elastic/elasticsearch": "^8.4.0", + "@getmetal/metal-sdk": "*", + "@getzep/zep-js": "^0.7.0", + "@gomomento/sdk": "^1.23.0", + "@google-ai/generativelanguage": "^0.2.1", + "@google-cloud/storage": "^6.10.1", + "@huggingface/inference": "^1.5.1", + "@mozilla/readability": "*", + "@notionhq/client": "^2.2.10", + "@opensearch-project/opensearch": "*", + "@pinecone-database/pinecone": "*", + "@planetscale/database": "^1.8.0", + "@qdrant/js-client-rest": "^1.2.0", + "@raycast/api": "^1.55.2", + "@smithy/eventstream-codec": "^2.0.5", + "@smithy/util-utf8": "^2.0.0", + "@supabase/postgrest-js": "^1.1.1", + "@supabase/supabase-js": "^2.10.0", + "@tensorflow-models/universal-sentence-encoder": "*", + "@tensorflow/tfjs-converter": "*", + "@tensorflow/tfjs-core": "*", + "@upstash/redis": "^1.20.6", + "@writerai/writer-sdk": "^0.40.2", + "@xata.io/client": "^0.25.1", + "@xenova/transformers": "^2.5.4", + "@zilliz/milvus2-sdk-node": ">=2.2.7", + "apify-client": "^2.7.1", + "axios": "*", + "cheerio": "^1.0.0-rc.12", + "chromadb": "*", + "cohere-ai": ">=6.0.0", + "d3-dsv": "^2.0.0", + "epub2": "^3.0.1", + "faiss-node": "^0.3.0", + "fast-xml-parser": "^4.2.7", + "firebase-admin": "^11.9.0", + "google-auth-library": "^8.9.0", + "hnswlib-node": "^1.4.2", + "html-to-text": "^9.0.5", + "ignore": "^5.2.0", + "ioredis": "^5.3.2", + "jsdom": "*", + "llmonitor": "*", + "mammoth": "*", + "mongodb": "^5.2.0", + "mysql2": "^3.3.3", + "node-llama-cpp": "*", + "notion-to-md": "^3.1.0", + "pdf-parse": "1.1.1", + "peggy": "^3.0.2", + "pg": "^8.11.0", + "pg-copy-streams": "^6.0.5", + "pickleparser": "^0.1.0", + "playwright": "^1.32.1", + "puppeteer": "^19.7.2", + "redis": "^4.6.4", + "replicate": "^0.18.0", + "sonix-speech-recognition": "^2.1.1", + "srt-parser-2": "^1.2.2", + "typeorm": "^0.3.12", + "typesense": "^1.5.3", + "usearch": "^1.1.1", + "vectordb": "^0.1.4", + "voy-search": "0.6.2", + "weaviate-ts-client": "^1.4.0", + "web-auth-library": "^1.0.3", + "youtube-transcript": "^1.0.6", + "youtubei.js": "^5.8.0" + }, + "peerDependenciesMeta": { + "@aws-crypto/sha256-js": { + "optional": true + }, + "@aws-sdk/client-dynamodb": { + "optional": true + }, + "@aws-sdk/client-kendra": { + "optional": true + }, + "@aws-sdk/client-lambda": { + "optional": true + }, + "@aws-sdk/client-s3": { + "optional": true + }, + "@aws-sdk/client-sagemaker-runtime": { + "optional": true + }, + "@aws-sdk/client-sfn": { + "optional": true + }, + "@aws-sdk/credential-provider-node": { + "optional": true + }, + "@aws-sdk/protocol-http": { + "optional": true + }, + "@aws-sdk/signature-v4": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@clickhouse/client": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@elastic/elasticsearch": { + "optional": true + }, + "@getmetal/metal-sdk": { + "optional": true + }, + "@getzep/zep-js": { + "optional": true + }, + "@gomomento/sdk": { + "optional": true + }, + "@google-ai/generativelanguage": { + "optional": true + }, + "@google-cloud/storage": { + "optional": true + }, + "@huggingface/inference": { + "optional": true + }, + "@mozilla/readability": { + "optional": true + }, + "@notionhq/client": { + "optional": true + }, + "@opensearch-project/opensearch": { + "optional": true + }, + "@pinecone-database/pinecone": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@qdrant/js-client-rest": { + "optional": true + }, + "@raycast/api": { + "optional": true + }, + "@smithy/eventstream-codec": { + "optional": true + }, + "@smithy/util-utf8": { + "optional": true + }, + "@supabase/postgrest-js": { + "optional": true + }, + "@supabase/supabase-js": { + "optional": true + }, + "@tensorflow-models/universal-sentence-encoder": { + "optional": true + }, + "@tensorflow/tfjs-converter": { + "optional": true + }, + "@tensorflow/tfjs-core": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@writerai/writer-sdk": { + "optional": true + }, + "@xata.io/client": { + "optional": true + }, + "@xenova/transformers": { + "optional": true + }, + "@zilliz/milvus2-sdk-node": { + "optional": true + }, + "apify-client": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "chromadb": { + "optional": true + }, + "cohere-ai": { + "optional": true + }, + "d3-dsv": { + "optional": true + }, + "epub2": { + "optional": true + }, + "faiss-node": { + "optional": true + }, + "fast-xml-parser": { + "optional": true + }, + "firebase-admin": { + "optional": true + }, + "google-auth-library": { + "optional": true + }, + "hnswlib-node": { + "optional": true + }, + "html-to-text": { + "optional": true + }, + "ignore": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "llmonitor": { + "optional": true + }, + "mammoth": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "node-llama-cpp": { + "optional": true + }, + "notion-to-md": { + "optional": true + }, + "pdf-parse": { + "optional": true + }, + "peggy": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-copy-streams": { + "optional": true + }, + "pickleparser": { + "optional": true + }, + "playwright": { + "optional": true + }, + "puppeteer": { + "optional": true + }, + "redis": { + "optional": true + }, + "replicate": { + "optional": true + }, + "sonix-speech-recognition": { + "optional": true + }, + "srt-parser-2": { + "optional": true + }, + "typeorm": { + "optional": true + }, + "typesense": { + "optional": true + }, + "usearch": { + "optional": true + }, + "vectordb": { + "optional": true + }, + "voy-search": { + "optional": true + }, + "weaviate-ts-client": { + "optional": true + }, + "web-auth-library": { + "optional": true + }, + "youtube-transcript": { + "optional": true + }, + "youtubei.js": { + "optional": true + } + } + }, + "node_modules/langchain/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/langchain/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/langchain/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/langchain/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/langchain/node_modules/yaml": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", + "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/langchainhub": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/langchainhub/-/langchainhub-0.0.6.tgz", + "integrity": "sha512-SW6105T+YP1cTe0yMf//7kyshCgvCTyFBMTgH2H3s9rTAR4e+78DA/BBrUL/Mt4Q5eMWui7iGuAYb3pgGsdQ9w==" + }, + "node_modules/langsmith": { + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.0.40.tgz", + "integrity": "sha512-R74HClnzClnm1/eFrcd7isiJ4iLQcrJV/Rm9fDZOZagQR4p+bnNCxYWCHoRex3Q9T7w1aRI0EMJIU+8WsF6rEQ==", + "dependencies": { + "@types/uuid": "^9.0.1", + "commander": "^10.0.1", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + }, + "bin": { + "langsmith": "dist/cli/main.cjs" + } + }, + "node_modules/langsmith/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/langsmith/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -15918,6 +16598,16 @@ "tmpl": "1.0.5" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -16128,6 +16818,46 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/ml-array-mean": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ml-array-mean/-/ml-array-mean-1.1.6.tgz", + "integrity": "sha512-MIdf7Zc8HznwIisyiJGRH9tRigg3Yf4FldW8DxKxpCCv/g5CafTw0RRu51nojVEOXuCQC7DRVVu5c7XXO/5joQ==", + "dependencies": { + "ml-array-sum": "^1.1.6" + } + }, + "node_modules/ml-array-sum": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ml-array-sum/-/ml-array-sum-1.1.6.tgz", + "integrity": "sha512-29mAh2GwH7ZmiRnup4UyibQZB9+ZLyMShvt4cH4eTK+cL2oEMIZFnSyB3SS8MlsTh6q/w/yh48KmqLxmovN4Dw==", + "dependencies": { + "is-any-array": "^2.0.0" + } + }, + "node_modules/ml-distance": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/ml-distance/-/ml-distance-4.0.1.tgz", + "integrity": "sha512-feZ5ziXs01zhyFUUUeZV5hwc0f5JW0Sh0ckU1koZe/wdVkJdGxcP06KNQuF0WBTj8FttQUzcvQcpcrOp/XrlEw==", + "dependencies": { + "ml-array-mean": "^1.1.6", + "ml-distance-euclidean": "^2.0.0", + "ml-tree-similarity": "^1.0.0" + } + }, + "node_modules/ml-distance-euclidean": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ml-distance-euclidean/-/ml-distance-euclidean-2.0.0.tgz", + "integrity": "sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q==" + }, + "node_modules/ml-tree-similarity": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ml-tree-similarity/-/ml-tree-similarity-1.0.0.tgz", + "integrity": "sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==", + "dependencies": { + "binary-search": "^1.3.5", + "num-sort": "^2.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -16204,6 +16934,62 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -16271,6 +17057,17 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/num-sort": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/num-sort/-/num-sort-2.1.0.tgz", + "integrity": "sha512-1MQz1Ed8z2yckoBeSfkQHHO9K1yDRxxtotKSJ9yvcTUUxSvfvzEq5GwBrjjHEpMlq/k5gvXdmJ1SbYxWtpNoVg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -16488,6 +17285,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.4.0.tgz", + "integrity": "sha512-JN0t628Kh95T0IrXl0HdBqnlJg+4Vq0Bnh55tio+dfCnyzHvMLiWyCM9m726MAJD2YkDU4/8RQB6rNbEq9ct2w==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.0.tgz", + "integrity": "sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw==" + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -16504,6 +17329,14 @@ "node": ">= 0.8.0" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -16532,6 +17365,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", @@ -16544,6 +17392,17 @@ "node": ">=8" } }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -21949,6 +22808,14 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/web-vitals": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.4.0.tgz", @@ -22955,6 +23822,22 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", + "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.21.4.tgz", + "integrity": "sha512-fjUZh4nQ1s6HMccgIeE0VP4QG/YRGPmyjO9sAh890aQKPEk3nqbfUXhMFaC+Dr5KvYBm8BCyvfpZf2jY9aGSsw==", + "peerDependencies": { + "zod": "^3.21.4" + } } } } diff --git a/package.json b/package.json index ae7c5e1..1a6c1bb 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,9 @@ "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", "bootstrap": "^5.3.2", + "dotenv-webpack": "^8.0.1", + "exponential-backoff": "^3.1.1", + "langchain": "^0.0.154", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", diff --git a/tsconfig.json b/tsconfig.json index e43a6dd..02dfd61 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "lib": [ "dom", "dom.iterable", diff --git a/webpack.config.js b/webpack.config.js index 4ea8f41..1751573 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,5 +1,5 @@ const path = require("path"); - +const Dotenv = require("dotenv-webpack"); module.exports = { entry: { popup: "./react-chrome-extension/src/popup/index.tsx", @@ -30,4 +30,7 @@ module.exports = { filename: "[name].js", path: path.resolve(__dirname, "extension"), }, + plugins: [ + new Dotenv(), + ], }; From 700b58ae9a9b7798c67211322d31e8b2f7e22679 Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 29 Sep 2023 17:31:09 -0400 Subject: [PATCH 08/16] removes random comment --- autofill/autofillScript.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 5077955..44d8bb6 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -106,6 +106,9 @@ function labelDict(labels: Element[], fields: Element[], map: Map(); +labelDict(Array.from(document.querySelectorAll('label')), Array.from(document.querySelectorAll('input')), labelMap); + const user = { name: "samir sam beall", email: "samir.beall@gmail.com", @@ -117,10 +120,8 @@ const user = { async function main (){ - let labelMap = new Map(); - labelDict(Array.from(document.querySelectorAll('label')), Array.from(document.querySelectorAll('input')), labelMap); - - let template_text = "I will give you an input field and you choose which response best fits the fields label. The data you will select form exclusively comes from: "; + let template_text = "I will give you an input field and you choose which response best fits the response} \ + the data you will use is:"; template_text += JSON.stringify(user) @@ -155,8 +156,18 @@ async function main (){ messages.push(new HumanMessage({content: "placeholder"})) + for (let [key, value] of labelMap){ + messages.push(new HumanMessage({content: value?.textContent || ''})); + let chatModelResult = chatModel.predictMessages(messages); + + chatModelResult.then((resolvedResponse: BaseMessage) => { + console.log("chat result: ") + console.log(chatModelResult); + if(key) (key as HTMLInputElement).value = resolvedResponse.content; + }) +} - for (const qf of questionsAndFields){ + /*for (const qf of questionsAndFields){ console.log("querying chat") messages[7] = new HumanMessage({content: qf.question}); @@ -171,7 +182,7 @@ async function main (){ }) // messages.push(chatModelResult); - } + }*/ console.log(messages); } From d9d29f5322f6afccd5428d69eab768e72542bee3 Mon Sep 17 00:00:00 2001 From: kyogrekube Date: Fri, 29 Sep 2023 17:37:39 -0400 Subject: [PATCH 09/16] Added dropdown menu alternative method (commented) --- autofill/autofillScript.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 44d8bb6..4a7066c 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -32,8 +32,11 @@ const agreeToTerms = document.querySelector('input[name*="agree"]'); if (agreeToTerms) (agreeToTerms as HTMLInputElement).checked = true; // Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns -const dropdown = document.querySelector('select');; -if (dropdown) (dropdown as HTMLSelectElement).value = "ALB"; +const stateField = document.getElementById("address-level1") as HTMLSelectElement; +stateField.value = "AL"; + +const countryField = document.getElementById("country") as HTMLSelectElement; +countryField.value = "US"; @@ -62,7 +65,6 @@ export {} import { AIMessage, BaseMessage, ChatMessage, HumanMessage, SystemMessage } from "langchain/schema"; import { chatModel } from "./llm"; -import{ backOff }from "exponential-backoff"; From 143a869b530ce233d451570211b97562101cd440 Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 29 Sep 2023 17:38:42 -0400 Subject: [PATCH 10/16] removes accidental api key --- .env | 2 +- autofill/autofillScript.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.env b/.env index 4cfd813..48e789f 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ # Enter your openai key here -OPENAI_API_KEY=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 +OPENAI_API_KEY= diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 44d8bb6..578d930 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -62,7 +62,6 @@ export {} import { AIMessage, BaseMessage, ChatMessage, HumanMessage, SystemMessage } from "langchain/schema"; import { chatModel } from "./llm"; -import{ backOff }from "exponential-backoff"; From 5ad5e4d65683678d4ed6f0742800b10148753a1e Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 6 Oct 2023 16:07:22 -0400 Subject: [PATCH 11/16] furthered accuracy of autofill. Uses two functions to verify location of input parameters, then uses GPT-3.5 to fill in fields. --- .gitignore | 3 + autofill/autofillScript.ts | 170 ++++++++++++++++++------ autofill/llm.ts | 4 +- autofill/resumeParse.ts | 0 package-lock.json | 262 +++++++++++++++++++++++++++++++++++++ package.json | 2 + 6 files changed, 397 insertions(+), 44 deletions(-) create mode 100644 autofill/resumeParse.ts diff --git a/.gitignore b/.gitignore index d84d6e7..256299b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ react-chrome-extension/build npm-debug.log* yarn-debug.log* yarn-error.log* +.env +.env +.gitignore diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 4a7066c..0e8c641 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -65,67 +65,155 @@ export {} import { AIMessage, BaseMessage, ChatMessage, HumanMessage, SystemMessage } from "langchain/schema"; import { chatModel } from "./llm"; - - - -// Very basic function to find closest label to input field. Used for testing below function labelDist(labels: Element[], input: Element): Element { let minDist = Number.MAX_VALUE; let minLabel = labels[0]; - for (let i = 0; i < labels.length; i++) { - let dist = Math.abs(labels[i].getBoundingClientRect().top - input.getBoundingClientRect().top); + for (let i of labels) { + let dist = Math.abs(i.getBoundingClientRect().top - input.getBoundingClientRect().top); if (dist < minDist) { minDist = dist; - minLabel = labels[i]; + minLabel = i; } } return minLabel; } -function fieldDist(fields: Element[], input: Element): Element { +function inputDist(inputs: Element[], label: Element): Element { let minDist = Number.MAX_VALUE; - let minField = fields[0]; - for (let i = 0; i < fields.length; i++) { - let dist = Math.abs(fields[i].getBoundingClientRect().top - input.getBoundingClientRect().top); + let minInput = inputs[0]; + for (let i of inputs) { + let dist = Math.abs(i.getBoundingClientRect().top - label.getBoundingClientRect().top); if (dist < minDist) { minDist = dist; - minField = fields[i]; + minInput = i; } } - return minField; + return minInput; } -function labelDict(labels: Element[], fields: Element[], map: Map){ - let emptyElement = document.createElement("input"); - for (let i = 0; i < fields.length; i++){ - let label = labelDist(labels, fields[i]); - if(fields[i] == fieldDist(fields, label)){ - map.set(fields[i], label); + +function labelDict(labels: Element[], fields: Element[], map: Map, set: Set){ + for (let i of fields){ + let label = labelDist(labels, i); + if(!set.has(label) && i == inputDist(fields, label)) { + map.set(i, label); + set.add(label); + console.log("new label found " + label.textContent); } else{ - map.set(fields[i], map.get(fields[i-1] || emptyElement)); + let newLabel = label.cloneNode(true); + newLabel.textContent = label.textContent + " 2"; + console.log("duplicate label found " + newLabel.textContent); } } } let labelMap = new Map(); -labelDict(Array.from(document.querySelectorAll('label')), Array.from(document.querySelectorAll('input')), labelMap); +// remove dupe labels + +let labels = Array.from(document.querySelectorAll('label')); + +let labelSet = new Set(); +labelDict(labels, Array.from(document.querySelectorAll('input')), labelMap, labelSet); const user = { - name: "samir sam beall", - email: "samir.beall@gmail.com", + name: "Ariel Ricardo Montero", + email: "ariel.montmaj@gmail.com", address: "1999 Burdett Ave, Troy, NY 12180", phone_number: "(123) 456-78910", zip: "12180", - none: "none" + none: "", + resume: ` Ariel Montero + (845) 413-6766 | montea8@rpi.edu | linkedin.com/in/ariel-montero | github.com/timelord1102 + + Education + Rensselaer Polytechnic Institute Troy, NY + Bachelor of Science in Computer Science (ABET-Accredited) Aug. 2021– May 2025 + Relevant Coursework: Data Structures, Foundations of Computer Science, Principles of Software, Introduction to Algorithms + + Experience + Developer - EasyApp Aug. 2023 – Present + Rensselaer Center for Open Source Troy, NY + Reduce job application time to mere minutes, providing an increase in speed of nearly 1000% over non-AI assisted capabilities on average + Spearhead development of an AI powered text generative backend designed to automatically adapt to and fill out various online job applications + Develop a connected frontend in the form of a Google Chrome and Firefox extension for easy of use + + Sales Associate May 2023 – Present + Follett Corporation Troy, NY + Lead projects dedicated to improving store efficiency and appearance + Balance various tasks with greeting and assisting over 100 customers daily + Adapt skills to non-normal work environments such as events and after hours projects + + Cashier and Maintenance Tech Jan. 2023 – Mar. 2023 + Sodexo Troy, NY + Balanced customer assistance with maintenance of dining hall standards + Guaranteed smooth operation of all sections of the eatery + Showed mastery of cashier software by debugging issues with the underlying Windows 7 systems + + Projects + SteamScrape | Python, JSON, Steam API, Git May 2023 – Present + Developed a script to scrape a list of over 90,000 games and DLC on Steam + Combined Steam’s API and web scraping to gather information regardless of API availability + Used JSON files to store data and keep track of scanned games for easy data updates with no user intervention + + RPIt | Jellyfin, Ubuntu Server, Docker, Tdarr Aug. 2022 – Present + Created a media server with nearly 12 terabytes of video files sourced from a large Blu-ray collection + Implemented using a heavily customized Jellyfin software installed as a Docker image for easy maintenance + Utilized Tdarr to fully automate the transcoding of media for standardization of encodings to x264 + + Technical Skills + Programming Languages: Python, Java, C/C++, Typescript + Developer Tools: Git, GitHub, Docker, VS Code, Visual Studio, Eclipse, WSL, Powershell, LangChain + Languages: English, Spanish + ` }; async function main (){ - let template_text = "I will give you an input field and you choose which response best fits the response} \ - the data you will use is:"; - - template_text += JSON.stringify(user) + let template_text = "Use the following resume to pull data from and fill out a form:" + template_text += `Ariel Montero + (845) 413-6766 | montea8@rpi.edu | linkedin.com/in/ariel-montero | github.com/timelord1102 + + Education + Rensselaer Polytechnic Institute Troy, NY + Bachelor of Science in Computer Science (ABET-Accredited) Aug. 2021– May 2025 + Relevant Coursework: Data Structures, Foundations of Computer Science, Principles of Software, Introduction to Algorithms + + Experience + Developer - EasyApp Aug. 2023 – Present + Rensselaer Center for Open Source Troy, NY + Reduce job application time to mere minutes, providing an increase in speed of nearly 1000% over non-AI assisted capabilities on average + Spearhead development of an AI powered text generative backend designed to automatically adapt to and fill out various online job applications + Develop a connected frontend in the form of a Google Chrome and Firefox extension for easy of use + + Sales Associate May 2023 – Present + Follett Corporation Troy, NY + Lead projects dedicated to improving store efficiency and appearance + Balance various tasks with greeting and assisting over 100 customers daily + Adapt skills to non-normal work environments such as events and after hours projects + + Cashier and Maintenance Tech Jan. 2023 – Mar. 2023 + Sodexo Troy, NY + Balanced customer assistance with maintenance of dining hall standards + Guaranteed smooth operation of all sections of the eatery + Showed mastery of cashier software by debugging issues with the underlying Windows 7 systems + + Projects + SteamScrape | Python, JSON, Steam API, Git May 2023 – Present + Developed a script to scrape a list of over 90,000 games and DLC on Steam + Combined Steam’s API and web scraping to gather information regardless of API availability + Used JSON files to store data and keep track of scanned games for easy data updates with no user intervention + + RPIt | Jellyfin, Ubuntu Server, Docker, Tdarr Aug. 2022 – Present + Created a media server with nearly 12 terabytes of video files sourced from a large Blu-ray collection + Implemented using a heavily customized Jellyfin software installed as a Docker image for easy maintenance + Utilized Tdarr to fully automate the transcoding of media for standardization of encodings to x264 + + Technical Skills + Programming Languages: Python, Java, C/C++, Typescript + Developer Tools: Git, GitHub, Docker, VS Code, Visual Studio, Eclipse, WSL, Powershell, LangChain + Languages: English, Spanish + ` console.log(template_text); @@ -140,25 +228,23 @@ async function main (){ messages.push(new HumanMessage({content: "Middle Name"})); messages.push(new AIMessage({content: "Sam"})); - const inputFields = document.querySelectorAll('input'); - const questionsAndFields: { question: string, field: HTMLInputElement }[] = []; + messages.push(new HumanMessage({content: "City"})); + messages.push(new AIMessage({content: "Troy"})); - inputFields.forEach((inputField: HTMLInputElement) => { - const label = document.querySelector(`label[for="${inputField.id}"]`); - if (label) { - questionsAndFields.push({ - question: label.textContent || '', - field: inputField - }); - } - }); + messages.push(new HumanMessage({content: "City 2"})); + messages.push(new AIMessage({content: ""})); - console.log(questionsAndFields); + messages.push(new HumanMessage({content: "School"})); + messages.push(new AIMessage({content: "Rensselear Polytechnic Institute"})); - messages.push(new HumanMessage({content: "placeholder"})) - for (let [key, value] of labelMap){ + const inputFields = document.querySelectorAll('input'); + const questionsAndFields: { question: string, field: HTMLInputElement }[] = []; + + let inputs = Array.from(inputFields); + for (let [key, value] of labelMap) { + messages.push(new HumanMessage({content: value?.textContent || ''})); let chatModelResult = chatModel.predictMessages(messages); diff --git a/autofill/llm.ts b/autofill/llm.ts index 798cf07..2527c0b 100644 --- a/autofill/llm.ts +++ b/autofill/llm.ts @@ -1,3 +1,3 @@ -import { ChatOpenAI } from "langchain/chat_models/openai"; +import { OpenAI } from "langchain/llms/openai"; -export const chatModel = new ChatOpenAI({openAIApiKey: process.env.OPENAI_API_KEY, temperature: 0}); \ No newline at end of file +export const chatModel = new OpenAI({openAIApiKey: process.env.OPENAI_API_KEY, temperature: 0, modelName: "gpt-3.5-turbo-instruct"}); \ No newline at end of file diff --git a/autofill/resumeParse.ts b/autofill/resumeParse.ts new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json index 7e61e71..48ac51c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,9 @@ "bootstrap": "^5.3.2", "dotenv-webpack": "^8.0.1", "exponential-backoff": "^3.1.1", + "fs": "^0.0.1-security", "langchain": "^0.0.154", + "langchain-gpt4all": "^0.0.74", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", @@ -2339,6 +2341,11 @@ "node": ">=10.0.0" } }, + "node_modules/@dqbd/tiktoken": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@dqbd/tiktoken/-/tiktoken-1.0.7.tgz", + "integrity": "sha512-bhR5k5W+8GLzysjk8zTMVygQZsgvf7W1F0IlL4ZQ5ugjo5rCyiwGM5d8DYriXspytfu98tv59niang3/T+FoDw==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2432,6 +2439,14 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortaine/fetch-event-source": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@fortaine/fetch-event-source/-/fetch-event-source-3.0.6.tgz", + "integrity": "sha512-621GAuLMvKtyZQ3IA6nlDWhV1V/7PGOTNIGLUifxt0KzM+dZIweJ6F3XvQF3QnqeNfS1N7WQ0Kil1Di/lhChEw==", + "engines": { + "node": ">=16.15" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", @@ -6458,6 +6473,14 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -6930,6 +6953,11 @@ "node": ">=8" } }, + "node_modules/browser-or-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + }, "node_modules/browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -7625,6 +7653,14 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -10181,6 +10217,11 @@ "node": ">= 0.6" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -16312,6 +16353,227 @@ } } }, + "node_modules/langchain-gpt4all": { + "version": "0.0.74", + "resolved": "https://registry.npmjs.org/langchain-gpt4all/-/langchain-gpt4all-0.0.74.tgz", + "integrity": "sha512-Wuetf7spGz63D+h9r4eb7udsWpBZj6HHifhA+NShl+J1N07LDr34/K7f9eZRNOhehOFP/0FjUWshzSXwyCmvjQ==", + "dependencies": { + "@anthropic-ai/sdk": "^0.4.3", + "@dqbd/tiktoken": "^1.0.7", + "ansi-styles": "^5.0.0", + "binary-extensions": "^2.2.0", + "browser-or-node": "^2.1.1", + "expr-eval": "^2.0.2", + "flat": "^5.0.2", + "jsonpointer": "^5.0.1", + "ml-distance": "^4.0.0", + "object-hash": "^3.0.0", + "openai": "^3.2.0", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0", + "yaml": "^2.2.1", + "zod": "^3.21.4", + "zod-to-json-schema": "^3.20.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.310.0", + "@aws-sdk/client-lambda": "^3.310.0", + "@aws-sdk/client-s3": "^3.310.0", + "@clickhouse/client": "^0.0.14", + "@getmetal/metal-sdk": "*", + "@huggingface/inference": "^1.5.1", + "@opensearch-project/opensearch": "*", + "@pinecone-database/pinecone": "*", + "@supabase/supabase-js": "^2.10.0", + "@tensorflow-models/universal-sentence-encoder": "*", + "@tensorflow/tfjs-converter": "*", + "@tensorflow/tfjs-core": "*", + "@zilliz/milvus2-sdk-node": "^2.2.0", + "axios": "*", + "cheerio": "^1.0.0-rc.12", + "chromadb": "^1.4.0", + "cohere-ai": "^5.0.2", + "d3-dsv": "^2.0.0", + "epub2": "^3.0.1", + "gpt4all": "*", + "hnswlib-node": "^1.4.2", + "html-to-text": "^9.0.5", + "mammoth": "*", + "mongodb": "^5.2.0", + "pdf-parse": "1.1.1", + "playwright": "^1.32.1", + "puppeteer": "^19.7.2", + "redis": "^4.6.4", + "replicate": "^0.9.0", + "srt-parser-2": "^1.2.2", + "typeorm": "^0.3.12", + "weaviate-ts-client": "^1.0.0" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-dynamodb": { + "optional": true + }, + "@aws-sdk/client-lambda": { + "optional": true + }, + "@aws-sdk/client-s3": { + "optional": true + }, + "@clickhouse/client": { + "optional": true + }, + "@getmetal/metal-sdk": { + "optional": true + }, + "@huggingface/inference": { + "optional": true + }, + "@opensearch-project/opensearch": { + "optional": true + }, + "@pinecone-database/pinecone": { + "optional": true + }, + "@supabase/supabase-js": { + "optional": true + }, + "@tensorflow-models/universal-sentence-encoder": { + "optional": true + }, + "@tensorflow/tfjs-converter": { + "optional": true + }, + "@tensorflow/tfjs-core": { + "optional": true + }, + "@zilliz/milvus2-sdk-node": { + "optional": true + }, + "axios": { + "optional": true + }, + "cheerio": { + "optional": true + }, + "chromadb": { + "optional": true + }, + "cohere-ai": { + "optional": true + }, + "d3-dsv": { + "optional": true + }, + "epub2": { + "optional": true + }, + "gpt4all": { + "optional": true + }, + "hnswlib-node": { + "optional": true + }, + "html-to-text": { + "optional": true + }, + "mammoth": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "pdf-parse": { + "optional": true + }, + "playwright": { + "optional": true + }, + "puppeteer": { + "optional": true + }, + "redis": { + "optional": true + }, + "replicate": { + "optional": true + }, + "srt-parser-2": { + "optional": true + }, + "typeorm": { + "optional": true + }, + "weaviate-ts-client": { + "optional": true + } + } + }, + "node_modules/langchain-gpt4all/node_modules/@anthropic-ai/sdk": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.4.4.tgz", + "integrity": "sha512-Z/39nQi1sSUCeLII3lsAbL1u+0JF6cR2XmUEX9sLH0VtxmIjY6cjOUYjCkYh4oapTxOkhAFnVSAFJ6cxml2qXg==", + "dependencies": { + "@fortaine/fetch-event-source": "^3.0.6", + "cross-fetch": "^3.1.5" + } + }, + "node_modules/langchain-gpt4all/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/langchain-gpt4all/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/langchain-gpt4all/node_modules/openai": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", + "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, + "node_modules/langchain-gpt4all/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/langchain-gpt4all/node_modules/yaml": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", + "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "engines": { + "node": ">= 14" + } + }, "node_modules/langchain/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", diff --git a/package.json b/package.json index 1a6c1bb..95f98dc 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "bootstrap": "^5.3.2", "dotenv-webpack": "^8.0.1", "exponential-backoff": "^3.1.1", + "fs": "^0.0.1-security", "langchain": "^0.0.154", + "langchain-gpt4all": "^0.0.74", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", From b7b384545e8866607d2ea3b6c75ccace9beb5b08 Mon Sep 17 00:00:00 2001 From: kyogrekube Date: Fri, 6 Oct 2023 16:09:39 -0400 Subject: [PATCH 12/16] Populate dropdown menus comnt from lines 125-146) --- autofill/autofillScript.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 4a7066c..658c3b9 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -117,9 +117,34 @@ const user = { address: "1999 Burdett Ave, Troy, NY 12180", phone_number: "(123) 456-78910", zip: "12180", - none: "none" + major: "Computer Science", + //school: "RPI", //Even if the school variable is after the major variable, it will autofill the "School", "Company", and "Postion fields with "RPI" + none: "none", }; +// Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns +//const stateField = document.getElementById("degree") as HTMLSelectElement; +//stateField.value = "Bachelor's Degree"; + +/*Possible methods for dropdown? +const dropdownData = [ + { id: 1, name: "Option 1" }, + { id: 2, name: "Option 2" }, + { id: 3, name: "Option 3" } +]; + +const dropdown = document.getElementById("dropdown") as HTMLSelectElement; + +// Function to populate the dropdown +function populateDropdown(data: any[]) { + data.forEach(item => { + const option = document.createElement("option"); + option.value = JSON.stringify(item); // Convert the object to a JSON string + option.text = item.name; // Set the display text + dropdown.appendChild(option); + }); +}*/ + async function main (){ let template_text = "I will give you an input field and you choose which response best fits the response} \ From a3507cff7204725fdd9bdfd0009a6ed7f9dad6d0 Mon Sep 17 00:00:00 2001 From: kyogrekube Date: Fri, 6 Oct 2023 16:40:42 -0400 Subject: [PATCH 13/16] PDF Upload Function Added --- autofill/autofillScript.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 658c3b9..42bd001 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -145,6 +145,44 @@ function populateDropdown(data: any[]) { }); }*/ +//FUNCTION FOR UPLOADING A PDF +function uploadPDF() { + document.addEventListener('DOMContentLoaded', () => { + const uploadForm = document.getElementById('uploadForm') as HTMLFormElement; + const pdfInput = document.getElementById('pdfInput') as HTMLInputElement; + const messageDiv = document.getElementById('message'); + + uploadForm.addEventListener('submit', async (e) => { + e.preventDefault(); + + const formData = new FormData(); + if (pdfInput.files!=null) { + formData.append('pdfFile', pdfInput.files[0]); + } + try { + const response = await fetch('/upload', { + method: 'POST', + body: formData, + }); + + if (messageDiv!=null) { + if (response.ok) { + messageDiv.innerText = 'PDF uploaded successfully!'; + } else { + messageDiv.innerText = 'Failed to upload PDF.'; + } + } + } catch (error) { + console.error('Error:', error); + if (messageDiv!=null) { + messageDiv.innerText = 'An error occurred while uploading the PDF.'; + } + } + }); + }); +} + +// main.ts async function main (){ let template_text = "I will give you an input field and you choose which response best fits the response} \ From daf69bd2586323f0efc2f8259658e21a8c1c777e Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 6 Oct 2023 20:19:01 -0400 Subject: [PATCH 14/16] further modified the autofill algorithm. Now MUCH more efficient runtime and memory wise. Also added a new feature to autofill allowing for AI completion of dropdown menus. The algoritm continues to use GPT to generate the proper field response. The new drop down algorithm passes GPT all possible options allowing it to choose the appropriate response. --- autofill/autofillScript.ts | 405 ++++++++----------------------------- autofill/resumeParse.ts | 0 package-lock.json | 6 + package.json | 1 + 4 files changed, 89 insertions(+), 323 deletions(-) delete mode 100644 autofill/resumeParse.ts diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 9d441d4..ed0414f 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,343 +1,102 @@ -/*// Very basic function to find closest label to input field. Used for testing below -function labelDist(labels: Element[], input: Element): Element { - let minDist = Number.MAX_VALUE; - let minLabel = labels[0]; - for (let i = 0; i < labels.length; i++) { - let dist = Math.abs(labels[i].getBoundingClientRect().top - input.getBoundingClientRect().top); - if (dist < minDist) { - minDist = dist; - minLabel = labels[i]; - } - } - return minLabel; -} - - -// This file will be run on the content page, and should include all the logic for inserting text into form items. -const firstNameField = document.querySelector('input[name="First Name"]'); -const lastNameField = document.querySelector('input[name="Last Name"]'); - -// Gets all input fields that contain keyword "email" -const emailField = document.querySelectorAll('input[id*="email"]'); - -if (firstNameField) (firstNameField as HTMLInputElement).value = "yourFirstName"; -if (lastNameField) (lastNameField as HTMLInputElement).value = "yourLastName"; - -// Sets all email fields to "yourEmail" as long as field ID contains "email" -for (let i = 0; i < emailField.length; i++) - if (emailField[i]) (emailField[i] as HTMLInputElement).value = "yourEmail"; - -// Trigger agree to terms and conditions. Tested on "https://store.steampowered.com/join" but should work on any site with a checkbox with the word "agree" in the name. Proof of concept for checkboxes -const agreeToTerms = document.querySelector('input[name*="agree"]'); -if (agreeToTerms) (agreeToTerms as HTMLInputElement).checked = true; - -// Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns -const stateField = document.getElementById("address-level1") as HTMLSelectElement; -stateField.value = "AL"; - -const countryField = document.getElementById("country") as HTMLSelectElement; -countryField.value = "US"; - - - -// Testing, fill all input fields with its own label text - -// Get all labels, convert to array -const labels = document.querySelectorAll('label'); -const labelArray = Array.from(labels); - -// Get all input fields -const inputs = document.querySelectorAll('input'); - -let label; -// For each input field, find closest label and set input field to label text. Currently bugged for non labeled input fields -for (let i = 0; i < inputs.length; i++) { - label = labelDist(labelArray, inputs[i]); - label = label?.textContent; - if (label) (inputs[i] as HTMLInputElement).value = label; - -} - - -export {} -*/ - -import { AIMessage, BaseMessage, ChatMessage, HumanMessage, SystemMessage } from "langchain/schema"; +import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from "langchain/schema"; import { chatModel } from "./llm"; -function labelDist(labels: Element[], input: Element): Element { - let minDist = Number.MAX_VALUE; - let minLabel = labels[0]; - for (let i of labels) { - let dist = Math.abs(i.getBoundingClientRect().top - input.getBoundingClientRect().top); - if (dist < minDist) { - minDist = dist; - minLabel = i; - } - } - return minLabel; -} - -function inputDist(inputs: Element[], label: Element): Element { - let minDist = Number.MAX_VALUE; - let minInput = inputs[0]; - for (let i of inputs) { - let dist = Math.abs(i.getBoundingClientRect().top - label.getBoundingClientRect().top); - if (dist < minDist) { - minDist = dist; - minInput = i; - } - } - return minInput; -} - - -function labelDict(labels: Element[], fields: Element[], map: Map, set: Set){ - for (let i of fields){ - let label = labelDist(labels, i); - if(!set.has(label) && i == inputDist(fields, label)) { - map.set(i, label); - set.add(label); - console.log("new label found " + label.textContent); - } - else{ - let newLabel = label.cloneNode(true); - newLabel.textContent = label.textContent + " 2"; - console.log("duplicate label found " + newLabel.textContent); - } - } -} - -let labelMap = new Map(); -// remove dupe labels - -let labels = Array.from(document.querySelectorAll('label')); - -let labelSet = new Set(); -labelDict(labels, Array.from(document.querySelectorAll('input')), labelMap, labelSet); +const $ = require('jquery'); const user = { - name: "Ariel Ricardo Montero", - email: "ariel.montmaj@gmail.com", - address: "1999 Burdett Ave, Troy, NY 12180", - phone_number: "(123) 456-78910", - zip: "12180", - resume: ` Ariel Montero - (845) 413-6766 | montea8@rpi.edu | linkedin.com/in/ariel-montero | github.com/timelord1102 - - Education - Rensselaer Polytechnic Institute Troy, NY - Bachelor of Science in Computer Science (ABET-Accredited) Aug. 2021– May 2025 - Relevant Coursework: Data Structures, Foundations of Computer Science, Principles of Software, Introduction to Algorithms - - Experience - Developer - EasyApp Aug. 2023 – Present - Rensselaer Center for Open Source Troy, NY - Reduce job application time to mere minutes, providing an increase in speed of nearly 1000% over non-AI assisted capabilities on average - Spearhead development of an AI powered text generative backend designed to automatically adapt to and fill out various online job applications - Develop a connected frontend in the form of a Google Chrome and Firefox extension for easy of use - - Sales Associate May 2023 – Present - Follett Corporation Troy, NY - Lead projects dedicated to improving store efficiency and appearance - Balance various tasks with greeting and assisting over 100 customers daily - Adapt skills to non-normal work environments such as events and after hours projects - - Cashier and Maintenance Tech Jan. 2023 – Mar. 2023 - Sodexo Troy, NY - Balanced customer assistance with maintenance of dining hall standards - Guaranteed smooth operation of all sections of the eatery - Showed mastery of cashier software by debugging issues with the underlying Windows 7 systems - - Projects - SteamScrape | Python, JSON, Steam API, Git May 2023 – Present - Developed a script to scrape a list of over 90,000 games and DLC on Steam - Combined Steam’s API and web scraping to gather information regardless of API availability - Used JSON files to store data and keep track of scanned games for easy data updates with no user intervention - - RPIt | Jellyfin, Ubuntu Server, Docker, Tdarr Aug. 2022 – Present - Created a media server with nearly 12 terabytes of video files sourced from a large Blu-ray collection - Implemented using a heavily customized Jellyfin software installed as a Docker image for easy maintenance - Utilized Tdarr to fully automate the transcoding of media for standardization of encodings to x264 - - Technical Skills - Programming Languages: Python, Java, C/C++, Typescript - Developer Tools: Git, GitHub, Docker, VS Code, Visual Studio, Eclipse, WSL, Powershell, LangChain - Languages: English, Spanish - `, - major: "Computer Science", - none: "none" + name: "samir sam beall", + email: "samir.beall@gmail.com", + address: "1999 Burdett Ave, Troy, NY 12180", + phone_number: "(123) 456-78910", + zip: "12180", + null: "other" }; -// Dropdown test. Sets to Albania on "https://www.globalsqa.com/demo-site/select-dropdown-menu/" proof of concept for dropdowns -//const stateField = document.getElementById("degree") as HTMLSelectElement; -//stateField.value = "Bachelor's Degree"; - -/*Possible methods for dropdown? -const dropdownData = [ - { id: 1, name: "Option 1" }, - { id: 2, name: "Option 2" }, - { id: 3, name: "Option 3" } -]; - -const dropdown = document.getElementById("dropdown") as HTMLSelectElement; - -// Function to populate the dropdown -function populateDropdown(data: any[]) { - data.forEach(item => { - const option = document.createElement("option"); - option.value = JSON.stringify(item); // Convert the object to a JSON string - option.text = item.name; // Set the display text - dropdown.appendChild(option); - }); -}*/ - -//FUNCTION FOR UPLOADING A PDF -function uploadPDF() { - document.addEventListener('DOMContentLoaded', () => { - const uploadForm = document.getElementById('uploadForm') as HTMLFormElement; - const pdfInput = document.getElementById('pdfInput') as HTMLInputElement; - const messageDiv = document.getElementById('message'); - - uploadForm.addEventListener('submit', async (e) => { - e.preventDefault(); - - const formData = new FormData(); - if (pdfInput.files!=null) { - formData.append('pdfFile', pdfInput.files[0]); - } - try { - const response = await fetch('/upload', { - method: 'POST', - body: formData, - }); - - if (messageDiv!=null) { - if (response.ok) { - messageDiv.innerText = 'PDF uploaded successfully!'; - } else { - messageDiv.innerText = 'Failed to upload PDF.'; - } +function normalFields(){ + + let template = 'From the following data, pick a single best response for the field: \n' + JSON.stringify(user) + + console.log("template: " + template); + + let messages = [new SystemMessage({ content: template })]; + + messages.push(new HumanMessage({content: "First Name"})); + messages.push(new AIMessage({content: "Samir"})); + messages.push(new HumanMessage({content: "Street Address"})); + messages.push(new AIMessage({content: "1999 Burdette Ave"})); + messages.push(new HumanMessage({content: "Middle Name"})); + messages.push(new AIMessage({content: "Sam"})); + + let divs = document.querySelectorAll('div'); + + console.log("divs found: " + divs.length); + + messages.push(new HumanMessage({content: "placeholder"})); + + for (let i of divs){ + // get all divs with one label and one input using jquery + let label = $(i).find('label'); + let input = $(i).find('input'); + if(label.length == 1 && input.length == 1){ + // if (input[0]) (input[0] as HTMLInputElement).value = label[0].textContent; + // give ai the label + let label_text = label[0].textContent; + console.log("label: " + label_text); + messages[7] = (new HumanMessage({content: label_text})); + // get ai response + let response = chatModel.predictMessages(messages); + // set input value to response + response.then((res: BaseMessage) => { + if (res instanceof AIMessage){ + console.log("\tAI response: " + res.content); + if (input[0]) (input[0] as HTMLInputElement).value = res.content; } - } catch (error) { - console.error('Error:', error); - if (messageDiv!=null) { - messageDiv.innerText = 'An error occurred while uploading the PDF.'; - } - } - }); - }); + }) + } + } } -// main.ts -async function main (){ - - let template_text = "Use the following resume to pull data from and fill out a form:" - template_text += `Ariel Montero - (845) 413-6766 | montea8@rpi.edu | linkedin.com/in/ariel-montero | github.com/timelord1102 - - Education - Rensselaer Polytechnic Institute Troy, NY - Bachelor of Science in Computer Science (ABET-Accredited) Aug. 2021– May 2025 - Relevant Coursework: Data Structures, Foundations of Computer Science, Principles of Software, Introduction to Algorithms - - Experience - Developer - EasyApp Aug. 2023 – Present - Rensselaer Center for Open Source Troy, NY - Reduce job application time to mere minutes, providing an increase in speed of nearly 1000% over non-AI assisted capabilities on average - Spearhead development of an AI powered text generative backend designed to automatically adapt to and fill out various online job applications - Develop a connected frontend in the form of a Google Chrome and Firefox extension for easy of use - - Sales Associate May 2023 – Present - Follett Corporation Troy, NY - Lead projects dedicated to improving store efficiency and appearance - Balance various tasks with greeting and assisting over 100 customers daily - Adapt skills to non-normal work environments such as events and after hours projects - - Cashier and Maintenance Tech Jan. 2023 – Mar. 2023 - Sodexo Troy, NY - Balanced customer assistance with maintenance of dining hall standards - Guaranteed smooth operation of all sections of the eatery - Showed mastery of cashier software by debugging issues with the underlying Windows 7 systems - - Projects - SteamScrape | Python, JSON, Steam API, Git May 2023 – Present - Developed a script to scrape a list of over 90,000 games and DLC on Steam - Combined Steam’s API and web scraping to gather information regardless of API availability - Used JSON files to store data and keep track of scanned games for easy data updates with no user intervention - - RPIt | Jellyfin, Ubuntu Server, Docker, Tdarr Aug. 2022 – Present - Created a media server with nearly 12 terabytes of video files sourced from a large Blu-ray collection - Implemented using a heavily customized Jellyfin software installed as a Docker image for easy maintenance - Utilized Tdarr to fully automate the transcoding of media for standardization of encodings to x264 - - Technical Skills - Programming Languages: Python, Java, C/C++, Typescript - Developer Tools: Git, GitHub, Docker, VS Code, Visual Studio, Eclipse, WSL, Powershell, LangChain - Languages: English, Spanish - ` - - console.log(template_text); +function dropdownFields(){ - let messages = [new SystemMessage({ content: template_text })]; + let template = 'This is the users data: ' + JSON.stringify(user) + '\n' + 'Pick the best option for each dropdown.'; - messages.push(new HumanMessage({content: "First Name"})); - messages.push(new AIMessage({content: "Samir"})); + let messages = [new SystemMessage({ content: template })]; - messages.push(new HumanMessage({content: "Address"})); - messages.push(new AIMessage({content: "1999 Burdette Ave"})); - // - messages.push(new HumanMessage({content: "Middle Name"})); - messages.push(new AIMessage({content: "Sam"})); + let genderOptions = ["male", "femiale", "other"]; - messages.push(new HumanMessage({content: "City"})); - messages.push(new AIMessage({content: "Troy"})); + messages.push(new HumanMessage({content: JSON.stringify(genderOptions)})); + messages.push(new AIMessage({content: "male"})); - messages.push(new HumanMessage({content: "City 2"})); - messages.push(new AIMessage({content: ""})); + messages.push(new HumanMessage({content: "placeholder"})); - messages.push(new HumanMessage({content: "School"})); - messages.push(new AIMessage({content: "Rensselear Polytechnic Institute"})); + // get dropdowns from page using jquery + let dropdowns = $('select'); + console.log("dropdowns: " + dropdowns.length); + // for each dropdown get the options as an array + for (let i of dropdowns){ + let options = $(i).find('option'); + console.log("options: " + options.length); - - - const inputFields = document.querySelectorAll('input'); - const questionsAndFields: { question: string, field: HTMLInputElement }[] = []; - - let inputs = Array.from(inputFields); - for (let [key, value] of labelMap) { - - messages.push(new HumanMessage({content: value?.textContent || ''})); - let chatModelResult = chatModel.predictMessages(messages); - - chatModelResult.then((resolvedResponse: BaseMessage) => { - console.log("chat result: ") - console.log(chatModelResult); - if(key) (key as HTMLInputElement).value = resolvedResponse.content; - }) -} - - /*for (const qf of questionsAndFields){ - - console.log("querying chat") - messages[7] = new HumanMessage({content: qf.question}); - - let chatModelResult = chatModel.predictMessages(messages); - - chatModelResult.then((resolvedResponse: BaseMessage) => { - console.log("chat result: ") - console.log(chatModelResult); - - qf.field.value = resolvedResponse.content; - }) - // messages.push(chatModelResult); - - }*/ - - console.log(messages); + let dropdownOptions = []; + for (let j of options){ + let option = j as HTMLOptionElement; + dropdownOptions.push(option.text); + } + // give ai the dropdown options + messages[3] = (new HumanMessage({content: JSON.stringify(dropdownOptions)})); + // get ai response + let response = chatModel.predictMessages(messages); + // set dropdown value to response + response.then((res: BaseMessage) => { + if (res instanceof AIMessage){ + console.log("AI response: " + res.content); + if (i) (i as HTMLSelectElement).value = res.content.trim(); + } + }) + } } -main(); - +normalFields(); +//dropdownFields(); export {} \ No newline at end of file diff --git a/autofill/resumeParse.ts b/autofill/resumeParse.ts deleted file mode 100644 index e69de29..0000000 diff --git a/package-lock.json b/package-lock.json index 48ac51c..ed7094d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "dotenv-webpack": "^8.0.1", "exponential-backoff": "^3.1.1", "fs": "^0.0.1-security", + "jquery": "^3.7.1", "langchain": "^0.0.154", "langchain-gpt4all": "^0.0.74", "react": "^18.2.0", @@ -15789,6 +15790,11 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + }, "node_modules/js-tiktoken": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.7.tgz", diff --git a/package.json b/package.json index 95f98dc..c246f6f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dotenv-webpack": "^8.0.1", "exponential-backoff": "^3.1.1", "fs": "^0.0.1-security", + "jquery": "^3.7.1", "langchain": "^0.0.154", "langchain-gpt4all": "^0.0.74", "react": "^18.2.0", From b3bee3203a743584491066740f7cbd86ac5363a6 Mon Sep 17 00:00:00 2001 From: Ariel Date: Fri, 6 Oct 2023 21:11:59 -0400 Subject: [PATCH 15/16] fixes all previous issues AI responses are stripped of "AI :" prefixes. Dropdowns consitantly filled. AI responses made even more accurate by providing multiple data points to the AI. These include the field label, name and ID --- autofill/autofillScript.ts | 42 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index ed0414f..7849933 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -12,6 +12,14 @@ const user = { null: "other" }; +function cleanUp(input: string): string{ + while (input[0] != ':'){ + input = input.slice(1); + } + input = input.slice(1); + return input; +} + function normalFields(){ let template = 'From the following data, pick a single best response for the field: \n' + JSON.stringify(user) @@ -20,12 +28,16 @@ function normalFields(){ let messages = [new SystemMessage({ content: template })]; - messages.push(new HumanMessage({content: "First Name"})); + messages.push(new HumanMessage({content: "Field text: Name, Field ID: name, Field name: name"})); messages.push(new AIMessage({content: "Samir"})); - messages.push(new HumanMessage({content: "Street Address"})); + messages.push(new HumanMessage({content: "Field text: Street Address, Field ID: street_address, Field name: street_address"})); messages.push(new AIMessage({content: "1999 Burdette Ave"})); - messages.push(new HumanMessage({content: "Middle Name"})); - messages.push(new AIMessage({content: "Sam"})); + messages.push(new HumanMessage({content: "Field text: Confirm Address, Field ID: confirm_address, Field name: confirm_address"})); + messages.push(new AIMessage({content: "1999 Burdette Ave"})); + messages.push(new HumanMessage({content: "Field text: Email, Field ID: email, Field name: email"})); + messages.push(new AIMessage({content: "samir.beall@gmail.com"})); + messages.push(new HumanMessage({content: "Field text: Confirm Address, Field ID: confirm_email, Field name: confirm_email"})); + messages.push(new AIMessage({content: "samir.beall@gmail.com"})); let divs = document.querySelectorAll('div'); @@ -40,20 +52,21 @@ function normalFields(){ if(label.length == 1 && input.length == 1){ // if (input[0]) (input[0] as HTMLInputElement).value = label[0].textContent; // give ai the label - let label_text = label[0].textContent; - console.log("label: " + label_text); - messages[7] = (new HumanMessage({content: label_text})); + let label_text = "Field Text: " + label[0].textContent + ", Field ID: " + input[0].id + ", Field Name: " + input[0].name; + messages[11] = (new HumanMessage({content: label_text})); // get ai response let response = chatModel.predictMessages(messages); // set input value to response response.then((res: BaseMessage) => { if (res instanceof AIMessage){ - console.log("\tAI response: " + res.content); - if (input[0]) (input[0] as HTMLInputElement).value = res.content; + console.log("label: " + label_text + " input: " + cleanUp(res.content)); + if (input[0]) (input[0] as HTMLInputElement).value = cleanUp(res.content).trim(); } }) } } + console.log(JSON.stringify(messages)); + } function dropdownFields(){ @@ -71,16 +84,14 @@ function dropdownFields(){ // get dropdowns from page using jquery let dropdowns = $('select'); - console.log("dropdowns: " + dropdowns.length); - // for each dropdown get the options as an array + // for each dropdown get the option value field as an array for (let i of dropdowns){ let options = $(i).find('option'); - console.log("options: " + options.length); let dropdownOptions = []; for (let j of options){ let option = j as HTMLOptionElement; - dropdownOptions.push(option.text); + dropdownOptions.push(option.value); } // give ai the dropdown options messages[3] = (new HumanMessage({content: JSON.stringify(dropdownOptions)})); @@ -89,14 +100,13 @@ function dropdownFields(){ // set dropdown value to response response.then((res: BaseMessage) => { if (res instanceof AIMessage){ - console.log("AI response: " + res.content); - if (i) (i as HTMLSelectElement).value = res.content.trim(); + if (i) (i as HTMLSelectElement).value = cleanUp(res.content).trim(); } }) } } normalFields(); -//dropdownFields(); +dropdownFields(); export {} \ No newline at end of file From adc77b104dddc33bbe05bf59b216e4220a71b07b Mon Sep 17 00:00:00 2001 From: Ariel Date: Sun, 8 Oct 2023 15:02:18 -0400 Subject: [PATCH 16/16] adds more comments to code. Thats it. --- autofill/autofillScript.ts | 45 ++++++++++++++++++++++++++------------ package-lock.json | 14 ++++++++++++ package.json | 1 + 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/autofill/autofillScript.ts b/autofill/autofillScript.ts index 7849933..0445d48 100644 --- a/autofill/autofillScript.ts +++ b/autofill/autofillScript.ts @@ -1,17 +1,18 @@ import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from "langchain/schema"; import { chatModel } from "./llm"; -const $ = require('jquery'); +import $ from 'jquery'; const user = { - name: "samir sam beall", - email: "samir.beall@gmail.com", + name: "ariel ricardo montero majthenyi", + email: "montea8@rpi.edu", address: "1999 Burdett Ave, Troy, NY 12180", phone_number: "(123) 456-78910", zip: "12180", null: "other" }; +// A simple function to clean up the response from the AI. The AI will often return a string containing "AI: " at the beginning function cleanUp(input: string): string{ while (input[0] != ':'){ input = input.slice(1); @@ -20,8 +21,11 @@ function cleanUp(input: string): string{ return input; } -function normalFields(){ +// Uses AI to fill in standard text fields. +// Standard text fields assume that both the input field and label are wrapped exclusively in a div. +async function normalFields(){ + // Set up GPT-3 prompt let template = 'From the following data, pick a single best response for the field: \n' + JSON.stringify(user) console.log("template: " + template); @@ -29,33 +33,38 @@ function normalFields(){ let messages = [new SystemMessage({ content: template })]; messages.push(new HumanMessage({content: "Field text: Name, Field ID: name, Field name: name"})); - messages.push(new AIMessage({content: "Samir"})); + messages.push(new AIMessage({content: "Ariel"})); messages.push(new HumanMessage({content: "Field text: Street Address, Field ID: street_address, Field name: street_address"})); messages.push(new AIMessage({content: "1999 Burdette Ave"})); messages.push(new HumanMessage({content: "Field text: Confirm Address, Field ID: confirm_address, Field name: confirm_address"})); messages.push(new AIMessage({content: "1999 Burdette Ave"})); messages.push(new HumanMessage({content: "Field text: Email, Field ID: email, Field name: email"})); - messages.push(new AIMessage({content: "samir.beall@gmail.com"})); + messages.push(new AIMessage({content: "montea8@rpi.edu"})); messages.push(new HumanMessage({content: "Field text: Confirm Address, Field ID: confirm_email, Field name: confirm_email"})); - messages.push(new AIMessage({content: "samir.beall@gmail.com"})); - + messages.push(new AIMessage({content: "montea8@rpi.edu"})); + // End of GPT-3 prompt setup + + // get all divs let divs = document.querySelectorAll('div'); - - console.log("divs found: " + divs.length); + // Placeholder message to be replaced in each loop iteration messages.push(new HumanMessage({content: "placeholder"})); + // for each div, get labels and inputs contained by the div. This is done useing jquery for (let i of divs){ + // get all divs with one label and one input using jquery let label = $(i).find('label'); let input = $(i).find('input'); if(label.length == 1 && input.length == 1){ - // if (input[0]) (input[0] as HTMLInputElement).value = label[0].textContent; - // give ai the label + // give ai the information including the label text, input id, and input name. + // This helps it be more accurate when presented with ambiguous fields let label_text = "Field Text: " + label[0].textContent + ", Field ID: " + input[0].id + ", Field Name: " + input[0].name; messages[11] = (new HumanMessage({content: label_text})); + // get ai response let response = chatModel.predictMessages(messages); + // set input value to response response.then((res: BaseMessage) => { if (res instanceof AIMessage){ @@ -65,12 +74,14 @@ function normalFields(){ }) } } - console.log(JSON.stringify(messages)); - } +// Uses AI to fill in dropdown fields. Dropdown fields are similar to input fields, but instead of an input, they have +// a select element with a number of options. The options are treated similarly to an array +// This array is passed to the AI which then chooses the best response. function dropdownFields(){ + // Set up GPT-3 prompt let template = 'This is the users data: ' + JSON.stringify(user) + '\n' + 'Pick the best option for each dropdown.'; let messages = [new SystemMessage({ content: template })]; @@ -79,7 +90,9 @@ function dropdownFields(){ messages.push(new HumanMessage({content: JSON.stringify(genderOptions)})); messages.push(new AIMessage({content: "male"})); + // End of GPT-3 prompt setup + // Placeholder message to be replaced in each loop iteration messages.push(new HumanMessage({content: "placeholder"})); // get dropdowns from page using jquery @@ -88,15 +101,19 @@ function dropdownFields(){ for (let i of dropdowns){ let options = $(i).find('option'); + //covert options to array. Potentially may need to be changed to a Map to account for ambiguous labeling let dropdownOptions = []; for (let j of options){ let option = j as HTMLOptionElement; dropdownOptions.push(option.value); } + // give ai the dropdown options messages[3] = (new HumanMessage({content: JSON.stringify(dropdownOptions)})); + // get ai response let response = chatModel.predictMessages(messages); + // set dropdown value to response response.then((res: BaseMessage) => { if (res instanceof AIMessage){ diff --git a/package-lock.json b/package-lock.json index ed7094d..f8fa36a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", "@types/jest": "^29.5.5", + "@types/jquery": "^3.5.22", "@types/node": "^20.6.3", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", @@ -5372,6 +5373,14 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/@types/jquery": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.22.tgz", + "integrity": "sha512-ISQFeUK5GwRftLK4PVvKTWEVCxZ2BpaqBz0TWkIq5w4vGojxZP9+XkqgcPjxoqmPeew+HLyWthCBvK7GdF5NYA==", + "dependencies": { + "@types/sizzle": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -5520,6 +5529,11 @@ "@types/node": "*" } }, + "node_modules/@types/sizzle": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.4.tgz", + "integrity": "sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag==" + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", diff --git a/package.json b/package.json index c246f6f..e23e747 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", "@types/jest": "^29.5.5", + "@types/jquery": "^3.5.22", "@types/node": "^20.6.3", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7",