javascript: (function () { const getElementDescription = (element) => { const labelsText = Array.from(element.labels) .map((label) => label.innerText) .join(', '); return `${labelsText} ${element.placeholder || ''}`.trim(); }; const formatName = (name) => name.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 63); const getDescription = (element) => { const describeId = element.getAttribute('aria-describedby'); return describeId ? document.querySelector(`#${describeId}`).innerText : ''; }; const getInputSchema = (input) => { const { name, type, min, max, pattern, required } = input; if (!name) return null; const schema = { name, type: type === 'number' ? 'number' : 'string', description: getElementDescription(input), }; if (min) schema.minimum = Number(min); if (max) schema.maximum = Number(max); if (pattern) schema.pattern = pattern; return [formatName(name), schema, required]; }; const getSelectSchema = (select) => { const { name, required } = select; if (!name) return null; return [ formatName(name), { name, type: 'string', description: getElementDescription(select), enum: Array.from(select.options).map((option) => option.value), }, required, ]; }; const getTextareaSchema = (textArea) => { const { name, required } = textArea; if (!name) return null; return [ formatName(name), { name, type: 'string', description: getElementDescription(textArea) }, required, ]; }; const getCheckboxesSchema = ([name, values]) => { const element = document.querySelector(`[name="${name}"]`); const isArray = name.endsWith('[]'); const schema = { name, type: isArray ? 'array' : 'boolean', description: getDescription(element), }; if (isArray) { schema.uniqueItems = true; schema.items = { oneOf: values }; } return [formatName(name), schema]; }; const getRadioSchema = ([name, values]) => { const element = document.querySelector(`[name="${name}"]`); return [ formatName(name), { name, type: 'string', description: getDescription(element), enum: values.map((v) => v.const), }, ]; }; const generateSchema = (form) => { const inputSelectors = [ 'input[type="text"]', 'input[type="email"]', 'input[type="number"]', 'input[type="password"]', 'input[type="tel"]', 'input[type="url"]', 'input[type="date"]', 'input[type="time"]', 'input[type="datetime-local"]', 'input[type="month"]', 'input[type="week"]', 'input[type="color"]', 'input[type="range"]', 'input[type="search"]', ].join(', '); const inputs = Array.from(form.querySelectorAll(inputSelectors)) .map(getInputSchema) .filter(Boolean); const checkboxes = groupByName( Array.from(form.querySelectorAll('input[type="checkbox"]')) ).map(getCheckboxesSchema); const radios = groupByName( Array.from(form.querySelectorAll('input[type="radio"]')) ).map(getRadioSchema); const selects = Array.from(form.getElementsByTagName('select')) .map(getSelectSchema) .filter(Boolean); const textAreas = Array.from(form.getElementsByTagName('textarea')) .map(getTextareaSchema) .filter(Boolean); const schemaProps = [ ...inputs, ...checkboxes, ...radios, ...selects, ...textAreas, ]; const required = schemaProps.filter(([, , r]) => r).map(([name]) => name); return { name: 'fillup_form', description: 'Schema to fill form inputs', parameters: { type: 'object', required, properties: Object.fromEntries( schemaProps.map(([name, schema]) => [name, schema]) ), }, }; }; const fillForm = (formFields, inputData) => { inputData.forEach(([name, value]) => { try { const fieldDef = formFields[name]; const fieldName = fieldDef.name; const fieldElement = document.querySelector(`[name="${fieldName}"]`); if (Array.isArray(value)) { value.forEach((val) => { const checkbox = document.querySelector( `[name="${fieldName}"][value="${val}"]` ); if (checkbox) checkbox.checked = true; }); } else if (fieldElement.type === 'radio') { const radio = document.querySelector( `[name="${fieldName}"][value="${value}"]` ); if (radio) radio.checked = true; } else if (fieldElement) { fieldElement.value = value; } } catch (error) { console.error(`Error filling form field: ${name}`, error); } }); }; const callOpenAiAPI = async ({ api_key, model = 'gpt-4', max_tokens = 3024, tools, messages, }) => { try { const response = await fetch( 'https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { Authorization: `Bearer ${api_key}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model, max_tokens, temperature: 0, tools, messages, }), } ); return await response.json(); } catch (error) { console.error('Error calling OpenAI API:', error); throw error; } }; const groupByName = (arr) => Object.entries( arr.reduce((result, obj) => { const { name, value, id } = obj; if (!result[name]) result[name] = []; result[name].push({ const: value, id, title: getElementDescription(obj), }); return result; }, {}) ); const setupForms = () => { const forms = Array.from(document.getElementsByTagName('form')); forms.forEach((form, i) => { const dialogHtml = ` ✨ Fill

`; const dialogContainer = document.createElement('div'); dialogContainer.innerHTML = dialogHtml; const submitButton = form.querySelector('button[type="submit"]'); submitButton.parentElement.appendChild(dialogContainer); document .getElementById(`btn-submit-${i}`) .addEventListener('click', () => submitForm(submitButton, form, i)); }); }; const submitForm = async (submitButton, form, formId) => { submitButton.classList.add('spinner'); const formSchema = generateSchema(form); const data = document.getElementById(`_data_${formId}`).value; const apiKey = document.getElementById(`_api-key_${formId}`).value; try { const llmResponse = await callOpenAiAPI({ api_key: apiKey, tools: [{ type: 'function', function: formSchema }], tool_choice: 'auto', messages: [ { role: 'user', content: `call "fillup_form" with following data:\n${data}`, }, ], }); const rawData = llmResponse.choices[0].message?.tool_calls?.[0]?.function?.arguments || llmResponse.choices[0].message?.content; const inputData = Object.entries(JSON.parse(rawData)); fillForm(formSchema.parameters.properties, inputData); } catch (error) { console.error('Error processing form submission:', error); } finally { submitButton.classList.remove('spinner'); } }; setupForms(); })();