backend / tools /TOOLS_README.md
KevanSoon
added new tools folder
83704ca

Test Summary Tool:

curl -X POST "http://localhost:8080/api/analyze_html" -F "[email protected];type=text/html"

response:

{
  "summary": "This payslip shows earnings including base salary, allowances, and overtime pay, with deductions for advances, loans, and CPF, resulting in a net pay of 2363.40 or 4213.40.  CPF contributions are also detailed.",
  "earnings": [
    "基 本工资 (Basic Salary): 1800.00",
    "总加班费 (Total Overtime): 368.16",
    "[加班1.5倍] (Overtime 1.5x): 141.60",
    "[加班2.0倍] (Overtime 2.0x): 226.56",
    "住宿补贴 (Housing Allowance): 450.00",
    "特别津贴 (Special Allowance): 100.00",
    "交通津贴 (Transport Allowance): 300.00",
    "雇主公积金 (Employer CPF): 180.00"
  ],
  "deductions": [
    "第一周预支 (First Week Advance): -300.00",
    "员工贷款 (Employee Loan): -80.00",
    "CDAC: -1.00",
    "员工公积金 (Employee CPF): -191.00",
    "总无薪假 (Total Unpaid Leave): -82.76"
  ],
  "additional_info": {
    "gross_pay": ["2935.40", "4935.40"],
    "net_pay": ["2363.40", "4213.40"],
    "cpf_salary": ["2555.40", "4555.40"],
    "total_cpf": ["371.00", "661.00"],
    "annual_leave": { "used": "1.00", "balance": "48.00" },
    "medical_leave": { "used": "0.00", "balance": "14.00" },
    "bank_details": {
      "bank": "华侨银行 (OCBC Bank)",
      "account_number": "151179932"
    }
  }
}

Test Keyword Tool:

curl -X POST "http://localhost:8080/api/verify_document_keywords" -F "[email protected];type=text/html" -F "analysis_type=legality" -F "search_context=Singapore employment law"

reponse:

{
  "analysis_configuration": {
    "analysis_type": "legality",
    "search_context": "Singapore employment law"
  },
  "verification_results": [
    {
      "claim": "基本工资 1800.00",
      "summary": "Claim states a base salary of 1800.00. No evidence to verify.",
      "status": "Needs Manual Review"
    },
    {
      "claim": "[ 加班1. 5倍 ] 10. 00小时 x $ 14. 16 = 141. 60",
      "summary": "Claim states overtime pay at 1.5x rate for 10 hours. The calculation needs verification. No evidence to verify the hourly rate or overtime policy.",
      "status": "Needs Manual Review"
    },
    {
      "claim": "[ 加班2. 0倍 ] 12. 00小时 x $ 18. 88 = 226. 56",
      "summary": "Claim states overtime pay at 2.0x rate for 12 hours. The calculation needs verification. No evidence to verify the hourly rate or overtime policy.",
      "status": "Needs Manual Review"
    },
    {
      "claim": "员工公积金 - 191. 00",
      "summary": "Claim states a deduction of 191.00 for employee housing fund. No evidence to verify the legality or accuracy.",
      "status": "Needs Manual Review"
    },
    {
      "claim": "年假 / 已用 / 余额 : 1. 00 / 1. 00 / 48. 00",
      "summary": "Claim states vacation leave information. No evidence to verify the accuracy or legality of the leave policy.",
      "status": "Needs Manual Review"
    }
  ]
}

New tool:

