百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

AI驱动的表单自动填写 ai智能填报

myzbx 2024-12-22 19:43 31 浏览

我们都同意,填写表格是一项枯燥且耗时的任务。如果我们可以创建一个可以为我们填写表格的 AI 助手,让我们将时间投入到更有建设性的任务中,那会怎样?

AI 助手将能够通过调用以表单字段为参数的函数来填写表单。该函数将返回一个 JSON 对象,其中表单字段作为键,值作为要填写的值。

网络上有无数的表单,每个表单都有自己独特的结构和命名约定。直到最近,几乎不可能创建一个可以填写任何表格的通用助手。但随着 LLM 的出现,我们可以创建一个。

在大多数情况下,函数调用允许 LLM 与 API 交互,但绝大多数 Web 应用程序不公开 API,与它们交互的唯一方法是填写表格。

本文的受众

本文适用于想要了解大型语言模型 (LLM)(如 OpenAI 或 Anthropic)“函数调用”功能基础知识的程序员。

函数调用是 LLM 的基本功能,允许创建可以与外部世界交互的专用工具、代理或助手。本文将向你展示如何创建一个可以填写 HTML 表单的简单 AI 助手。

你将学到什么

通过为 LLM 提供函数签名的定义来启用函数调用。函数签名是函数预期输入属性的描述。

你将学习如何创建动态生成的 JSON 模式函数签名,允许 AI 助手与 HTML 表单交互。

JSON 模式是定义和验证 JSON 对象结构的强大工具。出于教育目的,将不使用任何外部库,只使用纯 JavaScript 代码。

1、原理及实现代码

表单可能彼此非常不同,但它们都是使用输入字段、文本区域、复选框、单选按钮等常见元素构建的。

我们将仅讨论脚本中最重要的部分。完整脚本可在此处找到。

首先,我们需要识别表单元素及其类型。无论元素类型如何,每个元素都应该有一个 name属性,该属性稍后将用作 JSON 对象中的键。

对于每种元素类型,我们将创建一个函数,该函数将返回定义元素的 JSON 模式片段。JSON 模式应包含元素用途的描述。

这对于 LLM 了解元素的用途或预期值非常有用。描述的文本将从元素的标签或占位符属性中收集。

每个元素的 Json 模式属性至少包含:

  • name:元素的名称
  • type:元素类型,通常是字符串
  • description:元素描述

然后我们可以根据元素类型拥有更多附加字段。例如,对于输入元素,我们可以有最小、最大、模式和必填字段。

对于选择元素、单选或复选框元素,我们还添加了包含所有可能值的枚举字段。特定的复选框和单选元素应该以特殊方式处理,因为它们可以具有与一个名称相关的多个值选项。

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])
      ),
    },
  };
};

此函数扫描表单中的所有输入元素并为每个元素创建一个架构。它按名称对复选框和单选按钮进行分组,并为每个组创建一个架构。最后,它创建一个包含所有表单元素的 JSON 架构。

在这里,我们定义了一个将调用 OpenAI chat completitions API 的函数。我们提供模型名称(在本例中为“gpt-4o”,这保证了函数调用的良好结果)和 API 密钥,同时我们将“温度”设置为 0 以获得确定性结果。

const callOpenAiAPI = async ({
  api_key,
  model = 'gpt-4o',
  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;
  }
};

最后,我们可以向 OpenAI API 提交请求,并用响应填写表单。我们利用“工具”功能提供生成的模式。在这里,我们使用“自动”工具选择让 OpenAI 选择最适合该工作的工具。

我们将要填写在表单中的数据作为消息提供给 AI 助手,使用非常简单的提示调用 fillup_form,其中包含以下数据: \n${data}。

我们可以以类似的方式调用 Anthropic API,而不是 openAi。

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');
  }
};

上述函数返回来自 OpenAI API 的响应,其中对象将表单字段映射到要填写的值。然后我们调用 fillForm 函数用响应填充表单。瞧!表单已填写。

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);
    }
  });
};

2、可以用它做什么?

可以通过添加更多高级功能(如处理文件上传、处理动态表单等)进一步改进此脚本。可能的进一步发展:

  • 浏览器扩展将根据存储的配置文件自动填写页面上的表单。
  • 可以创建 AI 代理来代表我们填写表单。
  • 可以创建自动数据输入工具,该工具将根据数据库或任何其他来源的数据填写表单。
  • 在需要保护隐私的情况下,使用 LLM 生成虚假数据。
  • 我们可以使用一些持久层扩展脚本以存储填充的值,以便将来使用它们。

如果表单非常复杂且包含大量字段,请将表单拆分为较小的部分(字段集)并分别填写。

3、结束语

此脚本应该适用于大多数表单。但是,如果表单是动态的(某些表单元素在用户输入时会更改或激活)或使用一些高级功能(如文件上传)或以非标准或错误的方式构建,它可能无法按预期工作。在这种情况下,你可能需要调整脚本以处理这些情况。


原文链接:AI驱动的自动表单填写 - 汇智网

相关推荐

别让水 “跑” 出卫生间!下沉设计打造滴水不漏的家

