Skip to content
Learn Agentic AI9 min read0 views

AI-Powered Form Filling: Auto-Complete and Smart Defaults in SaaS Applications

Build intelligent form auto-completion that predicts field values from context, validates entries in real time, and lets users override every suggestion with a single keystroke.

The Cost of Empty Forms

Every blank form field is friction. In a CRM, a sales rep creating a new deal fills in the same industry, deal stage, and estimated close date patterns hundreds of times. In an HR system, onboarding forms repeat company name, department, and location across dozens of fields. AI-powered form filling reduces this friction by predicting field values from context — the user's history, the current record, and patterns from similar entries.

Context Extraction for Predictions

The prediction engine examines three context sources: the user's recent activity, the partially filled form, and historical patterns from similar records.

from dataclasses import dataclass
from datetime import datetime

@dataclass
class FormContext:
    user_id: str
    tenant_id: str
    form_type: str  # e.g., "deal", "contact", "ticket"
    partial_fields: dict  # Fields the user has already filled
    current_page: str
    related_entity_id: str | None = None

class FormPredictionEngine:
    def __init__(self, db, llm_client):
        self.db = db
        self.llm_client = llm_client

    async def get_predictions(self, context: FormContext) -> dict:
        # Source 1: User's recent entries for this form type
        recent_entries = await self.get_recent_entries(
            context.user_id, context.tenant_id, context.form_type, limit=20
        )

        # Source 2: Related entity data
        related_data = {}
        if context.related_entity_id:
            related_data = await self.get_related_entity(
                context.tenant_id, context.related_entity_id
            )

        # Source 3: Tenant-wide patterns
        common_values = await self.get_common_values(
            context.tenant_id, context.form_type
        )

        predictions = {}

        # Rule-based predictions (fast, no LLM needed)
        predictions.update(
            self.rule_based_predictions(context, recent_entries, related_data)
        )

        # LLM-based predictions for complex fields
        llm_predictions = await self.llm_predictions(
            context, recent_entries, common_values
        )
        # Only add LLM predictions for fields not already predicted
        for field, value in llm_predictions.items():
            if field not in predictions:
                predictions[field] = value

        return predictions

    def rule_based_predictions(self, context: FormContext,
                                recent: list[dict],
                                related: dict) -> dict:
        predictions = {}

        # If creating a deal from a contact page, prefill contact info
        if context.form_type == "deal" and related.get("type") == "contact":
            predictions["contact_name"] = related.get("name", "")
            predictions["company"] = related.get("company", "")

        # Most frequent values from recent entries
        if recent:
            from collections import Counter
            for field in ["industry", "source", "priority"]:
                values = [e.get(field) for e in recent if e.get(field)]
                if values:
                    most_common = Counter(values).most_common(1)[0][0]
                    predictions[field] = most_common

        return predictions

    async def get_recent_entries(self, user_id: str, tenant_id: str,
                                  form_type: str, limit: int) -> list[dict]:
        rows = await self.db.fetch("""
            SELECT form_data FROM form_submissions
            WHERE user_id = $1 AND tenant_id = $2 AND form_type = $3
            ORDER BY created_at DESC LIMIT $4;
        """, user_id, tenant_id, form_type, limit)
        return [row["form_data"] for row in rows]

Prediction API with Confidence Scores

Return predictions with confidence levels so the frontend can style high-confidence suggestions differently from uncertain ones.

from fastapi import FastAPI, Depends
from pydantic import BaseModel

app = FastAPI()

class FieldPrediction(BaseModel):
    field_name: str
    predicted_value: str | int | float | bool
    confidence: float  # 0.0 to 1.0
    source: str        # "history", "related_entity", "pattern", "llm"

class PredictionResponse(BaseModel):
    predictions: list[FieldPrediction]

@app.post("/api/forms/predict", response_model=PredictionResponse)
async def predict_form_fields(
    context: FormContext,
    tenant_id: str = Depends(get_current_tenant),
    engine: FormPredictionEngine = Depends(get_prediction_engine),
):
    context.tenant_id = tenant_id
    raw_predictions = await engine.get_predictions(context)

    predictions = []
    for field, value in raw_predictions.items():
        confidence = calculate_confidence(field, value, context)
        predictions.append(FieldPrediction(
            field_name=field,
            predicted_value=value,
            confidence=confidence,
            source=determine_source(field, value),
        ))

    # Sort by confidence descending
    predictions.sort(key=lambda p: p.confidence, reverse=True)
    return PredictionResponse(predictions=predictions)


