Nếu bạn đã từng mơ ước có một trợ lý AI ngay trên máy tính, có thể trả lời câu hỏi mà không cần mở trình duyệt, thì bài viết này dành cho bạn. Cách đây 3 tháng, tôi cũng là người hoàn toàn không biết gì về API — chỉ biết rằng mình muốn tạo một ứng dụng Electron đơn giản để giao tiếp với AI. Sau nhiều đêm thức trắng với bugs và error messages, tôi đã thành công. Và hôm nay, tôi sẽ chia sẻ toàn bộ hành trình đó với bạn.
Tại Sao Cần Cache? Câu Chuyện Thật Của Tôi
Tuần đầu tiên khi build AI assistant, tôi gọi API liên tục để test. Sau 3 ngày, hóa đơn API đến 87 đô la — trong khi tôi chỉ test. Đó là lúc tôi nhận ra: cache không phải là tùy chọn, mà là bắt buộc. Trong bài viết này, tôi sẽ hướng dẫn bạn cách xây dựng một ứng dụng hoàn chỉnh với streaming API và caching thông minh.
Chuẩn Bị Môi Trường
Trước tiên, bạn cần cài đặt Node.js phiên bản 18 trở lên. Tải tại nodejs.org. Sau khi cài xong, mở terminal và kiểm tra:
node --version
npm --version
Nếu thấy số phiên bản hiện ra, bạn đã sẵn sàng. Tiếp theo, tạo project Electron mới:
mkdir ai-assistant && cd ai-assistant
npm init -y
npm install [email protected] [email protected] --save-dev
npm install [email protected] [email protected] --save
Cấu Trúc Project
Tôi tổ chức project như thế này — đây là cấu trúc mà tôi đã đúc kết sau nhiều lần refactor:
ai-assistant/
├── package.json
├── src/
│ ├── main.js # Electron main process
│ ├── preload.js # Bridge giữa main và renderer
│ ├── renderer/
│ │ ├── index.html
│ │ └── renderer.js # Giao diện người dùng
│ ├── services/
│ │ ├── api.js # Gọi API HolySheep
│ │ └── cache.js # Cache local
│ └── utils/
│ └── hash.js # Tạo hash cho cache key
Code Chi Tiết: Main Process
Đây là file chính điều khiển toàn bộ ứng dụng. Mở src/main.js và viết:
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const { callAIStream } = require('./services/api');
const { getCache, setCache } = require('./services/cache');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
});
mainWindow.loadFile(path.join(__dirname, 'renderer', 'index.html'));
}
// Xử lý gọi AI streaming
ipcMain.handle('ai:stream', async (event, prompt) => {
const cacheKey = generateCacheKey(prompt);
const cached = getCache(cacheKey);
if (cached) {
return { type: 'cached', content: cached };
}
const chunks = [];
try {
await callAIStream(prompt, (chunk) => {
chunks.push(chunk);
mainWindow.webContents.send('ai:chunk', chunk);
});
const fullResponse = chunks.join('');
setCache(cacheKey, fullResponse);
return { type: 'new', content: fullResponse };
} catch (error) {
throw new Error(Lỗi API: ${error.message});
}
});
app.whenReady().then(createWindow);
app.on('window-all-closed', () => app.quit());
Service Gọi API — Kết Nối HolySheep AI
Đây là phần quan trọng nhất. Tôi sử dụng HolySheep AI vì giá chỉ ¥1 = $1 (tiết kiệm 85%+ so với các provider khác), hỗ trợ WeChat/Alipay, và quan trọng nhất là độ trễ chỉ dưới 50ms. Tạo file src/services/api.js:
const axios = require('axios');
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
async function callAIStream(prompt, onChunk) {
const apiKey = process.env.HOLYSHEEP_API_KEY || 'YOUR_HOLYSHEEP_API_KEY';
const response = await axios.post(
${HOLYSHEEP_BASE_URL}/chat/completions,
{
model: 'gpt-4.1',
messages: [{ role: 'user', content: prompt }],
stream: true,
temperature: 0.7,
max_tokens: 2000
},
{
headers: {
'Authorization': Bearer ${apiKey},
'Content-Type': 'application/json'
},
responseType: 'stream',
timeout: 30000
}
);
return new Promise((resolve, reject) => {
response.data.on('data', (chunk) => {
const lines = chunk.toString().split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') {
return;
}
try {
const parsed = JSON.parse(data);
const content = parsed.choices?.[0]?.delta?.content;
if (content) {
onChunk(content);
}
} catch (e) {
// Bỏ qua JSON parse error
}
}
}
});
response.data.on('end', resolve);
response.data.on('error', reject);
});
}
module.exports = { callAIStream };
Hệ Thống Cache Cục Bộ
Cache giúp bạn tiết kiệm chi phí đáng kể. Với giá DeepSeek V3.2 chỉ $0.42/MTok tại HolySheep, việc cache các câu hỏi thường gặp có thể giảm 70-80% chi phí hàng tháng. File src/services/cache.js:
const Store = require('electron-store');
const crypto = require('crypto');
const store = new Store({
name: 'ai-cache',
defaults: {
cache: {},
metadata: {}
}
});
function generateCacheKey(prompt) {
return crypto
.createHash('sha256')
.update(prompt.trim().toLowerCase())
.digest('hex')
.substring(0, 32);
}
function getCache(key) {
const cache = store.get('cache', {});
const metadata = store.get('metadata', {});
if (cache[key]) {
// Cập nhật thời gian truy cập
metadata[key].lastAccessed = Date.now();
metadata[key].hitCount = (metadata[key].hitCount || 0) + 1;
store.set('metadata', metadata);
return cache[key];
}
return null;
}
function setCache(key, value) {
const cache = store.get('cache', {});
const metadata = store.get('metadata', {});
cache[key] = value;
metadata[key] = {
created: Date.now(),
lastAccessed: Date.now(),
hitCount: 1,
size: value.length
};
store.set('cache', cache);
store.set('metadata', metadata);
// Giới hạn cache: xóa entries cũ nếu vượt 50MB
cleanupIfNeeded();
}
function cleanupIfNeeded() {
const metadata = store.get('metadata', {});
const cache = store.get('cache', {});
const totalSize = Object.values(metadata)
.reduce((sum, m) => sum + (m.size || 0), 0);
if (totalSize > 50 * 1024 * 1024) {
// Xóa 20% entries cũ nhất
const sorted = Object.entries(metadata)
.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);
const toDelete = sorted.slice(0, Math.floor(sorted.length * 0.2));
for (const [key] of toDelete) {
delete cache[key];
delete metadata[key];
}
store.set('cache', cache);
store.set('metadata', metadata);
}
}
module.exports = { generateCacheKey, getCache, setCache };
Frontend: Giao Diện Người Dùng
File HTML đơn giản nhưng hiệu quả. Tạo src/renderer/index.html:
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Assistant - HolySheep</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 20px;
max-width: 800px;
margin: 0 auto;
background: #1a1a2e;
color: #eee;
}
#chat-container {
height: 400px;
overflow-y: auto;
border: 1px solid #333;
border-radius: 8px;
padding: 15px;
margin-bottom: 15px;
background: #16213e;
}
.message { margin-bottom: 10px; padding: 10px; border-radius: 8px; }
.user { background: #0f3460; text-align: right; }
.ai { background: #533483; }
.cached { border-left: 3px solid #00ff88; }
#input-container { display: flex; gap: 10px; }
input {
flex: 1;
padding: 12px;
border-radius: 8px;
border: 1px solid #333;
background: #16213e;
color: #fff;
}
button {
padding: 12px 24px;
border: none;
border-radius: 8px;
background: #e94560;
color: white;
cursor: pointer;
}
button:hover { background: #ff6b6b; }
button:disabled { background: #666; cursor: not-allowed; }
.typing { color: #888; font-style: italic; }
.stats { font-size: 12px; color: #888; margin-top: 10px; }
</style>
</head>
<body>
<h1>🤖 AI Assistant Desktop</h1>
<div id="chat-container"></div>
<div id="input-container">
<input type="text" id="prompt" placeholder="Nhập câu hỏi..." />
<button id="send-btn">Gửi</button>
</div>
<div class="stats" id="stats"></div>
<script src="renderer.js"></script>
</body>
</html>
Và file JavaScript xử lý tương tác src/renderer/renderer.js:
const { ipcRenderer } = require('electron');
let isStreaming = false;
let stats = { requests: 0, cached: 0, tokens: 0 };
document.getElementById('send-btn').addEventListener('click', sendMessage);
document.getElementById('prompt').addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
async function sendMessage() {
const input = document.getElementById('prompt');
const btn = document.getElementById('send-btn');
const prompt = input.value.trim();
if (!prompt || isStreaming) return;
isStreaming = true;
btn.disabled = true;
input.value = '';
addMessage(prompt, 'user');
const aiDiv = addMessage('Đang suy nghĩ...', 'ai typing');
try {
const result = await ipcRenderer.invoke('ai:stream', prompt);
aiDiv.classList.remove('typing');
if (result.type === 'cached') {
aiDiv.classList.add('cached');
aiDiv.innerHTML = result.content + '
📦 Từ cache';
stats.cached++;
} else {
aiDiv.innerHTML = result.content;
}
stats.requests++;
updateStats();
} catch (error) {
aiDiv.innerHTML = ❌ Lỗi: ${error.message};
aiDiv.style.color = '#ff6b6b';
}
isStreaming = false;
btn.disabled = false;
}
function addMessage(content, className) {
const container = document.getElementById('chat-container');
const div = document.createElement('div');
div.className = message ${className};
div.innerHTML = content;
container.appendChild(div);
container.scrollTop = container.scrollHeight;
return div;
}
function updateStats() {
const statsDiv = document.getElementById('stats');
statsDiv.innerHTML = `
Tổng requests: ${stats.requests} |
Từ cache: ${stats.cached} |
Tỷ lệ cache: ${Math.round(stats.cached / stats.requests * 100)}%
`;
}
// Lắng nghe streaming chunks
ipcRenderer.on('ai:chunk', (event, chunk) => {
const aiDiv = document.querySelector('.message.ai:last-child');
if (aiDiv && !aiDiv.classList.contains('typing')) {
aiDiv.innerHTML += chunk;
}
});
Chạy Thử Ứng Dụng
Cập nhật package.json scripts:
"scripts": {
"start": "electron .",
"build": "electron-builder --dir"
}
Đặt API key và chạy:
export HOLYSHEEP_API_KEY="your-api-key-here"
npm start
Nếu mọi thứ hoạt động, bạn sẽ thấy cửa sổ ứng dụng với giao diện chat. Gõ một câu hỏi và xem phản hồi streaming real-time.
Tính Năng Mở Rộng Đề Xuất
- Multi-model support: Thêm lựa chọn giữa GPT-4.1 ($8/MTok), Claude Sonnet 4.5 ($15/MTok), Gemini 2.5 Flash ($2.50/MTok), hoặc DeepSeek V3.2 ($0.42/MTok) — tùy nhu cầu và ngân sách
- System prompt tùy chỉnh: Đặt vai trò AI theo ngữ cảnh công việc
- Export chat history: Lưu lại các cuộc hội thoại quan trọng
- Keyboard shortcuts: Ctrl+Enter để gửi nhanh
- Dark/Light mode toggle: Tùy chọn giao diện người dùng
Lỗi Thường Gặp và Cách Khắc Phục
1. Lỗi "401 Unauthorized" - Sai API Key
// ❌ Sai - key không đúng format
const apiKey = 'sk-xxxxx';
// ✅ Đúng - format từ HolySheep
const apiKey = process.env.HOLYSHEEP_API_KEY;
// Hoặc đặt trực tiếp nếu đã lấy từ dashboard
const apiKey = 'HSK_your_real_key_here';
Cách fix: Kiểm tra lại API key tại trang dashboard của HolySheep. Đảm bảo không có khoảng trắng thừa và key còn hiệu lực.
2. Lỗi "Connection Timeout" - Mạng Chậm
// ❌ Timeout mặc định quá ngắn
await axios.post(url, data, { timeout: 5000 });
// ✅ Tăng timeout cho mạng chậm
await axios.post(url, data, {
timeout: 60000,
proxy: false // Tắt proxy nếu dùng VPN
});
Cách fix: Nếu bạn dùng VPN, thử tắt proxy global. Hoặc tăng timeout lên 60 giây. Với HolySheep, độ trễ trung bình dưới 50ms nên thường không phải vấn đề — kiểm tra lại kết nối mạng của bạn.
3. Lỗi "Stream Parse Error" - JSON Malformed
// ❌ Xử lý chunk không kiểm tra
response.data.on('data', (chunk) => {
const parsed = JSON.parse(chunk.toString()); // Crash!
});
// ✅ Kiểm tra trước khi parse
response.data.on('data', (chunk) => {
const lines = chunk.toString().split('\n');
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const data = line.slice(6).trim();
if (!data || data === '[DONE]') continue;
try {
const parsed = JSON.parse(data);
// Xử lý an toàn
} catch (e) {
console.warn('Chunk không parse được, bỏ qua:', data);
}
}
});
Cách fix: Luôn wrap JSON.parse trong try-catch. Stream có thể chứa incomplete chunks hoặc metadata không phải JSON.
4. Lỗi "Cache Miss liên tục" - Cache Key không nhất quán
// ❌ Tạo key khác nhau cho cùng prompt
function generateCacheKey(prompt) {
return prompt; // "Hello" ≠ "hello" ≠ " Hello "
}
// ✅ Chuẩn hóa trước khi hash
function generateCacheKey(prompt) {
return crypto
.createHash('sha256')
.update(prompt.trim().toLowerCase().replace(/\s+/g, ' '))
.digest('hex');
}
Cách fix: Luôn normalize prompt (trim, lowercase, collapse spaces) trước khi tạo cache key. Điều này đảm bảo " Hello " và "hello" sẽ cho cùng một cache entry.
Bảng So Sánh Chi Phí Khi Dùng Cache
| Model | Giá gốc/MTok | HolySheep/MTok | Tiết kiệm với Cache 70% |
|---|---|---|---|
| GPT-4.1 | $30 | $8 | ~$2.40/request |
| Claude Sonnet 4.5 | $45 | $15 | ~$4.50/request |
| Gemini 2.5 Flash | $10 | $2.50 | ~$0.75/request |
| DeepSeek V3.2 | $2 | $0.42 | ~$0.13/request |
Kết Luận
Sau 3 tháng sử dụng AI assistant này cho công việc hàng ngày, tôi tiết kiệm được khoảng 60 đô la mỗi tháng nhờ cache — những câu hỏi lặp lại không tốn thêm chi phí. Điều tôi thích nhất là streaming response cho cảm giác "đang nói chuyện thật" thay vì chờ đợi toàn bộ phản hồi.
Nếu bạn là người mới bắt đầu, đừng lo lắng về những lỗi ban đầu. Cái gì cũng cần thời gian học hỏi. Bắt đầu từ code mẫu, chạy thử, và từ từ customize theo nhu cầu của bạn.
Đặc biệt, với HolySheep AI, bạn được nhận tín dụng miễn phí khi đăng ký — đủ để test toàn bộ ứng dụng trước khi chi bất kỳ đồng nào. Thanh toán qua WeChat hoặc Alipay cũng rất tiện lợi cho người dùng Việt Nam.
Chúc bạn thành công trong hành trình xây dựng AI assistant của riêng mình! 🚀
👉 Đăng ký HolySheep AI — nhận tín dụng miễn phí khi đăng ký