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

217 lines
5.7 KiB
Markdown

# 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
```python
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
```python
interview = (chatfield()
.type("Job Application") # Interview type
.desc("Collect applicant info") # Description
.build())
```
### Roles
```python
.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
```python
.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
```python
.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:"**
```python
# 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
```python
.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_*`
```python
.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:
```python
.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
```python
.build() # Return Interview instance
```
---
## Field Access
**Dot notation** (regular fields):
```python
interview.name
interview.age.as_int
```
**Bracket notation** (special characters):
```python
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):
```python
.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).