def calculate_confidence(field: str, value, context: FormContext) -> float:
    # Fields from related entities get high confidence
    if context.related_entity_id and field in ["contact_name", "company"]:
        return 0.95
    # Fields from frequent user patterns
    if field in ["industry", "source", "priority"]:
        return 0.75
    # LLM predictions get moderate confidence
    return 0.5

Frontend Integration with User Override

The frontend shows predictions as ghost text that users can accept with Tab or override by typing.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

import { useState, useEffect, useCallback } from "react";

interface Prediction {
  field_name: string;
  predicted_value: string;
  confidence: number;
}

function useFormPredictions(formType: string, partialFields: Record<string, string>) {
  const [predictions, setPredictions] = useState<Record<string, Prediction>>({});

  const fetchPredictions = useCallback(async () => {
    const response = await fetch("/api/forms/predict", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        form_type: formType,
        partial_fields: partialFields,
        current_page: window.location.pathname,
      }),
    });
    const data = await response.json();
    const mapped: Record<string, Prediction> = {};
    for (const p of data.predictions) {
      mapped[p.field_name] = p;
    }
    setPredictions(mapped);
  }, [formType, JSON.stringify(partialFields)]);

  useEffect(() => {
    const timer = setTimeout(fetchPredictions, 500); // Debounce
    return () => clearTimeout(timer);
  }, [fetchPredictions]);

  return predictions;
}

// Smart input component with ghost text
function SmartInput({ name, value, onChange, prediction }: {
  name: string;
  value: string;
  onChange: (value: string) => void;
  prediction?: Prediction;
}) {
  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Tab" && prediction && !value) {
      e.preventDefault();
      onChange(prediction.predicted_value);
    }
  };

  return (
    <div className="relative">
      {prediction && !value && (
        <span className="absolute left-3 top-2 text-gray-300 pointer-events-none">
          {prediction.predicted_value}
          <span className="ml-2 text-xs">Tab to accept</span>
        </span>
      )}
      <input name={name} value={value} onChange={(e) => onChange(e.target.value)}
        onKeyDown={handleKeyDown}
        className="w-full border rounded px-3 py-2" />
    </div>
  );
}

Validation with AI Assistance

Beyond prediction, the AI validates entries and flags potential errors.

async def validate_with_ai(form_data: dict, form_type: str,
                            llm_client) -> list[dict]:
    prompt = f"""Validate this {form_type} form submission for common errors:
{form_data}

Check for:
- Email format issues
- Phone number format issues
- Unreasonable numeric values (negative prices, dates in the past for deadlines)
- Mismatched fields (city and zip code mismatch)

Return JSON array of issues: [{{"field": "...", "issue": "...", "severity": "warning|error"}}]
Return empty array if no issues found."""

    response = await llm_client.chat(
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"},
    )
    return response.get("issues", [])

FAQ

How do I handle predictions for sensitive fields like salary or SSN?

Never predict sensitive fields. Maintain an explicit blocklist of fields that should never receive AI predictions: social security numbers, passwords, bank account numbers, salary figures, and health information. For these fields, disable the prediction feature entirely and rely on traditional input validation.

What if the AI prediction is wrong and the user does not notice?

Display predictions visually distinct from user-entered data (e.g., lighter text color, a small AI icon). Require explicit acceptance (Tab key or click) before a prediction becomes a committed value. In the form submission handler, log which fields were AI-predicted vs manually entered so you can audit prediction accuracy over time.

How do I improve prediction accuracy over time?

Track acceptance rates per field and per form type. Fields with acceptance rates below 30% should have their prediction strategy revised or disabled. Feed accepted predictions back as training signal by including them in the "recent entries" used by the rule-based predictor. Monthly, review the lowest-performing predictions and adjust the rules or prompts.


#AIForms #AutoComplete #SmartDefaults #SaaS #Python #TypeScript #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.