- rpa-dashboard-ai/SKILL.md: trigger description and the shared question flow; points at the no-AI frontend.md, themes and palette instead of copying them. - templates/contract.md: runs, review rows, endpoints and the server approve gate. - Superbill extracts: patient names and the client name removed, every file carries an EXAMPLE ONLY banner. tests/test_reference_scan.py checks both skills for patient data, internal IPs, credentials and keys. - tests/fixtures/d-ai-extraction and its eval entry, which runs page_check_ai on the built folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
35 lines
1.1 KiB
Python
35 lines
1.1 KiB
Python
"""The LLM extraction call: one scanned invoice in, its fields out, each with word scores."""
|
|
import json
|
|
|
|
from google import genai
|
|
from google.genai import types
|
|
|
|
MODEL = "gemini-2.5-flash"
|
|
FIELDS = { # field name -> mandatory
|
|
"Invoice number": True,
|
|
"Invoice date": True,
|
|
"Vendor": True,
|
|
"PO number": False,
|
|
"Due date": True,
|
|
"Total": True,
|
|
}
|
|
PROMPT = (
|
|
"Read this invoice. Return JSON: a list of {field, value, word_scores}, one per field in "
|
|
+ ", ".join(FIELDS)
|
|
+ ". word_scores is your 0-1 legibility score for each word of the value. Use an empty "
|
|
"value and no scores when a field isn't on the page."
|
|
)
|
|
|
|
|
|
def extract_invoice(document: bytes, mime_type: str) -> list[dict]:
|
|
client = genai.Client() # credentials come from the environment
|
|
response = client.models.generate_content(
|
|
model=MODEL,
|
|
contents=[types.Part.from_bytes(data=document, mime_type=mime_type), PROMPT],
|
|
config=types.GenerateContentConfig(response_mime_type="application/json"),
|
|
)
|
|
rows = json.loads(response.text)
|
|
for row in rows:
|
|
row["mandatory"] = FIELDS.get(row["field"], False)
|
|
return rows
|