formtovoice
v1.3.0
Published
AI-powered form filling with voice conversation. Let users fill website forms using natural voice interaction with OpenAI's real-time API.
Maintainers
Readme
FormToVoice
AI-powered form filling with voice conversation. Let users fill website forms using natural voice interaction with OpenAI's real-time API.
Features
- 🎤 Voice Conversation: Natural voice interaction for form filling
- 🤖 AI-Powered: Uses OpenAI's real-time API for intelligent form processing
- 🔄 Real-time: WebRTC-based real-time audio streaming
- 📝 Form Detection: Automatically detects and analyzes form fields
- 🎯 Smart Validation: Intelligent field validation and data extraction
- 📱 Responsive: Works on desktop and mobile devices
- 🎨 Customizable: Modern, clean UI that matches your design
- ⚡ Zero Dependencies: No external dependencies required
Installation
npm install formtovoiceQuick Start
1. Include the Library
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>2. Initialize
FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});3. That's it!
The library will automatically detect forms on your page and add voice buttons. Users can click the voice button to start a conversation with the AI assistant.
Platform Quick Start
React (5 minutes)
npm install formtovoiceimport { useEffect } from 'react';
import 'formtovoice/dist/formtovoice.min.js';
const MyForm = () => {
useEffect(() => {
window.FormToVoice?.init({
openaiApiKey: process.env.REACT_APP_OPENAI_API_KEY
});
return () => window.FormToVoice?.destroy();
}, []);
return <form>{/* your form fields */}</form>;
};Angular (5 minutes)
npm install formtovoice// app.component.ts
ngOnInit() {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => window.FormToVoice.init({ openaiApiKey: 'your-key' });
document.head.appendChild(script);
}Vue.js (5 minutes)
npm install formtovoice<template><form><!-- your form fields --></form></template>
<script>
export default {
mounted() {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => window.FormToVoice.init({ openaiApiKey: 'your-key' });
document.head.appendChild(script);
}
}
</script>WordPress (2 minutes)
// functions.php
wp_enqueue_script('formtovoice', 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js');
wp_add_inline_script('formtovoice', 'FormToVoice.init({openaiApiKey: "your-key"});');Shopify (2 minutes)
<!-- theme.liquid -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>FormToVoice.init({openaiApiKey: '{{ settings.openai_api_key }}'});</script>Platform-Specific Examples
React
Installation
npm install formtovoiceBasic Usage
import React, { useEffect } from 'react';
import 'formtovoice/dist/formtovoice.min.js';
const ContactForm = () => {
useEffect(() => {
// Initialize FormToVoice when component mounts
if (window.FormToVoice) {
window.FormToVoice.init({
openaiApiKey: process.env.REACT_APP_OPENAI_API_KEY,
theme: 'modern',
language: 'en'
});
}
// Cleanup when component unmounts
return () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
};
}, []);
return (
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
);
};
export default ContactForm;Advanced React Hook
import { useEffect, useRef } from 'react';
const useFormToVoice = (openaiApiKey, options = {}) => {
const formRef = useRef(null);
useEffect(() => {
if (window.FormToVoice && formRef.current) {
window.FormToVoice.init({
openaiApiKey,
...options
});
}
return () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
};
}, [openaiApiKey, options]);
return formRef;
};
// Usage
const MyForm = () => {
const formRef = useFormToVoice(process.env.REACT_APP_OPENAI_API_KEY, {
theme: 'modern',
language: 'en'
});
return (
<form ref={formRef}>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<button type="submit">Submit</button>
</form>
);
};Angular
Installation
npm install formtovoiceBasic Usage
// app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
declare global {
interface Window {
FormToVoice: any;
}
}
@Component({
selector: 'app-root',
template: `
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
`
})
export class AppComponent implements OnInit, OnDestroy {
ngOnInit() {
// Load FormToVoice script dynamically
this.loadFormToVoiceScript();
}
ngOnDestroy() {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
}
private loadFormToVoiceScript() {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
}
}Angular Service
// formtovoice.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class FormToVoiceService {
private isInitialized = false;
init(openaiApiKey: string, options: any = {}) {
if (window.FormToVoice && !this.isInitialized) {
window.FormToVoice.init({
openaiApiKey,
...options
});
this.isInitialized = true;
}
}
destroy() {
if (window.FormToVoice && this.isInitialized) {
window.FormToVoice.destroy();
this.isInitialized = false;
}
}
}Vue.js
Installation
npm install formtovoiceBasic Usage
<template>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
</template>
<script>
export default {
name: 'ContactForm',
mounted() {
// Load FormToVoice script
this.loadFormToVoiceScript();
},
beforeUnmount() {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
},
methods: {
loadFormToVoiceScript() {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: process.env.VUE_APP_OPENAI_API_KEY,
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
}
}
}
</script>Vue Plugin
// formtovoice-plugin.js
import { createApp } from 'vue';
const FormToVoicePlugin = {
install(app, options) {
app.config.globalProperties.$formtovoice = {
init: (openaiApiKey, config = {}) => {
if (window.FormToVoice) {
window.FormToVoice.init({
openaiApiKey,
...config
});
}
},
destroy: () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
}
};
}
};
export default FormToVoicePlugin;
// Usage in main.js
import { createApp } from 'vue';
import App from './App.vue';
import FormToVoicePlugin from './formtovoice-plugin.js';
const app = createApp(App);
app.use(FormToVoicePlugin);
app.mount('#app');Next.js
Installation
npm install formtovoiceBasic Usage
// pages/contact.js
import { useEffect } from 'react';
import Head from 'next/head';
export default function Contact() {
useEffect(() => {
// Load FormToVoice script
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY,
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
return () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
};
}, []);
return (
<>
<Head>
<title>Contact Form</title>
</Head>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
</>
);
}Next.js with Custom Hook
// hooks/useFormToVoice.js
import { useEffect } from 'react';
export const useFormToVoice = (openaiApiKey, options = {}) => {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey,
...options
});
};
document.head.appendChild(script);
return () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
};
}, [openaiApiKey, options]);
};Svelte
Installation
npm install formtovoiceBasic Usage
<!-- ContactForm.svelte -->
<script>
import { onMount, onDestroy } from 'svelte';
onMount(() => {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
});
onDestroy(() => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
});
</script>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>Nuxt.js
Installation
npm install formtovoiceBasic Usage
<!-- pages/contact.vue -->
<template>
<div>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
</div>
</template>
<script>
export default {
mounted() {
this.loadFormToVoiceScript();
},
beforeDestroy() {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
},
methods: {
loadFormToVoiceScript() {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: process.env.OPENAI_API_KEY,
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
}
}
}
</script>Gatsby
Installation
npm install formtovoiceBasic Usage
// src/pages/contact.js
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
const ContactPage = () => {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: process.env.GATSBY_OPENAI_API_KEY,
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
return () => {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
};
}, []);
return (
<>
<Helmet>
<title>Contact Form</title>
</Helmet>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
</>
);
};
export default ContactPage;Web Components
Basic Usage
// custom-form-element.js
class VoiceForm extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
`;
// Load FormToVoice script
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: this.getAttribute('api-key'),
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
}
disconnectedCallback() {
if (window.FormToVoice) {
window.FormToVoice.destroy();
}
}
}
customElements.define('voice-form', VoiceForm);HTML Usage
<voice-form api-key="your-openai-api-key"></voice-form>TypeScript
Type Definitions
// types/formtovoice.d.ts
declare global {
interface Window {
FormToVoice: {
init: (config: FormToVoiceConfig) => void;
destroy: () => void;
on: (event: string, handler: Function) => void;
off: (event: string, handler: Function) => void;
};
}
}
interface FormToVoiceConfig {
openaiApiKey: string;
theme?: 'modern' | 'minimal' | 'dark';
language?: string;
autoStart?: boolean;
debug?: boolean;
voice?: {
model?: string;
voice?: string;
};
}
export {};Usage
// app.ts
import './types/formtovoice';
window.FormToVoice.init({
openaiApiKey: process.env.OPENAI_API_KEY!,
theme: 'modern',
language: 'en'
});Node.js (Server-Side Rendering)
Installation
npm install formtovoiceBasic Usage
// server.js
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static('public'));
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>FormToVoice Example</title>
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
</head>
<body>
<form>
<input type="text" name="name" placeholder="Your Name" required />
<input type="email" name="email" placeholder="Your Email" required />
<textarea name="message" placeholder="Your Message" required></textarea>
<button type="submit">Submit</button>
</form>
<script>
FormToVoice.init({
openaiApiKey: '${process.env.OPENAI_API_KEY}',
theme: 'modern',
language: 'en'
});
</script>
</body>
</html>
`);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});Additional Platforms
WordPress
// functions.php
function enqueue_formtovoice() {
wp_enqueue_script('formtovoice', 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js', array(), '1.1.0', true);
wp_add_inline_script('formtovoice', '
document.addEventListener("DOMContentLoaded", function() {
FormToVoice.init({
openaiApiKey: "' . get_option('openai_api_key') . '",
theme: "modern",
language: "en"
});
});
');
}
add_action('wp_enqueue_scripts', 'enqueue_formtovoice');Drupal
// mymodule.module
function mymodule_page_attachments_alter(array &$attachments) {
$attachments['#attached']['library'][] = 'mymodule/formtovoice';
}
// mymodule.libraries.yml
formtovoice:
js:
https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js: { type: external, minified: true }
dependencies:
- core/drupalJoomla
<!-- templateDetails.xml -->
<fieldset name="formtovoice">
<field name="openai_api_key" type="text" label="OpenAI API Key" />
</fieldset>// template.php
$document = JFactory::getDocument();
$document->addScript('https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js');
$document->addScriptDeclaration('
FormToVoice.init({
openaiApiKey: "' . $this->params->get('openai_api_key') . '",
theme: "modern",
language: "en"
});
');Shopify
<!-- theme.liquid -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>
FormToVoice.init({
openaiApiKey: '{{ settings.openai_api_key }}',
theme: 'modern',
language: 'en'
});
</script>Webflow
<!-- Custom Code in Webflow -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
});
</script>Squarespace
<!-- Code Injection in Squarespace -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>
FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
</script>Wix
// Wix Code
import wixWindow from 'wix-window';
$w.onReady(function () {
// Load FormToVoice script
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: wixWindow.getSecret('OPENAI_API_KEY'),
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);
});Bubble
// Bubble.io Custom Code
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);Airtable
<!-- Airtable Custom Page -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>
FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
</script>Notion
<!-- Notion Custom Page -->
<script src="https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js"></script>
<script>
FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
</script>Figma
// Figma Plugin
const script = document.createElement('script');
script.src = 'https://unpkg.com/formtovoice@latest/dist/formtovoice.min.js';
script.onload = () => {
window.FormToVoice.init({
openaiApiKey: 'your-openai-api-key',
theme: 'modern',
language: 'en'
});
};
document.head.appendChild(script);Configuration
FormToVoice.init({
// Required: Your OpenAI API key
openaiApiKey: 'sk-...',
// Optional: UI theme
theme: 'modern', // 'modern' | 'minimal' | 'dark'
// Optional: Language
language: 'en', // 'en' | 'es' | 'fr' | 'de' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko'
// Optional: Auto-start conversation
autoStart: false,
// Optional: Debug mode
debug: false,
// Optional: Voice configuration
voice: {
model: 'gpt-4o-realtime-preview-2024-12-17',
voice: 'sage' // 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer'
}
});Supported Form Elements
- Text Inputs:
text,email,tel,password,url,search - Numeric Inputs:
number,range - Date/Time Inputs:
date,time,datetime-local,month,week - Selection Inputs:
select,radio,checkbox - Text Areas:
textarea - All HTML5 input types
API Reference
Methods
FormToVoice.init(options)
Initialize the FormToVoice library with configuration options.
FormToVoice.destroy()
Destroy the FormToVoice instance and clean up all event listeners.
FormToVoice.on(event, handler)
Add an event listener.
FormToVoice.off(event, handler)
Remove an event listener.
Events
conversationStarted- Fired when a voice conversation beginsconversationEnded- Fired when a voice conversation endsformFilled- Fired when a form is successfully fillederror- Fired when an error occurs
Example
FormToVoice.on('conversationStarted', (data) => {
console.log('Conversation started for form:', data.formElement);
});
FormToVoice.on('formFilled', (data) => {
console.log('Form filled with data:', data.formData);
});Platform Compatibility
✅ Fully Supported
- React (16.8+)
- Angular (8+)
- Vue.js (2.6+ / 3+)
- Next.js (10+)
- Svelte (3+)
- Nuxt.js (2+)
- Gatsby (3+)
- Web Components (All modern browsers)
- TypeScript (3.7+)
✅ CMS Platforms
- WordPress (5.0+)
- Drupal (8+)
- Joomla (3.9+)
- Shopify (All themes)
- Webflow (All plans)
- Squarespace (All plans)
✅ No-Code Platforms
- Wix (Velo/Code)
- Bubble (Custom Code)
- Airtable (Custom Pages)
- Notion (Custom Pages)
- Figma (Plugins)
✅ Server-Side
- Node.js (14+)
- Express.js (4+)
- Next.js (SSR/SSG)
- Nuxt.js (SSR/SSG)
Browser Support
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
Requirements
- OpenAI API key
- HTTPS connection (required for microphone access)
- Modern browser with WebRTC support
License
ISC
Support
For support, please open an issue on GitHub.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
