reneco-advanced-input-module
v0.0.21
Published
Component to input data into forms by voice
Readme
Stencil Component Starter
This is a starter project for building a standalone Web Components using Stencil.
Stencil is a compiler for building fast web apps using Web Components.
Stencil combines the best concepts of the most popular frontend frameworks into a compile-time rather than runtime tool. Stencil takes TypeScript, JSX, a tiny virtual DOM layer, efficient one-way data binding, an asynchronous rendering pipeline (similar to React Fiber), and lazy-loading out of the box, and generates 100% standards-based Web Components that run in any browser supporting the Custom Elements specification.
Stencil components are just Web Components, so they work in any major framework or with no framework at all.
Getting Started
To start building a new web component using Stencil, clone this repo to a new directory:
git clone https://github.com/stenciljs/component-starter.git my-component
cd my-component
git remote rm originand run:
npm install
npm startConfiguration Setup
Option 1: Using API Proxy (Recommended)
By default, the component uses a proxy API to handle OpenAI calls server-side. This is the recommended approach for production as it keeps your API keys secure.
- Start the proxy API server (see
api-proxy/README.md) - Use the component without providing an
api-key:<voice-input-module form-json='{...}' context="ng" api-proxy-url="http://localhost:8492" > </voice-input-module>
Option 2: Direct API Calls (Client-side)
For development or specific use cases, you can make direct calls to OpenAI from the browser:
Copy the template configuration file:
cp config.template.js config.jsEdit
config.jsand add your OpenAI API key:export const config = { OPENAI_API_KEY: 'your-actual-api-key-here' };Pass the API key to the component:
<voice-input-module form-json='{...}' context="ng" api-key="sk-..." > </voice-input-module>The
config.jsfile is gitignored and will not be committed to the repository
Note: When api-key is provided, the component will use direct API calls. When api-key is not provided, it will use the proxy API at api-proxy-url (default: http://localhost:8492).
To build the component for production, run:
npm run buildTo run the unit tests for the components, run:
npm testNeed help? Check out our docs here.
Naming Components
When creating new component tags, we recommend not using stencil in the component name (ex: <stencil-datepicker>). This is because the generated component has little to nothing to do with Stencil; it's just a web component!
Instead, use a prefix that fits your company or any name for a group of related components. For example, all of the Ionic-generated web components use the prefix ion.
Using this component
There are two strategies we recommend for using web components built with Stencil.
The first step for all two of these strategies is to publish to NPM.
You can read more about these different approaches in the Stencil docs.
Lazy Loading
If your Stencil project is built with the dist output target, you can import a small bootstrap script that registers all components and allows you to load individual component scripts lazily.
For example, given your Stencil project namespace is called my-design-system, to use my-component on any website, inject this into your HTML:
<script type="module" src="https://unpkg.com/my-design-system"></script>
<!--
To avoid unpkg.com redirects to the actual file, you can also directly import:
https://unpkg.com/[email protected]/dist/foobar-design-system/foobar-design-system.esm.js
-->
<my-component first="Stencil" middle="'Don't call me a framework'" last="JS"></my-component>This will only load the necessary scripts needed to render <my-component />. Once more components of this package are used, they will automatically be loaded lazily.
You can also import the script as part of your node_modules in your applications entry file:
import 'foobar-design-system/dist/foobar-design-system/foobar-design-system.esm.js';Check out this Live Demo.
Standalone
If you are using a Stencil component library with dist-custom-elements, we recommend importing Stencil components individually in those files where they are needed.
To export Stencil components as standalone components make sure you have the dist-custom-elements output target defined in your stencil.config.ts.
For example, given you'd like to use <my-component /> as part of a React component, you can import the component directly via:
import 'foobar-design-system/my-component';
function App() {
return (
<>
<div>
<my-component
first="Stencil"
middle="'Don't call me a framework'"
last="JS"
></my-component>
</div>
</>
);
}
export default App;Theme System
Overview
The voice-input-module component supports a complete theme system allowing visual customization via the theme prop (JSON string).
Theme Structure
{
texts: {
idle: string, // Text displayed at rest
recording: string, // Text displayed during voice recording
processing: string // Text displayed during processing (transcription/LLM)
},
container: {
width: string, // Container width (e.g., "auto", "500px", "100%")
height: string, // Container height (e.g., "auto", "200px")
backgroundColor: string, // Background color (e.g., "#ffffff", "rgb(255,255,255)")
borderColor: string, // Border color
borderRadius: string, // Corner radius (e.g., "8px", "0px", "20px")
padding: string, // Internal spacing (e.g., "20px", "12px", "24px")
gap: string // Spacing between elements (buttons and status) (e.g., "8px", "4px", "12px")
},
buttons: {
voice: {
backgroundColor: string, // Voice button background color
textColor: string, // Text/icon color (currently unused for SVG icon)
hoverColor: string, // Hover color
size: string // Button size (e.g., "50px", "40px", "65px")
},
audio: {
backgroundColor: string, // Audio upload button background color
textColor: string, // Text/icon color
hoverColor: string, // Hover color
size: string // Button size
},
ocr: {
backgroundColor: string, // OCR button background color
textColor: string, // Text/icon color
hoverColor: string, // Hover color
size: string // Button size
}
},
statusText: {
color: string, // Status text color
fontSize: string // Font size (e.g., "14px", "12px", "16px")
}
}Default Values
{
"texts": {
"idle": "Select an input method",
"recording": "Recording... Click to stop",
"processing": "Processing..."
},
"container": {
"width": "auto",
"height": "auto",
"backgroundColor": "#ffffff",
"borderColor": "#e2e8f0",
"borderRadius": "8px",
"padding": "20px",
"gap": "8px"
},
"buttons": {
"voice": {
"backgroundColor": "#ee4444",
"textColor": "#ffffff",
"hoverColor": "#dd3333",
"size": "50px"
},
"audio": {
"backgroundColor": "#3b82f6",
"textColor": "#ffffff",
"hoverColor": "#2563eb",
"size": "50px"
},
"ocr": {
"backgroundColor": "#10b981",
"textColor": "#ffffff",
"hoverColor": "#059669",
"size": "50px"
}
},
"statusText": {
"color": "#1e293b",
"fontSize": "14px"
}
}Visual Impact
texts
- idle: Message displayed when no action is in progress
- recording: Message displayed during live voice recording
- processing: Message displayed during audio transcription and form filling by LLM
container
- width: Controls main container width. Use "auto" to adapt to content, or a fixed value
- height: Controls main container height
- backgroundColor: Container background color
- borderColor: Container border color (1px border)
- borderRadius: Corner radius (0px = square, high values = very rounded)
- padding: Space between content and container edges
- gap: Vertical space between button row and status text
buttons.voice (Live voice recording button)
- backgroundColor: Circular button color
- textColor: Icon color (currently not applied for SVG)
- hoverColor: Mouse hover color
- size: Circular button diameter (e.g., "40px" = small, "65px" = large)
buttons.audio (Audio file upload button)
- backgroundColor: SVG icon color
- textColor: Text color (currently unused)
- hoverColor: Hover color
- size: Icon size (width and height)
buttons.ocr (OCR button - document upload)
- backgroundColor: OCR button color
- textColor: Text/icon color
- hoverColor: Hover color
- size: Button size
statusText
- color: Status text color
- fontSize: Status text font size
OCR Component Theme
The ocr-file-uploader component receives a subset of the theme via its theme prop:
{
"button": {
"size": "50px",
"backgroundColor": "#10b981",
"hoverColor": "#059669",
"textColor": "#ffffff"
}
}These values are extracted from theme.buttons.ocr of the parent component.
To implement in ocr-file-uploader component:
- Apply
button.sizeto button size - Apply
button.backgroundColorto button background color - Apply
button.hoverColorto hover color - Apply
button.textColorto icon/text color
Theme Examples
See the demo page (src/index.html) for 5 complete theme examples:
- Medical: Compact & Professional (red, small buttons)
- Nature: Large & Organic (green, large buttons, rounded)
- Tech Dark: Minimal & Terminal (dark background, square corners)
- Corporate: Standard & Professional (gray tones)
- Playful: Fun & Colorful (yellow, emojis, large padding)
Usage
Using Proxy API (Recommended)
<voice-input-module
id="my-component"
form-json='{...}'
context="ng"
api-proxy-url="http://localhost:8492"
input-types="['voice', 'audio', 'ocr']"
theme='{"texts":{"idle":"Start recording"},"container":{"backgroundColor":"#f0f9ff"},"buttons":{"voice":{"backgroundColor":"#0ea5e9","size":"60px"}}}'
>
</voice-input-module>Using Direct API Calls
<voice-input-module
id="my-component"
form-json='{...}'
api-key="sk-..."
context="ng"
input-types="['voice', 'audio', 'ocr']"
theme='{"texts":{"idle":"Start recording"},"container":{"backgroundColor":"#f0f9ff"},"buttons":{"voice":{"backgroundColor":"#0ea5e9","size":"60px"}}}'
>
</voice-input-module>Or in JavaScript:
const component = document.createElement('voice-input-module');
const theme = {
texts: { idle: "Start recording" },
container: { backgroundColor: "#f0f9ff" },
buttons: { voice: { backgroundColor: "#0ea5e9", size: "60px" } }
};
component.setAttribute('theme', JSON.stringify(theme));Important Notes
- All properties are optional: If a property is not provided, the default value is used
- Theme is reactive: Changing the
themeattribute updates the component in real-time - Colors: Accept all CSS formats (hex, rgb, rgba, color names)
- Sizes: Must include unit (px, rem, em, %)
- Width "auto": Recommended for container to adapt to button sizes
- Gap: Controls vertical spacing between buttons and status text
API Proxy Configuration
Overview
The voice-input-module component supports two operating modes for OpenAI API calls:
- Proxy Mode (Recommended): API calls go through a proxy server that securely manages API keys
- Direct Mode: API calls are made directly from the browser (for development only)
Proxy Mode (Default)
Advantages
- ✅ Security: API keys remain server-side
- ✅ Control: Ability to log, limit, or modify requests
- ✅ Production-ready: Recommended for production environments
Configuration
- Start the proxy API server (see
api-proxy/README.md) - Use the component without providing an
api-key:
<voice-input-module
form-json='{"fields": {...}}'
context="ng"
api-proxy-url="http://localhost:8492"
>
</voice-input-module>Parameters
api-proxy-url: Proxy server URL (default:http://localhost:8492)api-key: Do not provide to use proxy mode
Endpoints Used
The component will automatically call:
POST {api-proxy-url}/transcribefor audio transcriptionPOST {api-proxy-url}/completefor LLM form filling
Direct Mode
Advantages
- ✅ Simple: No proxy server needed
- ✅ Development: Ideal for quick testing
Disadvantages
- ❌ Security: API key is exposed client-side
- ❌ Not recommended for production
Configuration
- Provide an OpenAI API key to the component:
<voice-input-module
form-json='{"fields": {...}}'
context="ng"
api-key="sk-proj-..."
>
</voice-input-module>Parameters
api-key: OpenAI API key (starts withsk-)api-proxy-url: Ignored whenapi-keyis provided
Endpoints Used
The component will directly call:
POST https://api.openai.com/v1/audio/transcriptionsfor transcriptionPOST https://api.openai.com/v1/chat/completionsfor LLM
Selection Logic
if (apiKey) {
// Direct Mode: Direct calls to OpenAI
useProxy = false;
baseUrl = 'https://api.openai.com/v1';
} else {
// Proxy Mode: Calls via proxy server
useProxy = true;
baseUrl = apiProxyUrl || 'http://localhost:8492';
}Migration
From Direct to Proxy
<voice-input-module
form-json='...'
context="ng"
- api-key="sk-proj-..."
+ api-proxy-url="http://localhost:8492"
>
</voice-input-module>From Proxy to Direct
<voice-input-module
form-json='...'
context="ng"
- api-proxy-url="http://localhost:8492"
+ api-key="sk-proj-..."
>
</voice-input-module>Complete Examples
Example 1: Production with Proxy
<!DOCTYPE html>
<html>
<head>
<script type="module" src="./build/voice-input-module.esm.js"></script>
</head>
<body>
<voice-input-module
form-json='{"fields": {"name": {"type": "string", "title": "Name"}}}'
context="track"
api-proxy-url="https://api.mycompany.com/openai-proxy"
language="en"
input-types='["voice", "audio"]'
>
</voice-input-module>
</body>
</html>Example 2: Development with Direct
<!DOCTYPE html>
<html>
<head>
<script type="module" src="./build/voice-input-module.esm.js"></script>
</head>
<body>
<voice-input-module
form-json='{"fields": {"name": {"type": "string", "title": "Name"}}}'
context="track"
api-key="sk-proj-xxxxxxxxxxxxx"
language="en"
input-types='["voice", "audio"]'
>
</voice-input-module>
</body>
</html>Troubleshooting
Component is not making API calls
Check:
- If
api-keyis not provided, is the proxy server running? - Is the proxy URL correct?
- Does the proxy server have a valid OpenAI API key in its
.env?
CORS Error
Proxy Mode: Check the CORS configuration of the proxy server (api-proxy/main.py)
Direct Mode: Direct calls to OpenAI from the browser may be blocked by CORS in some cases
Authentication Error
Proxy Mode: Verify that the proxy server has a valid API key in api-proxy/.env
Direct Mode: Verify that the provided API key is valid and active
License
MIT License - See LICENSE at the root of the project