你是否遭遇过卫生间的水“偷偷溜”进客厅,导致木地板鼓起、墙角发霉的糟心事?又是否为卫生间门口反复渗漏,不得不一次次返工维修而头疼不已?在家庭装修中,卫生间防水堪称“兵家必争之地”,而卫生间门口下...

歼-10CE vs 阵风:谁才是空中霸主?全面性能对比解析

歼10CE与法国阵风战斗机性能深度对比分析一、总体定位与设计哲学歼10CE:单发中型多用途战斗机,侧重于空优(制空权争夺)和对地对海打击,具有较高的性价比和较强的多任务能力。法国阵风战斗机:双发中型多...

知名移植工作室肯定Switch2的图形性能,却被CPU拖了后腿

虽然Switch2发售多日,但没入手的玩家对其性能还是有顾虑。近日,知名移植工作室Virtuos的技术总监在接受采访时讨论了Switch2的性能,并给出了他们工作室的评价。简单来说,Switch2在D...

虹科实测 | CAN XL vs CAN FD传输性能深度对比:速率翻倍,抖动锐减!

导读在汽车电子与工业通信领域,CAN协议持续进化,推动着数据传输效率的提升。本次实测基于虹科PCAN-USBXL与虹科PCAN-USBProFD硬件,在同等严苛条件下对比CANXL与CANF...

1J117合金材料优异的耐腐蚀性、机械性能

1J117合金材料概述定义:1J117是一种不锈软磁精密合金,属于铁铬基合金,其圆棒产品具有特定的形状和尺寸,可满足各种工业应用中的特定需求。标准:技术条件标准为GB/T14986,品种规格标准...

据高管所称,Switch2能轻松移植XSS平台60帧游戏

任天堂,作为主机游戏界的御三家之一,一直注重游戏性而不注重更新升级硬件设备是其最大的特点。各位任豚们,忍受着任天堂早已落后硬件设备,真想感叹一句,天下苦任久矣!但Switch2的出现或许正在渐渐的改变...

FJK-110LED-HXJSN磁传感器有哪应用

作为一名从事电子技术相关工作的自媒体人,我经常会遇到各种传感器的应用问题。其中,FJK-110LED-HXJSN磁传感器是一款在工业自动化、智能设备等领域比较常见的磁场检测元件。今天我想和大家聊一聊这...

浅谈欧标方管200x200x5-12mm质S275JRH的优势与劣势

欧标方管200x200x5-12mm材质S275JRH是一种常见的结构用钢材,广泛应用于建筑、机械制造、桥梁、钢结构等领域。本文将对这种方管的优势与劣势进行浅谈,以帮助读者更好地了解其特性和适用场景。...

宽带拨号错误 651 全解析:故障定位与修复方案

在使用PPPoE拨号连接互联网时,错误651提示「调制解调器或其他连接设备报告错误」,通常表明从用户终端到运营商机房的链路中存在异常。以下从硬件、系统、网络三层维度展开排查:一、故障成因分类图...

模型微调:从理论到实践的深度解析

在人工智能领域,模型微调已成为提升模型性能、使其适应特定任务的关键技术。本文将全面系统地介绍模型微调的各个方面,帮助读者深入理解这一重要技术。一、什么是模型微调模型微调是指在已经训练好的预训练模型基础...

汉语拼音 z、c、s图文讲解(拼音字母表zcs教学视频)

以下是汉语拼音z、c、s的图文讲解,结合发音要领、书写规范及教学技巧:一、发音方法与口诀1.z的发音发音要领:舌尖轻抵上齿背,形成阻碍后稍放松,气流从窄缝中挤出,声带不振动(轻短音)。口诀:“写字写...

吴姗儒惹怒刘宇宁粉丝!吴宗宪护航「是综艺梗」叮咛女儿对话曝光

记者孟育民/台北报道Sandy吴姗儒在《小姐不熙娣》因为节目效果,将男星刘宇宁的头像踩在地上,引起粉丝怒火,节目发声明道歉后仍未平息,她也亲自发文郑重道歉:「我对刘宇宁本人完全没有任何恶意,却在综艺表...

苹果错误地发布了macOS Tahoe公开测试版 现已将其撤下

一些Beta测试人员下载了他们以为是macOSSequoia15.6RC的版本,但却错误地下载了macOSTahoe26公开测试版,后来苹果修复了该问题。苹果预计将于7月25...

make的多种用法!(make 的用法总结)

一、make的用法美make[meik]①V.制造;制定,拟定;使变得,使处于;造成,引起;整理(床铺);做,作出;强迫;挑选,任命…②n.(机器、设备等的)品牌,型号;结构,构造;通电,接电⑤[...

北顿尖刀哗变?俄第20近卫集团军损失惨重,拒绝执行指挥官命令?

【军武次位面】作者:太白近日,外国社交媒体“电报”上传出了一些消息,称俄罗斯在北顿涅兹克战场上的“尖刀”部队之一,俄第20近卫集团军因为损失惨重,已经出现了部分部队拒绝执行指挥官命令,甚至哗变的情况。...