ai-native-form
Version:
AI-powered React form assistant with GPT-4, speech input, and schema auto-generation.
84 lines (83 loc) • 3.32 kB
JavaScript
import { useFormContext, } from "react-hook-form";
import { useRef } from "react";
export function useAIForm(form, apiKey) {
const context = useFormContext();
const resolvedForm = form ?? context;
if (!resolvedForm) {
throw new Error("❌ useAIForm: No form context or object provided.");
}
const { setValue, register: baseRegister } = resolvedForm;
const schemaRef = useRef({
type: "object",
properties: {},
required: new Set(),
transformers: {},
});
const register = (name, options) => {
const fieldType = options?.type || "string";
schemaRef.current.properties[name] = { type: fieldType };
if (options?.required)
schemaRef.current.required.add(name);
return baseRegister(name, options);
};
const registerController = (name, meta) => {
schemaRef.current.properties[name] = {
type: meta.type || "string",
};
if (meta.enum) {
schemaRef.current.properties[name].enum = meta.enum;
}
if (meta.required) {
schemaRef.current.required.add(name);
}
if (meta.transform) {
schemaRef.current.transformers[name] = meta.transform;
}
};
const getSchema = () => ({
type: "object",
properties: schemaRef.current.properties,
required: Array.from(schemaRef.current.required),
});
const fillFromPrompt = async (prompt) => {
if (!apiKey)
throw new Error("❌ No OpenAI API key provided");
const schema = getSchema();
const res = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: "gpt-4-1106-preview",
messages: [
{
role: "system",
content: "You are a helpful assistant that fills out form fields from user prompts.",
},
{ role: "user", content: prompt },
],
tools: [
{
type: "function",
function: {
name: "fillForm",
description: "Fills out a form based on the user's natural language prompt. Use strictly the information provided by the user; if a field's information is not within the user's prompt, do not fill it. ",
parameters: schema,
},
},
],
tool_choice: { type: "function", function: { name: "fillForm" } },
}),
});
const result = await res.json();
const args = JSON.parse(result.choices[0].message.tool_calls[0].function.arguments);
Object.entries(args).forEach(([key, value]) => {
const transformer = schemaRef.current.transformers[key];
const finalValue = transformer ? transformer(value) : value;
setValue(key, finalValue);
});
};
return { register, registerController, fillFromPrompt, getSchema };
}