
在处理复杂的保险理赔表单时很多开发者都遇到过类似的困扰表单步骤繁多、字段含义不明确手动填写耗时且容易出错。最近出现的GPT-5.6-sol模型展示了一种全新的解决方案——它不仅能理解表单逻辑还能自动完成整个填写流程甚至处理文件上传和数据一致性校验。本文将深入探讨如何基于类似技术构建智能表单自动填写系统从技术原理到完整实现为开发者提供一套可落地的解决方案。本文将完整演示一个10步保险理赔表单的自动化处理系统涵盖表单解析、智能填充、文件上传和一致性校验等核心功能。无论你是前端开发者想要优化用户体验还是后端工程师需要处理表单数据都能从中获得实用的技术方案。我们将使用Python作为主要开发语言结合常见的Web自动化工具确保代码可直接复用到实际项目中。1. 智能表单自动化技术概述1.1 什么是表单智能填充技术表单智能填充技术是指利用人工智能模型自动识别、理解和填写Web表单的技术。与传统的前端自动填充不同智能填充系统能够理解表单字段的语义含义根据上下文逻辑生成合适的填写内容并处理复杂的表单交互流程。在实际的保险理赔场景中一个典型的10步表单可能包含个人信息、事故详情、损失评估、证明材料上传等多个环节。智能填充技术需要解决的核心问题包括字段类型识别、数据依赖关系处理、文件上传自动化、表单步骤导航等。1.2 GPT-5.6-sol的技术特点虽然GPT-5.6-sol是前沿的AI模型但其技术思路可以借鉴到实际的开发项目中。这类模型通常具备以下特点多步骤推理能力能够理解复杂的多步骤表单流程上下文感知根据已填写内容动态调整后续填写策略文件处理集成支持证据文件的上传和关联一致性维护确保整个表单内容的逻辑一致性在实际开发中我们可以通过组合现有的AI服务和自动化工具来实现类似功能而不必依赖特定的未公开模型。1.3 应用场景与价值智能表单填充技术在以下场景中具有重要价值保险理赔流程简化复杂的理赔申请提高处理效率政府服务申请自动化处理繁琐的行政审批表格金融开户流程优化银行、证券等机构的开户体验电商退货申请简化消费者退货退款流程对于开发者而言掌握这项技术能够显著提升产品的用户体验减少用户流失同时降低人工处理成本。2. 环境准备与技术选型2.1 开发环境要求为了构建智能表单自动化系统需要准备以下开发环境操作系统要求Windows 10/11, macOS 10.14, 或 Ubuntu 18.04建议使用Linux系统以获得更好的稳定性Python环境Python 3.8或更高版本pip包管理工具virtualenv或conda虚拟环境浏览器环境Chrome浏览器90版本对应版本的ChromeDriver2.2 核心技术依赖我们将使用以下技术栈构建智能表单填充系统# 核心依赖包列表 # requirements.txt selenium4.15.0 beautifulsoup44.12.2 requests2.31.0 openai1.3.0 pillow10.0.1 python-dotenv1.0.0 pandas2.1.0 numpy1.24.02.3 项目结构设计在开始编码前我们先设计合理的项目结构insurance_form_auto_fill/ ├── src/ │ ├── form_analyzer.py # 表单解析器 │ ├── field_classifier.py # 字段分类器 │ ├── data_generator.py # 数据生成器 │ ├── auto_filler.py # 自动填充器 │ └── file_uploader.py # 文件上传处理器 ├── config/ │ ├── form_templates/ # 表单模板配置 │ └── field_mappings/ # 字段映射配置 ├── tests/ # 测试用例 ├── docs/ # 文档 └── examples/ # 使用示例2.4 环境配置步骤按照以下步骤配置开发环境# 1. 创建虚拟环境 python -m venv form_auto_fill_env source form_auto_fill_env/bin/activate # Linux/macOS # form_auto_fill_env\Scripts\activate # Windows # 2. 安装依赖 pip install -r requirements.txt # 3. 下载ChromeDriver # 访问 https://chromedriver.chromium.org/ 下载对应版本 # 或将ChromeDriver所在目录添加到PATH环境变量 # 4. 配置环境变量 cp .env.example .env # 在.env文件中配置必要的API密钥和参数3. 表单解析与字段识别技术3.1 HTML表单结构分析保险理赔表单通常采用复杂的HTML结构包含多种输入类型和验证规则。我们需要首先分析表单的DOM结构# src/form_analyzer.py from selenium import webdriver from selenium.webdriver.common.by import By from bs4 import BeautifulSoup import re class FormAnalyzer: def __init__(self, driver): self.driver driver self.form_data {} def analyze_form_structure(self, form_selectorform): 分析表单整体结构 forms self.driver.find_elements(By.TAG_NAME, form) form_info [] for form in forms: form_id form.get_attribute(id) or anonymous_form form_action form.get_attribute(action) or N/A # 获取所有输入字段 inputs form.find_elements(By.TAG_NAME, input) selects form.find_elements(By.TAG_NAME, select) textareas form.find_elements(By.TAG_NAME, textarea) form_info.append({ id: form_id, action: form_action, input_count: len(inputs), select_count: len(selects), textarea_count: len(textareas), fields: self._extract_field_details(form) }) return form_info def _extract_field_details(self, form_element): 提取字段详细信息 fields [] # 处理input字段 inputs form_element.find_elements(By.TAG_NAME, input) for input_field in inputs: field_info { type: input_field.get_attribute(type) or text, name: input_field.get_attribute(name), id: input_field.get_attribute(id), placeholder: input_field.get_attribute(placeholder), required: input_field.get_attribute(required) is not None, label: self._find_associated_label(input_field) } fields.append(field_info) return fields def _find_associated_label(self, field): 查找关联的label标签 # 通过for属性匹配 field_id field.get_attribute(id) if field_id: try: label self.driver.find_element(By.CSS_SELECTOR, flabel[for{field_id}]) return label.text.strip() except: pass # 尝试查找父级或相邻的label try: parent field.find_element(By.XPATH, ./..) labels parent.find_elements(By.TAG_NAME, label) if labels: return labels[0].text.strip() except: pass return None3.2 字段语义分类算法不同类型的表单字段需要不同的处理策略。我们基于字段属性进行智能分类# src/field_classifier.py class FieldClassifier: def __init__(self): self.field_patterns { personal_name: [ r.*name.*, r.*姓名.*, r.*fullname.*, rfirstname, rlastname, r姓名 ], email: [r.*email.*, r.*邮件.*, r.*e-mail.*], phone: [r.*phone.*, r.*电话.*, r.*mobile.*], date: [r.*date.*, r.*时间.*, r.*day.*], address: [r.*address.*, r.*地址.*, r.*住址.*], insurance_policy: [r.*policy.*, r.*保单.*, r.*保险单.*], accident_description: [r.*description.*, r.*描述.*, r.*详情.*], damage_amount: [r.*amount.*, r.*金额.*, r.*损失.*] } def classify_field(self, field_info): 根据字段信息进行分类 field_name (field_info.get(name) or ).lower() field_id (field_info.get(id) or ).lower() field_placeholder (field_info.get(placeholder) or ).lower() field_label (field_info.get(label) or ).lower() # 合并所有文本信息进行模式匹配 search_text .join([field_name, field_id, field_placeholder, field_label]) for category, patterns in self.field_patterns.items(): for pattern in patterns: if re.search(pattern, search_text, re.IGNORECASE): return category # 根据输入类型进行默认分类 field_type field_info.get(type, text) if field_type in [email]: return email elif field_type in [tel, phone]: return phone elif field_type in [date, datetime]: return date return text3.3 多步骤表单导航策略10步保险理赔表单需要智能的导航控制# src/form_navigator.py class FormNavigator: def __init__(self, driver): self.driver driver self.current_step 0 self.total_steps 0 self.navigation_history [] def detect_form_steps(self): 检测表单的分步结构 # 查找分步指示器 step_indicators self.driver.find_elements( By.CSS_SELECTOR, .step, .progress, [class*step], [class*progress] ) # 查找下一步按钮 next_buttons self.driver.find_elements( By.CSS_SELECTOR, button[typesubmit], input[typesubmit], .next, [class*next] ) # 分析URL模式如果是多页面表单 current_url self.driver.current_url step_patterns [rstep(\d), rpage(\d), r/\d/] step_info { indicators: len(step_indicators), next_buttons: len(next_buttons), estimated_steps: self._estimate_total_steps() } return step_info def navigate_to_next_step(self): 导航到下一步 try: # 尝试点击下一步按钮 next_button self.driver.find_element( By.CSS_SELECTOR, button[typesubmit], input[typesubmit], .next-btn ) next_button.click() self.current_step 1 self.navigation_history.append(next_button) return True except: # 备用导航策略 return self._alternative_navigation() def _estimate_total_steps(self): 估算总步骤数 # 基于常见保险理赔流程的启发式估算 common_insurance_steps [ 个人信息, 保单信息, 事故详情, 损失评估, 证人信息, 医疗记录, 财产损失, 文件上传, 确认信息, 提交申请 ] return len(common_insurance_steps)4. 智能数据生成与填充引擎4.1 基于上下文的数据生成针对不同类型的表单字段我们需要生成合适的测试数据# src/data_generator.py import random from datetime import datetime, timedelta import string class InsuranceDataGenerator: def __init__(self): self.personal_templates self._load_personal_templates() self.accident_templates self._load_accident_templates() def generate_field_data(self, field_type, contextNone): 根据字段类型生成合适的数据 generators { personal_name: self._generate_name, email: self._generate_email, phone: self._generate_phone, date: self._generate_date, address: self._generate_address, insurance_policy: self._generate_policy_number, accident_description: self._generate_accident_description, damage_amount: self._generate_damage_amount } generator generators.get(field_type, self._generate_text) return generator(context) def _generate_name(self, contextNone): 生成中文姓名 surnames [李, 王, 张, 刘, 陈, 杨, 赵, 黄, 周, 吴] first_names [明, 伟, 芳, 秀英, 娜, 强, 静, 磊, 军, 勇] return random.choice(surnames) random.choice(first_names) def _generate_email(self, contextNone): 生成邮箱地址 domains [gmail.com, qq.com, 163.com, outlook.com, yahoo.com] username .join(random.choices(string.ascii_lowercase, k8)) return f{username}{random.choice(domains)} def _generate_phone(self, contextNone): 生成手机号码 prefixes [130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 150, 151, 152, 153, 155, 156, 157, 158, 159, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189] return random.choice(prefixes) .join(random.choices(0123456789, k8)) def _generate_accident_description(self, contextNone): 生成事故描述 templates [ 在{地点}发生交通事故对方车辆{行为}导致碰撞, 因{原因}造成财产损失需要申请理赔, 在{时间}于{地点}发生意外事故导致{损失} ] template random.choice(templates) placeholders { 地点: random.choice([十字路口, 停车场, 高速公路, 小区内部道路]), 行为: random.choice([违规变道, 闯红灯, 倒车不慎, 超速行驶]), 原因: random.choice([天气恶劣, 路面湿滑, 能见度低, 机械故障]), 时间: random.choice([上午, 下午, 晚上]), 损失: random.choice([车辆损坏, 人员受伤, 财产损失]) } return template.format(**placeholders)4.2 数据一致性维护机制确保整个表单数据在逻辑上保持一致# src/data_consistency.py class DataConsistencyManager: def __init__(self): self.context_data {} self.validation_rules {} def set_context(self, key, value): 设置上下文数据 self.context_data[key] value def validate_consistency(self, field_type, value, dependenciesNone): 验证数据一致性 if dependencies: for dep_field, dep_value in dependencies.items(): if dep_field in self.context_data: if not self._check_dependency(field_type, value, dep_field, self.context_data[dep_field]): return False return self._validate_field_rules(field_type, value) def _check_dependency(self, field_type, value, dep_field, dep_value): 检查字段依赖关系 # 示例事故日期不能早于保单生效日期 if field_type accident_date and dep_field policy_start_date: accident_date datetime.strptime(value, %Y-%m-%d) policy_date datetime.strptime(dep_value, %Y-%m-%d) return accident_date policy_date # 示例损失金额应该合理 if field_type damage_amount and dep_field insurance_limit: damage float(value) limit float(dep_value) return damage limit * 1.1 # 允许10%的浮动 return True def _validate_field_rules(self, field_type, value): 验证字段规则 rules { email: lambda v: in v and . in v.split()[-1], phone: lambda v: v.isdigit() and len(v) 11, date: lambda v: self._is_valid_date(v), damage_amount: lambda v: v.replace(., ).isdigit() and float(v) 0 } if field_type in rules: return rules[field_type](value) return True def _is_valid_date(self, date_str): 验证日期格式 try: datetime.strptime(date_str, %Y-%m-%d) return True except ValueError: return False4.3 智能填充执行引擎整合以上组件构建完整的自动填充系统# src/auto_filler.py from selenium.webdriver.support.ui import Select import time class InsuranceFormAutoFiller: def __init__(self, driver): self.driver driver self.form_analyzer FormAnalyzer(driver) self.field_classifier FieldClassifier() self.data_generator InsuranceDataGenerator() self.consistency_manager DataConsistencyManager() self.navigator FormNavigator(driver) def fill_entire_form(self, url, form_dataNone): 填充整个表单流程 self.driver.get(url) # 分析表单结构 form_info self.form_analyzer.analyze_form_structure() # 逐步处理每个表单步骤 for step in range(10): # 假设10步表单 if not self._process_current_step(): break # 导航到下一步 if step 9: # 最后一步不需要导航 time.sleep(1) # 等待页面加载 self.navigator.navigate_to_next_step() time.sleep(2) # 等待下一步加载 return self._get_fill_summary() def _process_current_step(self): 处理当前步骤的表单字段 try: # 获取当前页面的所有表单字段 form_elements self.driver.find_elements(By.TAG_NAME, form) if not form_elements: return False current_form form_elements[0] fields self.form_analyzer._extract_field_details(current_form) for field_info in fields: self._fill_single_field(field_info) return True except Exception as e: print(f处理步骤时出错: {e}) return False def _fill_single_field(self, field_info): 填充单个字段 field_type self.field_classifier.classify_field(field_info) # 生成合适的数据 context self.consistency_manager.context_data field_value self.data_generator.generate_field_data(field_type, context) # 验证数据一致性 if self.consistency_manager.validate_consistency(field_type, field_value): # 执行实际填充 self._execute_fill_action(field_info, field_value) # 更新上下文 field_name field_info.get(name) or field_info.get(id) if field_name: self.consistency_manager.set_context(field_name, field_value) def _execute_fill_action(self, field_info, value): 执行具体的填充操作 field_type field_info.get(type, text) try: if field_type in [text, email, tel, number, date]: # 文本输入框 input_element self.driver.find_element( By.CSS_SELECTOR, finput[name{field_info[name]}] ) input_element.clear() input_element.send_keys(value) elif field_type select: # 下拉选择框 select_element Select(self.driver.find_element( By.CSS_SELECTOR, fselect[name{field_info[name]}] )) select_element.select_by_visible_text(value) elif field_type textarea: # 文本区域 textarea self.driver.find_element( By.CSS_SELECTOR, ftextarea[name{field_info[name]}] ) textarea.clear() textarea.send_keys(value) elif field_type radio: # 单选按钮 radio self.driver.find_element( By.CSS_SELECTOR, finput[typeradio][name{field_info[name]}][value{value}] ) radio.click() elif field_type checkbox: # 复选框 checkbox self.driver.find_element( By.CSS_SELECTOR, finput[typecheckbox][name{field_info[name]}] ) if not checkbox.is_selected(): checkbox.click() except Exception as e: print(f填充字段 {field_info.get(name)} 时出错: {e})5. 文件上传与证据处理5.1 智能文件上传机制保险理赔表单通常需要上传各种证明文件# src/file_uploader.py import os from PIL import Image, ImageDraw import tempfile class EvidenceFileUploader: def __init__(self, driver): self.driver driver self.temp_files [] def handle_file_upload(self, field_info, file_typeNone): 处理文件上传字段 if not file_type: file_type self._detect_required_file_type(field_info) # 生成或获取合适的文件 file_path self._generate_sample_file(file_type) # 执行上传操作 self._perform_upload(field_info, file_path) return file_path def _detect_required_file_type(self, field_info): 检测需要的文件类型 field_name (field_info.get(name) or ).lower() field_label (field_info.get(label) or ).lower() file_patterns { image: [r.*photo.*, r.*image.*, r.*图片.*, r.*照片.*], document: [r.*document.*, r.*pdf.*, r.*文件.*, r.*证明.*], invoice: [r.*invoice.*, r.*receipt.*, r.*发票.*, r.*收据.*] } search_text f{field_name} {field_label} for file_type, patterns in file_patterns.items(): for pattern in patterns: if re.search(pattern, search_text, re.IGNORECASE): return file_type return document # 默认类型 def _generate_sample_file(self, file_type): 生成示例文件 generators { image: self._generate_sample_image, document: self._generate_sample_pdf, invoice: self._generate_sample_invoice } generator generators.get(file_type, self._generate_sample_document) return generator() def _generate_sample_image(self): 生成示例图片 # 创建临时图片文件 temp_file tempfile.NamedTemporaryFile(suffix.jpg, deleteFalse) # 生成简单的示例图片 img Image.new(RGB, (800, 600), colorwhite) draw ImageDraw.Draw(img) draw.text((100, 100), 保险理赔示例图片, fillblack) draw.rectangle([50, 50, 750, 550], outlineblack, width2) img.save(temp_file.name) self.temp_files.append(temp_file.name) return temp_file.name def _perform_upload(self, field_info, file_path): 执行实际上传操作 try: # 查找文件上传输入框 file_input self.driver.find_element( By.CSS_SELECTOR, finput[typefile][name{field_info[name]}] ) # 发送文件路径 file_input.send_keys(file_path) # 等待上传完成 time.sleep(2) except Exception as e: print(f文件上传失败: {e}) # 备用上传方案 self._alternative_upload_method(field_info, file_path) def cleanup_temp_files(self): 清理临时文件 for temp_file in self.temp_files: try: if os.path.exists(temp_file): os.unlink(temp_file) except: pass self.temp_files []5.2 多文件批量上传支持处理需要上传多个文件的情况# src/multi_file_uploader.py class MultiFileUploadHandler: def __init__(self, driver): self.uploader EvidenceFileUploader(driver) def handle_multi_file_upload(self, field_info, file_count3): 处理多文件上传 file_type self.uploader._detect_required_file_type(field_info) uploaded_files [] for i in range(file_count): file_path self.uploader._generate_sample_file(file_type) uploaded_files.append(file_path) # 检查是否支持多文件选择 try: file_input self.driver.find_element( By.CSS_SELECTOR, finput[typefile][name{field_info[name]}] ) # 如果支持multiple属性可以一次选择多个文件 if file_input.get_attribute(multiple): all_files \n .join(uploaded_files) file_input.send_keys(all_files) else: # 逐个上传 for file_path in uploaded_files: file_input.send_keys(file_path) time.sleep(1) # 等待每个文件上传完成 except Exception as e: print(f多文件上传失败: {e}) return uploaded_files6. 完整实战案例10步保险理赔表单自动化6.1 案例场景设定假设我们有一个真实的保险理赔网站包含以下10个步骤个人信息登记姓名、联系方式、身份证号保单信息确认保单号、保险类型、生效日期事故基本信息时间、地点、事故类型事故详细描述经过、原因、责任认定损失情况评估车辆损失、人身伤害、财产损失相关方信息对方信息、证人信息医疗记录如适用医院、诊断、费用维修估价维修厂、估价单、照片证明文件上传事故证明、医疗单据、维修发票信息确认提交最终确认并提交申请6.2 完整实现代码# examples/insurance_claim_auto_fill.py from selenium import webdriver from selenium.webdriver.chrome.options import Options from src.auto_filler import InsuranceFormAutoFiller from src.file_uploader import EvidenceFileUploader import time import json class InsuranceClaimAutomation: def __init__(self, headlessTrue): self.setup_driver(headless) self.auto_filler InsuranceFormAutoFiller(self.driver) self.uploader EvidenceFileUploader(self.driver) def setup_driver(self, headless): 设置WebDriver chrome_options Options() if headless: chrome_options.add_argument(--headless) chrome_options.add_argument(--no-sandbox) chrome_options.add_argument(--disable-dev-shm-usage) chrome_options.add_argument(--disable-blink-featuresAutomationControlled) chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) chrome_options.add_experimental_option(useAutomationExtension, False) self.driver webdriver.Chrome(optionschrome_options) self.driver.execute_script(Object.defineProperty(navigator, webdriver, {get: () undefined})) def automate_insurance_claim(self, target_url): 执行完整的保险理赔自动化流程 try: print(开始保险理赔表单自动化处理...) # 访问目标网站 self.driver.get(target_url) time.sleep(3) # 记录开始时间 start_time time.time() # 执行10步表单填充 result self.auto_filler.fill_entire_form(target_url) # 处理文件上传步骤 self._handle_file_upload_step() # 最终确认和提交 self._final_confirmation() # 记录完成时间 end_time time.time() duration end_time - start_time print(f自动化流程完成耗时: {duration:.2f}秒) return { success: True, duration: duration, steps_completed: 10, details: result } except Exception as e: print(f自动化流程失败: {e}) return { success: False, error: str(e) } finally: self.cleanup() def _handle_file_upload_step(self): 专门处理文件上传步骤 try: # 查找文件上传字段 file_inputs self.driver.find_elements(By.CSS_SELECTOR, input[typefile]) for file_input in file_inputs: field_name file_input.get_attribute(name) field_info {name: field_name, type: file} # 根据字段名判断文件类型 if photo in field_name.lower() or image in field_name.lower(): file_type image elif document in field_name.lower() or proof in field_name.lower(): file_type document else: file_type None self.uploader.handle_file_upload(field_info, file_type) except Exception as e: print(f文件上传处理失败: {e}) def _final_confirmation(self): 最终确认步骤 try: # 查找确认复选框 confirm_checkboxes self.driver.find_elements( By.CSS_SELECTOR, input[typecheckbox][name*confirm], input[typecheckbox][name*agree] ) for checkbox in confirm_checkboxes: if not checkbox.is_selected(): checkbox.click() # 等待用户 review在实际使用中可能需要调整 time.sleep(2) # 提交表单 submit_buttons self.driver.find_elements( By.CSS_SELECTOR, button[typesubmit], input[typesubmit] ) if submit_buttons: # 在实际生产环境中可能需要更谨慎的提交策略 # submit_buttons[0].click() print(检测到提交按钮演示模式中不实际提交) except Exception as e: print(f最终确认步骤失败: {e}) def cleanup(self): 清理资源 self.uploader.cleanup_temp_files() if self.driver: self.driver.quit() # 使用示例 if __name__ __main__: # 示例URL实际使用时替换为真实的保险理赔网站 sample_url https://example-insurance.com/claim-form automation InsuranceClaimAutomation(headlessFalse) result automation.automate_insurance_claim(sample_url) print(自动化结果:) print(json.dumps(result, indent2, ensure_asciiFalse))6.3 运行结果验证# examples/result_validator.py class ResultValidator: def __init__(self, driver): self.driver driver def validate_fill_results(self): 验证填充结果 validation_results { personal_info: self._validate_personal_info(), policy_info: self._validate_policy_info(), accident_details: self._validate_accident_details(), file_uploads: self._validate_file_uploads(), overall_completion: self._validate_overall_completion() } return validation_results def _validate_personal_info(self): 验证个人信息填写 try: # 检查关键个人信息字段是否已填写 required_fields [name, email, phone, id_number] filled_count 0 for field in required_fields: field_element self.driver.find_elements( By.CSS_SELECTOR, finput[name*{field}] ) if field_element and field_element[0].get_attribute(value): filled_count 1 return { status: success if filled_count 3 else partial, filled_fields: filled_count, total_fields: len(required_fields) } except: return {status: error, details: 验证失败} def _validate_overall_completion(self): 验证整体完成度 try: # 统计所有输入字段的填写比例 all_inputs self.driver.find_elements(By.TAG_NAME, input) all_textareas self.driver.find_elements(By.TAG_NAME, textarea) all_selects self.driver.find_elements(By.TAG_NAME, select) total_fields len(all_inputs) len(all_textareas) len(all_selects) filled_fields 0 # 检查输入框 for input_field in all_inputs: if input_field.get_attribute(type) not in [hidden, submit, button]: if input_field.get_attribute(value): filled_fields 1 # 检查文本区域 for textarea in all_textareas: if textarea.get_attribute(value): filled_fields 1 # 检查选择框假设有选中值就是已填写 for select in all_selects: filled_fields 1 # 简化处理 completion_rate (filled_fields / total_fields) * 100 if total_fields 0 else 0 return { completion_rate: round(completion_rate, 2), filled_fields: filled_fields, total_fields: total_fields, status: excellent if completion_rate 90 else