Files
gh-jhs-chatfield-claude-fil…/skills/filling-pdf-forms/references/Data-Model-API.md
2025-11-30 08:25:58 +08:00

5.7 KiB

Conversational Form API Reference

Library: chatfield Python package

API reference for building conversational form interviews. Powered by the Chatfield library.

Contents

  • Quick Start
  • Builder API
    • Interview Configuration
    • Roles
    • Fields
    • Validation
    • Special Field Types
    • Transformations
    • Cardinality
  • Field Access
  • Optional Fields

Quick Start

from chatfield import chatfield, Interviewer

# Define
interview = (chatfield()
    .field("name")
        .desc("What is your full name?")
        .must("include first and last")
    .field("age")
        .desc("Your age?")
        .as_int()
        .must("be between 18 and 120")
    .build())

# Run
interviewer = Interviewer(interview)
user_input = None
while not interview._done:
    message = interviewer.go(user_input)
    print(f"Assistant: {message}")
    if not interview._done:
        user_input = input("You: ").strip()

# Access
print(interview.name, interview.age.as_int)

Builder API

Interview Configuration

interview = (chatfield()
    .type("Job Application")            # Interview type
    .desc("Collect applicant info")     # Description
    .build())

Roles

.alice()                                # Configure AI assistant
    .type("Tax Assistant")
    .trait("Professional and accurate")
    .trait("Never provides tax advice")

.bob()                                  # Configure user
    .type("Taxpayer")
    .trait("Speaks colloquially")

Fields

.field("email")                         # Define field (becomes interview.email)
    .desc("What is your email?")        # User-facing question

All fields mandatory to populate (must be non-None for ._done). Content can be empty string "". Exception: .as_one(), .as_multi(), and fields with strict validation require non-empty values.

Validation

.field("email")
    .must("be valid email format")      # Requirement (AND logic)
    .must("not be disposable")
    .reject("profanity")                # Block pattern
    .hint("Background: Company email preferred")    # Advisory (not enforced)

Hints

Hints provide context and guidance to Alice. All hints must start with "Background:" or "Tooltip:"

# Background hints: Internal notes for Alice only (not mentioned to Bob)
.hint("Background: Convert Gregorian to Buddhist calendar (+543 years)")
.hint("Background: Optional per form instructions")

# Tooltip hints: May be shared with Bob if helpful
.hint("Tooltip: Your employer should provide this number")
.hint("Tooltip: Ask your supervisor if unsure")

Background hints are for Alice's internal use - she handles formatting/conversions transparently without mentioning them to Bob. Tooltip hints may be shared with Bob to help clarify what information is needed.

Special Field Types

.field("sentiment_score")
    .confidential()                     # Track silently, never ask Bob

.field("summary")
    .conclude()                         # Compute after regular fields (auto-confidential)

Transformations

LLM computes during collection. Access via interview.field.as_*

.field("age").as_int()                  # → interview.age.as_int = 25
.field("price").as_float()              # → interview.price.as_float = 99.99
.field("citizen").as_bool()             # → interview.citizen.as_bool = True
.field("hobbies").as_list()             # → interview.hobbies.as_list = ["reading", "coding"]
.field("config").as_json()              # → interview.config.as_json = {"theme": "dark"}
.field("progress").as_percent()         # → interview.progress.as_percent = 0.75
.field("greeting").as_lang("fr")        # → interview.greeting.as_lang_fr = "Bonjour"

# Optional descriptions guide edge cases
.field("has_partners")
    .as_bool("true if you have partners; false if not or N/A")

.field("quantity")
    .as_int("parse as integer, ignore units")

# Named string casts for formatting
.field("ssn")
    .must("be exactly 9 digits")
    .as_str("formatted", "Format as ###-##-####")
# Access: interview.ssn.as_str_formatted → "123-45-6789"

Validation vs. Casts:

  • Validation (.must()): Check content ("9 digits", "valid email")
  • Casts (.as_*()): Provide format (hyphens, capitalization)

Choice Cardinality

Select from predefined options:

.field("tax_class")
    .as_one("Individual", "C Corp", "S Corp")       # Exactly one choice required

.field("dietary")
    .as_nullable_one("Vegetarian", "Vegan")         # Zero or one

.field("languages")
    .as_multi("Python", "JavaScript", "Go")         # One or more choices required

.field("interests")
    .as_nullable_multi("ML", "Web Dev", "DevOps")   # Zero or more

Build

.build()                                # Return Interview instance

Field Access

Dot notation (regular fields):

interview.name
interview.age.as_int

Bracket notation (special characters):

interview["topmostSubform[0].Page1[0].f1_01[0]"]    # PDF form fields
interview["user.name"]                               # Dots
interview["full name"]                               # Spaces
interview["class"]                                   # Reserved words

Optional Fields

Fields known to be optional (from PDF tooltip, nearby context, or instructions):

.alice()
    .trait("Records optional fields as empty string when user says blank/none/skip")

.field("middle_name")
    .desc("Middle name")
    .hint("Background: Optional per form instructions")

.field("extension")
    .desc("Phone extension")
    .hint("Background: Leave blank if none")

For optional choices, use .as_nullable_one() or .as_nullable_multi() (see examples above).