import axios from "axios"; import { storage } from "./storage"; import type { InsertTranscription } from "@shared/schema"; import path from "path"; import fs from "fs"; import { execSync } from "child_process"; // Import execSync directly const TEMP_DIR = "uploads/transcription/"; // Ensure temp directory exists if (!fs.existsSync(TEMP_DIR)) { fs.mkdirSync(TEMP_DIR, { recursive: true }); } // Simple function to call Deepgram API directly async function transcribeWithDeepgram(audioFilePath: string): Promise { try { const audioData = fs.createReadStream(audioFilePath); const response = await axios.post( "https://api.deepgram.com/v1/listen", audioData, { headers: { Authorization: `Token ${process.env.DEEPGRAM_API_KEY}`, "Content-Type": "audio/wav", }, params: { model: "whisper", language: "ar", smart_format: true, detect_language: true, }, }, ); if (response.data && response.data.results) { return response.data.results.channels[0].alternatives[0].transcript; } console.error("❌ Deepgram response error: No results found."); return ""; } catch (error) { console.error( "❌ Deepgram API Error:", error.response?.data || error.message, ); return ""; } } // Simple function to translate using OpenAI API directly async function translateWithOpenAI(text: string): Promise { try { const response = await axios.post( "https://api.openai.com/v1/chat/completions", { model: "gpt-4", messages: [ { role: "system", content: "You are a professional translator. Translate the following text to Arabic if you recieve english and if you recieve arabic translate to english, maintaining the original meaning and context.", }, { role: "user", content: text, }, ], }, { headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, "Content-Type": "application/json", }, }, ); return response.data.choices[0].message.content; } catch (error) { console.error( "❌ OpenAI API Error:", error.response?.data || error.message, ); throw error; } } // For testing: Use local file instead of RTMP stream async function useTestFile(sessionId: number): Promise { const testFile = path.join(process.cwd(), "uploads", "3.mp3"); if (!fs.existsSync(testFile)) { throw new Error("Test file '2.mp3' not found in uploads folder"); } console.log(`Using test file: ${testFile}`); return testFile; } export async function processStreamClip(sessionId: number): Promise { let audioPath: string | undefined; try { // First update RTMP status to running await storage.updateTranscription(sessionId, { rtmpStreamStatus: "running", rtmpErrorMessage: null, }); // For testing: Use local file instead of RTMP stream audioPath = await useTestFile(sessionId); // Convert the audio file to WAV with correct parameters const uniqueFileName = `${Date.now()}_temp_audio.wav`; const wavPath = path.join(TEMP_DIR, uniqueFileName); // Convert to WAV with exact parameters const ffmpegCmd = `ffmpeg -i "${audioPath}" -acodec pcm_s16le -ac 1 -ar 16000 "${wavPath}"`; console.log("🎙 Converting audio to WAV format..."); execSync(ffmpegCmd); // Use imported execSync directly // Get transcription from Deepgram console.log("🎙 Sending to Deepgram for transcription..."); const originalText = await transcribeWithDeepgram(wavPath); console.log("✅ Transcription received:", originalText); if (originalText) { // Translate to Arabic with OpenAI console.log("🤖 Translating to Arabic with OpenAI..."); const translatedText = await translateWithOpenAI(originalText); console.log("✅ Translation received:", translatedText); // Create transcription record const transcriptionData: InsertTranscription = { sessionId, sourceLanguage: "en", originalText, translatedText, clipStartTime: new Date(Date.now() - 20000), // 20 seconds ago clipEndTime: new Date(), }; await storage.createTranscription(transcriptionData); console.log("✅ Transcription saved to database"); // Cleanup fs.unlinkSync(wavPath); } } catch (error) { console.error("❌ Error processing stream clip:", error); // Update RTMP status with error await storage.updateTranscription(sessionId, { rtmpStreamStatus: "error", rtmpErrorMessage: error instanceof Error ? error.message : "Unknown error occurred", }); } } let transcriptionInterval: NodeJS.Timeout | null = null; export function startTranscriptionService(sessionId: number): void { if (transcriptionInterval) { clearInterval(transcriptionInterval); } // For testing: Process just once instead of interval processStreamClip(sessionId).catch(console.error); } export function stopTranscriptionService(): void { if (transcriptionInterval) { clearInterval(transcriptionInterval); transcriptionInterval = null; } }