mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
128 lines
3.3 KiB
JavaScript
128 lines
3.3 KiB
JavaScript
require('dotenv/config');
|
|
const axios = require('axios');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const API_KEY = process.env.ASSEMBLYAI_API_KEY;
|
|
const BASE_URL = 'https://api.assemblyai.com/v2';
|
|
|
|
/**
|
|
* Uploads audio file to AssemblyAI
|
|
*/
|
|
async function uploadAudio(audioPath) {
|
|
const audioData = fs.readFileSync(audioPath);
|
|
|
|
const response = await axios.post(`${BASE_URL}/upload`, audioData, {
|
|
headers: {
|
|
'authorization': API_KEY,
|
|
'content-type': 'application/octet-stream'
|
|
}
|
|
});
|
|
|
|
return response.data.upload_url;
|
|
}
|
|
|
|
/**
|
|
* Extract session id from path or URL
|
|
*/
|
|
function getSessionId(inputPath) {
|
|
try {
|
|
const parsed = new URL(inputPath);
|
|
const base = path.basename(parsed.pathname);
|
|
return base.replace(/\.[^.]+$/, '');
|
|
} catch (err) {
|
|
return path.basename(inputPath, path.extname(inputPath));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates transcription job with speaker diarization
|
|
*/
|
|
async function createTranscript(audioUrl) {
|
|
const response = await axios.post(`${BASE_URL}/transcript`, {
|
|
audio_url: audioUrl,
|
|
speaker_labels: true,
|
|
language_detection: true
|
|
}, {
|
|
headers: {
|
|
'authorization': API_KEY,
|
|
'content-type': 'application/json'
|
|
}
|
|
});
|
|
|
|
return response.data.id;
|
|
}
|
|
|
|
/**
|
|
* Polls transcript status until completed
|
|
*/
|
|
async function pollTranscript(transcriptId) {
|
|
while (true) {
|
|
const response = await axios.get(`${BASE_URL}/transcript/${transcriptId}`, {
|
|
headers: { 'authorization': API_KEY }
|
|
});
|
|
|
|
const status = response.data.status;
|
|
|
|
if (status === 'completed') {
|
|
return response.data;
|
|
} else if (status === 'error') {
|
|
throw new Error(`Transcription failed: ${response.data.error}`);
|
|
}
|
|
|
|
// Wait 3 seconds before next poll
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Saves transcript to storage
|
|
*/
|
|
function saveTranscript(transcript, sessionId) {
|
|
const outputDir = path.join(__dirname, '..', '..', '..', 'storage', 'transcripts');
|
|
|
|
if (!fs.existsSync(outputDir)) {
|
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
}
|
|
|
|
const outputPath = path.join(outputDir, `${sessionId}.json`);
|
|
fs.writeFileSync(outputPath, JSON.stringify(transcript, null, 2));
|
|
|
|
console.log(`✅ Transcript saved: ${outputPath}`);
|
|
}
|
|
|
|
module.exports = {
|
|
name: "assembly",
|
|
type: "transcription",
|
|
displayname: "AssemblyAI",
|
|
run: async function(audioPath) {
|
|
try {
|
|
// Determine if audioPath is an external URL or a local file
|
|
let audioUrl;
|
|
if (/^https?:\/\//i.test(audioPath)) {
|
|
console.log('🔗 Using external audio URL...');
|
|
audioUrl = audioPath;
|
|
} else {
|
|
if (!fs.existsSync(audioPath)) {
|
|
throw new Error(`Audio file not found: ${audioPath}`);
|
|
}
|
|
console.log('📤 Uploading audio file...');
|
|
audioUrl = await uploadAudio(audioPath);
|
|
}
|
|
|
|
console.log('🔄 Creating transcript job...');
|
|
const transcriptId = await createTranscript(audioUrl);
|
|
|
|
console.log('⏳ Waiting for transcription...');
|
|
const transcript = await pollTranscript(transcriptId);
|
|
|
|
const sessionId = getSessionId(audioPath);
|
|
saveTranscript(transcript, sessionId);
|
|
|
|
return transcript;
|
|
} catch (error) {
|
|
console.error('❌ Transcription error:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
}; |