curl -X POST "http://localhost:8080/api/analyze_contract" -F "file=@full_pipeline_example.html;type=text/html"
{
  "language": "en",
  "extracted_data": {
    "employer": {
      "text": "ABC PTE \t\t\t有限公司",
      "summary": "The employer is ABC PTE \t\t\t有限公 司."
    },
    "employee": {
      "text": "\t\t\t吨啊 Kow",
      "summary": "The employee's name is \t\t\t吨啊 Kow."
    },
    "pay_period": {
      "text": "2021\t\t\t 年9月1日 - 2021\t\t\t年9月30日",
      "summary": "The pay period is from September 1, 2021 to September 30, 2021."
    },
    "salary": { "text": "2000美元", "summary": "The base salary is 2000 USD." },
    "bonus": { "text": "2000美元", "summary": "The bonus payment is 2000 USD." }
  },
  "summary_sheet_html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Payslip Summary</title>\n<style>\nbody {\n  font-family: sans-serif;\n  margin: 20px;\n}\n\n.container {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 20px;\n}\n\n.card {\n  background-color: #f2f2f2;\n  padding: 20px;\n  border-radius: 5px;\n  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);\n  min-width: 300px;\n}\n\nh2 {\n  color: #333;\n}\n\nh3 {\n  color: #555;\n  font-style: italic;\n}\n</style>\n</head>\n<body>\n\n<div class=\"container\">\n\n  <div class=\"card\">\n    <h2>Employer</h2>\n    <h3>The employer is ABC PTE 有限公司.</h3>\n    <p>ABC PTE     有限公司</p>\n  </div>\n\n  <div class=\"card\">\n    <h2>Employee</h2>\n    <h3>The employee's name is 吨啊 Kow.</h3>\n    <p>吨啊 Kow</p>\n  </div>\n\n  <div class=\"card\">\n    <h2>Pay Period</h2>\n    <h3>The pay period is from September 1, 2021 to September 30, 2021.</h3>\n    <p>2021年9月1日 - 2021年9月30日</p>\n  </div>\n\n  <div class=\"card\">\n    <h2>Salary</h2>\n    <h3>The base salary is 2000 USD.</h3>\n    <p>2000美元</p>\n  </div>\n\n  <div class=\"card\">\n    <h2>Bonus</h2>\n    <h3>The bonus payment is 2000 USD.</h3>\n    <p>2000美元</p>\n  </div>\n\n</div>\n\n</body>\n</html>",
  "debug_visualization_html": "<style>\n.lx-highlight { position: relative; border-radius:3px; padding:1px 2px;}\n.lx-highlight .lx-tooltip {\n  visibility: hidden;\n  opacity: 0;\n  transition: opacity 0.2s ease-in-out;\n  background: #333;\n  color: #fff;\n  text-align: left;\n  border-radius: 4px;\n  padding: 6px 8px;\n  position: absolute;\n  z-index: 1000;\n  bottom: 125%;\n  left: 50%;\n  transform: translateX(-50%);\n  font-size: 12px;\n  max-width: 240px;\n  white-space: normal;\n  box-shadow: 0 2px 6px rgba(0,0,0,0.3);\n}\n.lx-highlight:hover .lx-tooltip { visibility: visible; opacity:1; }\n.lx-animated-wrapper { max-width: 100%; font-family: Arial, sans-serif; }\n.lx-controls {\n  background: #fafafa; border: 1px solid #90caf9; border-radius: 8px;\n  padding: 12px; margin-bottom: 16px;\n}\n.lx-button-row {\n  display: flex; justify-content: center; gap: 8px; margin-bottom: 12px;\n}\n.lx-control-btn {\n  background: #4285f4; color: white; border: none; border-radius: 4px;\n  padding: 8px 16px; cursor: pointer; font-size: 13px; font-weight: 500;\n  transition: background-color 0.2s;\n}\n.lx-control-btn:hover { background: #3367d6; }\n.lx-progress-container {\n  margin-bottom: 8px;\n}\n.lx-progress-slider {\n  width: 100%; margin: 0; appearance: none; height: 6px;\n  background: #ddd; border-radius: 3px; outline: none;\n}\n.lx-progress-slider::-webkit-slider-thumb {\n  appearance: none; width: 18px; height: 18px; background: #4285f4;\n  border-radius: 50%; cursor: pointer;\n}\n.lx-progress-slider::-moz-range-thumb {\n  width: 18px; height: 18px; background: #4285f4; border-radius: 50%;\n  cursor: pointer; border: none;\n}\n.lx-status-text {\n  text-align: center; font-size: 12px; color: #666; margin-top: 4px;\n}\n.lx-text-window {\n  font-family: monospace; white-space: pre-wrap; border: 1px solid #90caf9;\n  padding: 12px; max-height: 260px; overflow-y: auto; margin-bottom: 12px;\n  line-height: 1.6;\n}\n.lx-attributes-panel {\n  background: #fafafa; border: 1px solid #90caf9; border-radius: 6px;\n  padding: 8px 10px; margin-top: 8px; font-size: 13px;\n}\n.lx-current-highlight {\n  border-bottom: 4px solid #ff4444;\n  font-weight: bold;\n  animation: lx-pulse 1s ease-in-out;\n}\n@keyframes lx-pulse {\n  0% { text-decoration-color: #ff4444; }\n  50% { text-decoration-color: #ff0000; }\n  100% { text-decoration-color: #ff4444; }\n}\n.lx-legend {\n  font-size: 12px; margin-bottom: 8px;\n  padding-bottom: 8px; border-bottom: 1px solid #e0e0e0;\n}\n.lx-label {\n  display: inline-block;\n  padding: 2px 4px;\n  border-radius: 3px;\n  margin-right: 4px;\n  color: #000;\n}\n.lx-attr-key {\n  font-weight: 600;\n  color: #1565c0;\n  letter-spacing: 0.3px;\n}\n.lx-attr-value {\n  font-weight: 400;\n  opacity: 0.85;\n  letter-spacing: 0.2px;\n}\n\n/* Add optimizations with larger fonts and better readability for GIFs */\n.lx-gif-optimized .lx-text-window { font-size: 16px; line-height: 1.8; }\n.lx-gif-optimized .lx-attributes-panel { font-size: 15px; }\n.lx-gif-optimized .lx-current-highlight { text-decoration-thickness: 4px; }\n</style>\n<div class=\"lx-animated-wrapper lx-gif-optimized\">\n  <div class=\"lx-attributes-panel\">\n    <div class=\"lx-legend\">Highlights Legend: <span class=\"lx-label\" style=\"background-color:#D2E3FC;\">bonus</span> <span class=\"lx-label\" style=\"background-color:#C8E6C9;\">document_meta</span> <span class=\"lx-label\" style=\"background-color:#FEF0C3;\">employee</span> <span class=\"lx-label\" style=\"background-color:#F9DEDC;\">employer</span> <span class=\"lx-label\" style=\"background-color:#FFDDBE;\">pay_period</span> <span class=\"lx-label\" style=\"background-color:#EADDFF;\">salary</span></div>\n    <div id=\"attributesContainer\"></div>\n  </div>\n  <div class=\"lx-text-window\" id=\"textWindow\">\n    <span class=\"lx-highlight lx-current-highlight\" data-idx=\"0\" style=\"background-color:#C8E6C9;\">Detailed</span> Payment Slip 明细的付款滑名称的雇主 <span class=\"lx-highlight\" data-idx=\"1\" style=\"background-color:#F9DEDC;\">ABC PTE 有限公司</span> 用于的时期:<span class=\"lx-highlight\" data-idx=\"2\" style=\"background-color:#FFDDBE;\">2021年9月1日 - 2021年9月30日</span> 2021年9月4日 名称的员工 <span class=\"lx-highlight\" data-idx=\"3\" style=\"background-color:#FEF0C3;\">吨啊 Kow</span> 模式支付 现金/吉赫克+银行-存款 加班详细信息 Description Amount Description Amount <span class=\"lx-highlight\" data-idx=\"4\" style=\"background-color:#EADDFF;\">基础支付 <span class=\"lx-highlight\" data-idx=\"5\" style=\"background-color:#EADDFF;\"><span class=\"lx-highlight\" data-idx=\"6\" style=\"background-color:#D2E3FC;\">2000美元</span></span></span> “Ovarime”付款游行 2021年9月1日 到 2021年9月30日 瓦洛瓦尔西斯 500美元 OverimeHousWokes 5 运输 300美元 “提取转换加载” 奥维琳支付 8 $72.70 GCC 5 200美元 <span class=\"lx-highlight\" data-idx=\"7\" style=\"background-color:#D2E3FC;\">阿内奖金 2000美元</span> ossPay A+B) 2500美元 ea = 不是支付(DE 4.26370 雇主 besucton 1,115美元 oe * 高级拉恩啊啊员工中央provident 基金连续性 $949\n  </div>\n  <div class=\"lx-controls\">\n    <div class=\"lx-button-row\">\n      <button class=\"lx-control-btn\" onclick=\"playPause()\">▶️ Play</button>\n      <button class=\"lx-control-btn\" onclick=\"prevEExtraction()\">⏮ Previous</button>\n      <button class=\"lx-control-btn\" onclick=\"nextExtraction()\">⏭ Next</button>\n    </div>\n    <div class=\"lx-progress-container\">\n      <input type=\"range\" id=\"progressSlider\" class=\"lx-progress-slider\"\n             min=\"0\" max=\"7\" value=\"0\"\n             onchange=\"jumpToExtraction(this.value)\">\n    </div>\n    <div class=\"lx-status-text\">\n      Entity <span id=\"entityInfo\">1/8</span> |\n      Pos <span id=\"posInfo\">[0-8]</span>\n    </div>\n  </div>\n</div>\n\n<script>\n  (function() {\n    const extractions = [{\"index\": 0, \"class\": \"document_meta\", \"text\": \"Detailed\", \"color\": \"#C8E6C9\", \"startPos\": 0, \"endPos\": 8, \"beforeText\": \"\", \"extractionText\": \"Detailed\", \"afterText\": \" Payment Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amo\", \"attributesHtml\": \"<div><strong>class:</strong> document_meta</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">language_code</span>: <span class=\\\"lx-attr-value\\\">en</span>}</div>\"}, {\"index\": 1, \"class\": \"employer\", \"text\": \"ABC PTE \\t\\t\\t\\u6709\\u9650\\u516c\\u53f8\", \"color\": \"#F9DEDC\", \"startPos\": 34, \"endPos\": 46, \"beforeText\": \"Detailed Payment Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b \", \"extractionText\": \"ABC PTE \\u6709\\u9650\\u516c\\u53f8\", \"afterText\": \" \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143 \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\", \"attributesHtml\": \"<div><strong>class:</strong> employer</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The employer is ABC PTE \\t\\t\\t\\u6709\\u9650\\u516c\\u53f8.</span>}</div>\"}, {\"index\": 2, \"class\": \"pay_period\", \"text\": \"2021\\t\\t\\t\\u5e749\\u67081\\u65e5 - 2021\\t\\t\\t\\u5e749\\u670830\\u65e5\", \"color\": \"#FFDDBE\", \"startPos\": 53, \"endPos\": 75, \"beforeText\": \"Detailed Payment Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a\", \"extractionText\": \"2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5\", \"afterText\": \" 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143 \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 O\", \"attributesHtml\": \"<div><strong>class:</strong> pay_period</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The pay period is from September 1, 2021 to September 30, 2021.</span>}</div>\"}, {\"index\": 3, \"class\": \"employee\", \"text\": \"\\t\\t\\t\\u5428\\u554a Kow\", \"color\": \"#FEF0C3\", \"startPos\": 92, \"endPos\": 98, \"beforeText\": \"Detailed Payment Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \", \"extractionText\": \"\\u5428\\u554a Kow\", \"afterText\": \" \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143 \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 OverimeHousWokes 5 \\u8fd0\\u8f93 30\", \"attributesHtml\": \"<div><strong>class:</strong> employee</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The employee&#x27;s name is \\t\\t\\t\\u5428\\u554a Kow.</span>}</div>\"}, {\"index\": 4, \"class\": \"salary\", \"text\": \"\\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143\", \"color\": \"#EADDFF\", \"startPos\": 162, \"endPos\": 173, \"beforeText\": \"ment Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \", \"extractionText\": \"\\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143\", \"afterText\": \" \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 OverimeHousWokes 5 \\u8fd0\\u8f93 300\\u7f8e\\u5143 \\u201c\\u63d0\\u53d6\\u8f6c\\u6362\\u52a0\\u8f7d\\u201d \\u5965\\u7ef4\\u7433\\u652f\\u4ed8 8 $72.70 GCC 5 200\\u7f8e\\u5143 \\u963f\\u5185\\u5956\\u91d1 2000\\u7f8e\\u5143 ossPay A+B) 2500\\u7f8e\\u5143 ea =\", \"attributesHtml\": \"<div><strong>class:</strong> salary</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The base salary is 2000 USD.</span>}</div>\"}, {\"index\": 5, \"class\": \"salary\", \"text\": \"2000\\u7f8e\\u5143\", \"color\": \"#EADDFF\", \"startPos\": 167, \"endPos\": 173, \"beforeText\": \"Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 \", \"extractionText\": \"2000\\u7f8e\\u5143\", \"afterText\": \" \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 OverimeHousWokes 5 \\u8fd0\\u8f93 300\\u7f8e\\u5143 \\u201c\\u63d0\\u53d6\\u8f6c\\u6362\\u52a0\\u8f7d\\u201d \\u5965\\u7ef4\\u7433\\u652f\\u4ed8 8 $72.70 GCC 5 200\\u7f8e\\u5143 \\u963f\\u5185\\u5956\\u91d1 2000\\u7f8e\\u5143 ossPay A+B) 2500\\u7f8e\\u5143 ea =\", \"attributesHtml\": \"<div><strong>class:</strong> salary</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The base salary is 2000 USD.</span>}</div>\"}, {\"index\": 6, \"class\": \"bonus\", \"text\": \"2000\\u7f8e\\u5143\", \"color\": \"#D2E3FC\", \"startPos\": 167, \"endPos\": 173, \"beforeText\": \"Slip \\u660e\\u7ec6\\u7684\\u4ed8\\u6b3e\\u6ed1\\u540d\\u79f0\\u7684\\u96c7\\u4e3b ABC PTE \\u6709\\u9650\\u516c\\u53f8 \\u7528\\u4e8e\\u7684\\u65f6\\u671f\\uff1a2021\\u5e749\\u67081\\u65e5 - 2021\\u5e749\\u670830\\u65e5 2021\\u5e749\\u67084\\u65e5 \\u540d\\u79f0\\u7684\\u5458\\u5de5 \\u5428\\u554a Kow \\u6a21\\u5f0f\\u652f\\u4ed8 \\u73b0\\u91d1/\\u5409\\u8d6b\\u514b+\\u94f6\\u884c-\\u5b58\\u6b3e \\u52a0\\u73ed\\u8be6\\u7ec6\\u4fe1\\u606f Description Amount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 \", \"extractionText\": \"2000\\u7f8e\\u5143\", \"afterText\": \" \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 OverimeHousWokes 5 \\u8fd0\\u8f93 300\\u7f8e\\u5143 \\u201c\\u63d0\\u53d6\\u8f6c\\u6362\\u52a0\\u8f7d\\u201d \\u5965\\u7ef4\\u7433\\u652f\\u4ed8 8 $72.70 GCC 5 200\\u7f8e\\u5143 \\u963f\\u5185\\u5956\\u91d1 2000\\u7f8e\\u5143 ossPay A+B) 2500\\u7f8e\\u5143 ea =\", \"attributesHtml\": \"<div><strong>class:</strong> bonus</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The bonus payment is 2000 USD.</span>}</div>\"}, {\"index\": 7, \"class\": \"bonus\", \"text\": \"\\u963f\\u5185\\u5956\\u91d1 2000\\u7f8e\\u5143\", \"color\": \"#D2E3FC\", \"startPos\": 288, \"endPos\": 299, \"beforeText\": \"ount Description Amount \\u57fa\\u7840\\u652f\\u4ed8 2000\\u7f8e\\u5143 \\u201cOvarime\\u201d\\u4ed8\\u6b3e\\u6e38\\u884c 2021\\u5e749\\u67081\\u65e5 \\u5230 2021\\u5e749\\u670830\\u65e5 \\u74e6\\u6d1b\\u74e6\\u5c14\\u897f\\u65af 500\\u7f8e\\u5143 OverimeHousWokes 5 \\u8fd0\\u8f93 300\\u7f8e\\u5143 \\u201c\\u63d0\\u53d6\\u8f6c\\u6362\\u52a0\\u8f7d\\u201d \\u5965\\u7ef4\\u7433\\u652f\\u4ed8 8 $72.70 GCC 5 200\\u7f8e\\u5143 \", \"extractionText\": \"\\u963f\\u5185\\u5956\\u91d1 2000\\u7f8e\\u5143\", \"afterText\": \" ossPay A+B) 2500\\u7f8e\\u5143 ea = \\u4e0d\\u662f\\u652f\\u4ed8\\uff08DE 4.26370 \\u96c7\\u4e3b besucton 1,115\\u7f8e\\u5143 oe * \\u9ad8\\u7ea7\\u62c9\\u6069\\u554a\\u554a\\u5458\\u5de5\\u4e2d\\u592eprovident \\u57fa\\u91d1\\u8fde\\u7eed\\u6027 $949\", \"attributesHtml\": \"<div><strong>class:</strong> bonus</div><div><strong>attributes:</strong> {<span class=\\\"lx-attr-key\\\">summary</span>: <span class=\\\"lx-attr-value\\\">The bonus is 2000 USD.</span>}</div>\"}];\n    let currentIndex = 0;\n    let isPlaying = false;\n    let animationInterval = null;\n    let animationSpeed = 1.0;\n\n    function updateDisplay() {\n      const extraction = extractions[currentIndex];\n      if (!extraction) return;\n\n      document.getElementById('attributesContainer').innerHTML = extraction.attributesHtml;\n      document.getElementById('entityInfo').textContent = (currentIndex + 1) + '/' + extractions.length;\n      document.getElementById('posInfo').textContent = '[' + extraction.startPos + '-' + extraction.endPos + ']';\n      document.getElementById('progressSlider').value = currentIndex;\n\n      const playBtn = document.querySelector('.lx-control-btn');\n      if (playBtn) playBtn.textContent = isPlaying ? '⏸ Pause' : '▶️ Play';\n\n      const prevHighlight = document.querySelector('.lx-text-windoww .lx-current-highlight');\n      if (prevHighlight) prevHighlight.classList.remove('lx-current-highlight');\n      const currentSpan = document.querySelector('.lx-text-window span[data-idx=\"' + currentIndex + '\"]');\n      if (currentSpan) {\n        currentSpan.classList.add('lx-current-highlight');\n        currentSpan.scrollIntoView({block: 'center', behavior: 'smooth'});\n      }\n    }\n\n    function nextExtraction() {\n      currentIndex = (currentIndex + 1) % extractions.length;\n      updateDisplay();\n    }\n\n    function prevExtraction() {\n      currentIndex = (currentIndex - 1 + extractions.length) % extractions.length;\n      updateDisplay();\n    }\n\n    function jumpToExtraction(index) {\n      currentIndex = parseInt(index);\n      updateDisplay();\n    }\n\n    function playPause() {\n      if (isPlaying) {\n        clearInterval(animationInterval);\n        isPlaying = false;\n      } else {\n        animationInterval = setInterval(nextExtraction, animationSpeed * 1000);\n        isPlaying = true;\n      }\n      updateDisplay();\n    }\n\n    window.playPause = playPause;\n    window.nextExtraction = nextExtraction;\n    window.prevExtraction = prevExtraction;\n    window.jumpToExtraction = jumpToExtraction;\n\n    updateDisplay();\n  })();\n</script>"
}