Full-Stack Implementation of AI Conversation Assistant Based on Containerized Architecture
This article outlines a containerized architecture solution for developing an AI conversation assistant, covering system design, core functionality implementation, engineering practices, and performance optimization strategies.
System Architecture Design
Containerization Advantages
The solution implements frontend-backend separation through containerized deployment using Docker images to encapsulate complete runtime environments, ensuring consistency across development, testing, and production stages. Kubernetes-based dynamic resource scheduling enables elastic scaling to maintain service stability under high concurrency. Frontend containers contain only static assets and rendering logic, while backend containers integrate business services with middleware dependencies as independent service units.
Technology Stack Selection
The layered architecture follows these principles:
- Frontend: Vue 3 composition API for code reusability, TypeScript for type safety, and Vite for rapid hot reloading
- Service Layer: Express framework for lightweight HTTP services, SQLite as embedded database
- Middleware: Redis for rate limiting, BullMQ for asynchronous task queues
- Speech Processing: Browser MediaRecorder API for audio capture, whisper.cpp for local speech recognition
Core Functionality Implementation
Streaming Conversation Interface
Server-Sent Events (SSE) enable real-time AI response streaming with chunked transfer encoding. The frontend establishes persistent connections via EventSource API to monitor three event types:
// Frontend streaming implementationconst eventSource = new EventSource(`/api/chat?stream=true`);eventSource.onmessage = (e) => {const data = JSON.parse(e.data);if (data.event === 'delta') updateChatContent(data.content);};
Dual-Token Authentication
The accessToken (15-minute validity) + refreshToken (7-day validity) system enables seamless token renewal:
// Token refresh interceptoraxios.interceptors.response.use(response => response,async (error) => {if (error.response.status === 401) {const { data } = await refreshToken();store.commit('updateTokens', data);return axios(error.config);}});
Voice Processing Pipeline
- Audio Capture: Web Audio API for standardized WAV output
- Asynchronous Transcription: BullMQ processes audio files through local whisper.cpp models
- Result Storage: Transcription text linked with original audio for message history
```javascript
// Voice processing task definition
const voiceQueue = new Bull(‘voice-processing’, {
redis: process.env.REDIS_URL,
defaultJobOptions: { attempts: 3, backoff: { type: ‘exponential’, delay: 1000 } }
});
voiceQueue.process(async (job) => {
const { filePath } = job.data;
const result = await whisper.transcribe(filePath);
return await saveTranscription(result);
});
# Engineering Practices## Monorepo StructureThe project adopts a unified repository with clear module separation:
.
├── ui/ # Frontend components
│ ├── src/
│ │ ├── api/ # API wrappers
│ │ ├── hooks/ # Custom hooks
│ │ └── utils/ # Utility functions
├── backend/ # Backend services
│ ├── controllers/ # Route handlers
│ ├── middleware/ # Middleware
│ └── repositories/ # Data access
└── docker-compose.yml # Container orchestration
## Container Build OptimizationMulti-stage Docker builds minimize image sizes:```dockerfile# Frontend build exampleFROM node:18-alpine as builderWORKDIR /appCOPY ui/package*.json ./RUN npm installCOPY ui/ .RUN npm run buildFROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlCOPY nginx.conf /etc/nginx/conf.d/default.conf
Automated Observability
Prometheus metrics integration with Grafana dashboards monitor:
- API response time distribution
- Voice processing queue backlog
- Token refresh frequency
- Database connection pool status
Performance Optimization
Rate Limiting Implementation
Redis sliding window algorithm provides granular rate control:
// Rate limiting middlewareconst rateLimiter = async (req, res, next) => {const key = `${req.ip}:${req.path}`;const now = Date.now();const windowSize = 60 * 1000; // 1-minute windowlet records = await redis.lrange(key, 0, -1);records = records.map(t => parseInt(t)).filter(t => now - t < windowSize);if (records.length >= 100) {return res.status(429).json({ error: 'Rate limit exceeded' });}records.push(now);await redis.rpush(key, ...records.slice(-99));await redis.expire(key, windowSize / 1000);next();};
Database Optimization
SQLite WAL mode improves concurrency with strategic indexing:
-- Session table indexesCREATE INDEX idx_sessions_user ON sessions(user_id);CREATE INDEX idx_sessions_updated ON sessions(updated_at);-- Message table indexesCREATE INDEX idx_messages_session ON messages(session_id);CREATE INDEX idx_messages_timestamp ON messages(timestamp);
Extensibility Design
Model Plug-in Architecture
Factory pattern enables dynamic AI model switching:
interface IModelClient {generate(prompt: string): Promise<string>;}class ModelFactory {static create(type: 'openai' | 'deepseek'): IModelClient {switch(type) {case 'openai': return new OpenAIClient();case 'deepseek': return new DeepSeekClient();default: throw new Error('Unsupported model');}}}
Multi-platform Adaptation
Conditional compilation enables code reuse across H5 and mini-programs:
// vite.config.js exampleexport default defineConfig({plugins: [vue({template: {compilerOptions: {isCustomElement: (tag) => tag.startsWith('mp-') // Mini-program handling}}})]});
This containerized architecture provides a production-validated solution for rapid AI conversation system development. The approach enables seamless cloud migration and hybrid deployment while maintaining all core functionalities from streaming interaction to automated operations.
