Prepare application for production deployment with enhanced voice features
Adds production environment configuration, global type declarations, and enhances voice recognition error handling and result processing. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ff0be73b-afdd-4747-978b-bb8301fb0a82 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9777c70b-fc38-4831-8d6b-78dfffe041b0/4b7360ad-65af-421c-ae9c-12d0b5534ad8.jpg
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
# Production Environment Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# Database Configuration (will be set by deployment platform)
|
||||||
|
DATABASE_URL=
|
||||||
|
|
||||||
|
# Security Configuration
|
||||||
|
SESSION_SECRET=your-production-session-secret-here
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
# API Keys (to be provided via deployment secrets)
|
||||||
|
ANTHROPIC_API_KEY=
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
APP_NAME=MenAssist
|
||||||
|
APP_VERSION=1.0.0
|
||||||
|
CORS_ORIGIN=https://your-domain.replit.app
|
||||||
|
|
||||||
|
# Voice Processing Configuration
|
||||||
|
VOICE_ENABLED=true
|
||||||
|
TTS_ENABLED=true
|
||||||
|
VOICE_TIMEOUT=30000
|
||||||
|
|
||||||
|
# AI Configuration
|
||||||
|
AI_ENABLED=true
|
||||||
|
AI_MODEL_PATH=./models/ai/base-llm
|
||||||
|
DAILY_JOKE_CACHE_TTL=86400
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
LOG_LEVEL=info
|
||||||
|
LOG_FORMAT=json
|
||||||
|
|
||||||
|
# Performance Configuration
|
||||||
|
CACHE_TTL=3600
|
||||||
|
MAX_UPLOAD_SIZE=10mb
|
||||||
|
REQUEST_TIMEOUT=30000
|
||||||
@@ -79,7 +79,7 @@ export function useEnhancedVoice() {
|
|||||||
console.log('Voice recognition ended');
|
console.log('Voice recognition ended');
|
||||||
};
|
};
|
||||||
|
|
||||||
recognition.onerror = (event) => {
|
recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
|
||||||
console.error('Voice recognition error:', event.error);
|
console.error('Voice recognition error:', event.error);
|
||||||
setIsListening(false);
|
setIsListening(false);
|
||||||
if (event.error === 'no-speech') {
|
if (event.error === 'no-speech') {
|
||||||
@@ -91,17 +91,22 @@ export function useEnhancedVoice() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
recognition.onresult = (event) => {
|
recognition.onresult = (event: SpeechRecognitionEvent) => {
|
||||||
let finalTranscript = '';
|
let finalTranscript = '';
|
||||||
let interimTranscript = '';
|
let interimTranscript = '';
|
||||||
|
|
||||||
for (let i = event.resultIndex; i < event.results.length; i++) {
|
for (let i = event.resultIndex; i < event.results.length; i++) {
|
||||||
const result = event.results[i];
|
const result = event.results[i];
|
||||||
const transcript = result[0].transcript;
|
if (!result) continue;
|
||||||
|
|
||||||
|
const alternative = result[0];
|
||||||
|
if (!alternative) continue;
|
||||||
|
|
||||||
|
const transcript = alternative.transcript;
|
||||||
|
|
||||||
if (result.isFinal) {
|
if (result.isFinal) {
|
||||||
finalTranscript += transcript;
|
finalTranscript += transcript;
|
||||||
if (result[0].confidence >= settings.confidenceThreshold) {
|
if (alternative.confidence >= settings.confidenceThreshold) {
|
||||||
processVoiceCommand(transcript, result[0].confidence);
|
processVoiceCommand(transcript, result[0].confidence);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Vendored
+79
@@ -0,0 +1,79 @@
|
|||||||
|
// Global type declarations for production environment
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
SpeechRecognition: typeof SpeechRecognition;
|
||||||
|
webkitSpeechRecognition: typeof SpeechRecognition;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechRecognition extends EventTarget {
|
||||||
|
continuous: boolean;
|
||||||
|
grammars: SpeechGrammarList;
|
||||||
|
interimResults: boolean;
|
||||||
|
lang: string;
|
||||||
|
maxAlternatives: number;
|
||||||
|
serviceURI: string;
|
||||||
|
start(): void;
|
||||||
|
stop(): void;
|
||||||
|
abort(): void;
|
||||||
|
onaudiostart: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onaudioend: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onend: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onerror: ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => any) | null;
|
||||||
|
onnomatch: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => any) | null;
|
||||||
|
onresult: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => any) | null;
|
||||||
|
onsoundstart: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onsoundend: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onspeechstart: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onspeechend: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
onstart: ((this: SpeechRecognition, ev: Event) => any) | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var SpeechRecognition: {
|
||||||
|
prototype: SpeechRecognition;
|
||||||
|
new(): SpeechRecognition;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SpeechRecognitionEvent extends Event {
|
||||||
|
readonly resultIndex: number;
|
||||||
|
readonly results: SpeechRecognitionResultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechRecognitionErrorEvent extends Event {
|
||||||
|
readonly error: string;
|
||||||
|
readonly message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechRecognitionResult {
|
||||||
|
readonly isFinal: boolean;
|
||||||
|
readonly length: number;
|
||||||
|
item(index: number): SpeechRecognitionAlternative;
|
||||||
|
[index: number]: SpeechRecognitionAlternative;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechRecognitionResultList {
|
||||||
|
readonly length: number;
|
||||||
|
item(index: number): SpeechRecognitionResult;
|
||||||
|
[index: number]: SpeechRecognitionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechRecognitionAlternative {
|
||||||
|
readonly transcript: string;
|
||||||
|
readonly confidence: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechGrammarList {
|
||||||
|
readonly length: number;
|
||||||
|
item(index: number): SpeechGrammar;
|
||||||
|
[index: number]: SpeechGrammar;
|
||||||
|
addFromURI(src: string, weight?: number): void;
|
||||||
|
addFromString(string: string, weight?: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpeechGrammar {
|
||||||
|
src: string;
|
||||||
|
weight: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// Production configuration for MenAssist
|
||||||
|
const config = {
|
||||||
|
// Server Configuration
|
||||||
|
server: {
|
||||||
|
port: process.env.PORT || 5000,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
compression: true,
|
||||||
|
helmet: true,
|
||||||
|
rateLimit: {
|
||||||
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||||
|
max: 100, // limit each IP to 100 requests per windowMs
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Database Configuration
|
||||||
|
database: {
|
||||||
|
ssl: true,
|
||||||
|
connectionTimeout: 30000,
|
||||||
|
idleTimeout: 30000,
|
||||||
|
maxConnections: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Security Configuration
|
||||||
|
security: {
|
||||||
|
session: {
|
||||||
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'strict',
|
||||||
|
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
|
},
|
||||||
|
cors: {
|
||||||
|
origin: process.env.CORS_ORIGIN || 'https://your-domain.replit.app',
|
||||||
|
credentials: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// AI Configuration
|
||||||
|
ai: {
|
||||||
|
enabled: process.env.AI_ENABLED === 'true',
|
||||||
|
timeout: 30000,
|
||||||
|
maxTokens: 1024,
|
||||||
|
rateLimiting: {
|
||||||
|
requests: 50,
|
||||||
|
window: 60000, // 1 minute
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Voice Configuration
|
||||||
|
voice: {
|
||||||
|
enabled: process.env.VOICE_ENABLED === 'true',
|
||||||
|
timeout: process.env.VOICE_TIMEOUT || 30000,
|
||||||
|
maxDuration: 60000, // 1 minute max recording
|
||||||
|
sampleRate: 16000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Logging Configuration
|
||||||
|
logging: {
|
||||||
|
level: process.env.LOG_LEVEL || 'info',
|
||||||
|
format: process.env.LOG_FORMAT || 'json',
|
||||||
|
enableAccessLogs: true,
|
||||||
|
enableErrorLogs: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Cache Configuration
|
||||||
|
cache: {
|
||||||
|
ttl: process.env.CACHE_TTL || 3600,
|
||||||
|
maxSize: '100mb',
|
||||||
|
compression: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// File Upload Configuration
|
||||||
|
upload: {
|
||||||
|
maxSize: process.env.MAX_UPLOAD_SIZE || '10mb',
|
||||||
|
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
||||||
|
destination: './uploads',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
||||||
Reference in New Issue
Block a user