The extension integrates with multiple AI providers for transcription and summarization. This document details the API implementations and usage.
{
provider: 'openai',
apiKey: 'sk-...',
transcriptionModel: 'whisper-1',
summarizationModel: 'gpt-4o-mini'
}
Endpoint: https://api.openai.com/v1/audio/transcriptions
Request:
const formData = new FormData();
formData.append('file', audioBlob, 'audio.webm');
formData.append('model', 'whisper-1');
formData.append('language', 'id'); // Indonesian
formData.append('response_format', 'json');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`
},
body: formData
});
Response:
{
"text": "Transcribed text in Indonesian..."
}
Endpoint: https://api.openai.com/v1/chat/completions
Request:
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: SYSTEM_PROMPT_INDO
},
{
role: 'user',
content: transcript
}
],
temperature: 0.3,
max_tokens: 2000
})
});
{
provider: 'gemini',
apiKey: 'AIza...',
transcriptionModel: 'gemini-2.0-flash-exp',
summarizationModel: 'gemini-2.0-flash-exp'
}
Endpoint: https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent
Request:
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-goog-api-key': apiKey
},
body: JSON.stringify({
contents: [{
parts: [{
text: prompt
}]
}],
generationConfig: {
temperature: 0.3,
maxOutputTokens: 2000
}
})
});
async function processAPIResponse(response, provider) {
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
const data = await response.json();
if (provider === 'openai') {
return data.choices[0].message.content;
} else if (provider === 'gemini') {
return data.candidates[0].content.parts[0].text;
}
}
class APIError extends Error {
constructor(message, status, provider) {
super(message);
this.status = status;
this.provider = provider;
}
}
async function handleAPIError(error) {
if (error.status === 429) {
// Rate limit - implement exponential backoff
await delay(1000 * Math.pow(2, retryCount));
return retry();
} else if (error.status === 401) {
// Invalid API key
throw new APIError('Invalid API key', 401, provider);
} else if (error.status >= 500) {
// Server error - retry
return retry();
}
}
async function callAPIWithRetry(apiCall, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await apiCall();
} catch (error) {
lastError = error;
if (i < maxRetries - 1) {
const delay = Math.min(1000 * Math.pow(2, i), 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
const SYSTEM_PROMPT_INDO = `
Anda adalah asisten medis yang membantu dokter di Puskesmas Indonesia.
Tugas Anda adalah menganalisis transkrip konsultasi dan menghasilkan ringkasan medis terstruktur.
Format output harus dalam JSON dengan kategori berikut:
- keluhan_utama: Keluhan utama pasien
- keluhan_tambahan: Keluhan tambahan (jika ada)
- riwayat_penyakit_sekarang: RPS
- riwayat_penyakit_dahulu: RPD
- riwayat_penyakit_keluarga: RPK
- pemeriksaan_fisik: Hasil pemeriksaan fisik
- diagnosa_kerja: Diagnosa kerja
- diagnosa_banding: Diagnosa banding
- terapi_obat: Daftar obat dengan dosis
- terapi_non_obat: Terapi non-obat
- edukasi: Edukasi untuk pasien
`;
const MEDICAL_TERMS = {
'demam': 'febris',
'sakit kepala': 'cephalgia',
'batuk': 'tussis',
'pilek': 'rhinitis',
// ... extensive medical dictionary
};
function convertToMedicalTerms(text) {
let result = text;
for (const [common, medical] of Object.entries(MEDICAL_TERMS)) {
const regex = new RegExp(`\\b${common}\\b`, 'gi');
result = result.replace(regex, medical);
}
return result;
}
class RateLimiter {
constructor(maxRequests, timeWindow) {
this.maxRequests = maxRequests;
this.timeWindow = timeWindow;
this.requests = [];
}
async throttle() {
const now = Date.now();
this.requests = this.requests.filter(t => now - t < this.timeWindow);
if (this.requests.length >= this.maxRequests) {
const oldestRequest = this.requests[0];
const waitTime = this.timeWindow - (now - oldestRequest);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.requests.push(now);
}
}
const mockResponses = {
transcription: {
text: "Pasien mengeluh demam sejak 3 hari..."
},
summary: {
keluhan_utama: "Demam",
diagnosa_kerja: "Suspek dengue fever"
}
};
function setupMockAPI() {
if (DEVELOPMENT_MODE) {
window.fetch = async (url, options) => {
// Return mock data for testing
return new Response(JSON.stringify(mockResponses));
};
}
}