From a7b4b707e8a3f1ac7bd2fcdc01de63b56eb32c07 Mon Sep 17 00:00:00 2001 From: Sir Blob <76974209+GamerBoss101@users.noreply.github.com> Date: Sun, 26 Jan 2025 08:57:49 -0500 Subject: [PATCH] final commit --- .../(web)/transcribe/{page.tsx => page.jsx} | 75 ++++----- src/app/(web)/transcribe/textsp.jsx | 74 +++++++++ src/app/api/transcribe/route.js | 152 +++++++++--------- tsconfig.json | 2 +- 4 files changed, 181 insertions(+), 122 deletions(-) rename src/app/(web)/transcribe/{page.tsx => page.jsx} (83%) create mode 100644 src/app/(web)/transcribe/textsp.jsx diff --git a/src/app/(web)/transcribe/page.tsx b/src/app/(web)/transcribe/page.jsx similarity index 83% rename from src/app/(web)/transcribe/page.tsx rename to src/app/(web)/transcribe/page.jsx index d460e86..f307bee 100644 --- a/src/app/(web)/transcribe/page.tsx +++ b/src/app/(web)/transcribe/page.jsx @@ -1,10 +1,8 @@ "use client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -//import Hero1 from '@/components/Hero1' -//IMPORT THE HERO1 FUNCTION TO MAKE THE TRANSCRIBE PAGE LOOK BETTER +import axios from "axios"; import React, { useState, useRef } from "react"; -// import axios from "axios"; import { AlertCircle } from "lucide-react" @@ -15,17 +13,18 @@ import { } from "@/components/ui/alert" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -const AudioTranscriber: React.FC = () => { - const [file, setFile] = useState(null); - const [transcription, setTranscription] = useState(null); +const AudioTranscriber = () => { + const [file, setFile] = useState(null); + const [transcription, setTranscription] = useState(null); const [loading, setLoading] = useState(false); const [recording, setRecording] = useState(false); - const [error, setError] = useState(null); - const mediaRecorderRef = useRef(null); - const audioChunksRef = useRef([]); + const [error, setError] = useState(null); + const mediaRecorderRef = useRef(null); + const audioChunksRef = useRef([]); + const [audioBlob, setAudioBlob] = useState(null); // Handle file selection - const handleFileChange = (event: React.ChangeEvent) => { + const handleFileChange = (event) => { if (event.target.files && event.target.files.length > 0) { setFile(event.target.files[0]); console.log("File selected:", event.target.files[0].name); @@ -33,42 +32,31 @@ const AudioTranscriber: React.FC = () => { }; // Handle file transcription - const handleTranscription = async (audioFile: File) => { - if (!audioFile) { - alert("No audio file to transcribe!"); - return; - } - - console.log("Starting transcription for:", audioFile.name); + const handleTranscription = async () => { + console.log(audioBlob, process.env.REACT_APP_GOOGLE_CLOUD_API_KEY) const formData = new FormData(); - formData.append("file", audioFile); - setLoading(true); - setError(null); // Clear previous errors + formData.append('audio', new Blob(audioChunksRef.current, { type: "audio/mp3" })); + try { - let response = await fetch("/api/transcribe", { - method: "POST", - body: formData, - headers: { - "Content-Type": "multipart/form-data", + const response = await axios.post( + 'https://speech.googleapis.com/v1/speech:recognize', // Replace with your actual endpoint + formData, + { + headers: { + 'Access-Control-Allow-Origin': '*/*', + 'Authorization': `Bearer AIzaSyCgQ_pa8AbNBUViQkqf2sNJQ8zl-fIPQfs`, // Replace with your API key + 'Content-Type': 'multipart/form-data', + }, } - }) + ); - console.log("! response:", response); - response = await response.json(); - console.log("@ response:", response); + console.log(response.data.results[0].alternatives[0].transcript); - // if (response.data && response.data.transcription) { - // setTranscription(response.data.transcription); - // } else { - // setError("Unexpected response format. Check backend API."); - // console.error("Invalid response format:", response.data); - // } + setTranscription(response.data.results[0].alternatives[0].transcript); } catch (error) { - console.error("Error transcribing audio:", error); - setError("Failed to transcribe audio. Please try again."); - } finally { - setLoading(false); + console.error('Error transcribing audio:', error); + setTranscription('Transcription failed.'); } }; @@ -89,14 +77,11 @@ const AudioTranscriber: React.FC = () => { }; mediaRecorderRef.current.onstop = async () => { - const audioBlob = new Blob(audioChunksRef.current, { type: "audio/mp3" }); - const audioFile = new File([audioBlob], "recording.mp3", { type: "audio/mp3" }); - console.log("Recording stopped. Blob created:", audioBlob); - setFile(audioFile); // Save the recorded file + setAudioBlob(new Blob(audioChunksRef.current, { type: "audio/mp3" })); setTranscription("Processing transcription for recorded audio..."); - await handleTranscription(audioFile); // Automatically transcribe + await handleTranscription(); // Automatically transcribe }; mediaRecorderRef.current.start(); @@ -129,7 +114,7 @@ const AudioTranscriber: React.FC = () => {

Upload or Record Audio

- diff --git a/src/app/(web)/transcribe/textsp.jsx b/src/app/(web)/transcribe/textsp.jsx new file mode 100644 index 0000000..7848084 --- /dev/null +++ b/src/app/(web)/transcribe/textsp.jsx @@ -0,0 +1,74 @@ +import React, { useState, useRef } from 'react'; +import axios from 'axios'; + +function SpeechToText() { + const [isRecording, setIsRecording] = useState(false); + const [audioBlob, setAudioBlob] = useState(null); + const [transcription, setTranscription] = useState(''); + const mediaRecorderRef = useRef(null); + + const startRecording = async () => { + try { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + mediaRecorderRef.current = new MediaRecorder(stream); + + mediaRecorderRef.current.ondataavailable = (event) => { + if (event.data && event.data.size > 0) { + setAudioBlob(new Blob([event.data], { type: 'audio/webm' })); + } + }; + + mediaRecorderRef.current.start(); + setIsRecording(true); + } catch (error) { + console.error('Error accessing microphone:', error); + } + }; + + const stopRecording = () => { + mediaRecorderRef.current.stop(); + setIsRecording(false); + }; + + const handleTranscription = async () => { + if (!audioBlob) { + alert('No audio recorded.'); + return; + } + + const formData = new FormData(); + formData.append('audio', audioBlob, 'audio.webm'); + + try { + const response = await axios.post( + 'https://speech.googleapis.com', // Replace with your actual endpoint + formData, + { + headers: { + 'Authorization': `Bearer ${process.env.REACT_APP_GOOGLE_CLOUD_API_KEY}`, // Replace with your API key + 'Content-Type': 'multipart/form-data', + }, + } + ); + + setTranscription(response.data.results[0].alternatives[0].transcript); + } catch (error) { + console.error('Error transcribing audio:', error); + setTranscription('Transcription failed.'); + } + }; + + return ( +
+ + +

Transcription: {transcription}

+
+ ); +} + +export default SpeechToText; \ No newline at end of file diff --git a/src/app/api/transcribe/route.js b/src/app/api/transcribe/route.js index 7679e97..878b08d 100644 --- a/src/app/api/transcribe/route.js +++ b/src/app/api/transcribe/route.js @@ -11,103 +11,103 @@ config(); const OPENAI_API_KEY = process.env.OPENAI_API_KEY; if (!OPENAI_API_KEY) { - throw new Error("OpenAI API key is missing. Set OPENAI_API_KEY in your .env.local file."); + throw new Error("OpenAI API key is missing. Set OPENAI_API_KEY in your .env.local file."); } // Initialize OpenAI client const openaiClient = new OpenAI({ - apiKey: OPENAI_API_KEY, + apiKey: OPENAI_API_KEY, }); // Helper to parse multipart form data async function parseMultipartForm(req) { - const form = formidable({ - multiples: false, - uploadDir: "/tmp", - keepExtensions: true, - maxFileSize: 50 * 1024 * 1024, - }); + const form = formidable({ + multiples: false, + uploadDir: "/tmp", + keepExtensions: true, + maxFileSize: 50 * 1024 * 1024, + }); - return new Promise((resolve, reject) => { - form.parse(req, (err, fields, files) => { - if (err) { - return reject(err); - } - const file = files.file[0]; - resolve({ - filePath: file.filepath, - originalFilename: file.originalFilename || 'unknown', - }); - }); - }); + return new Promise((resolve, reject) => { + form.parse(req, (err, fields, files) => { + if (err) { + return reject(err); + } + const file = files.file[0]; + resolve({ + filePath: file.filepath, + originalFilename: file.originalFilename || 'unknown', + }); + }); + }); } // Main handler export async function POST(req, res) { - if (req.method !== "POST") { - return res.status(405).json({ error: "Method not allowed. Use POST." }); - } + if (req.method !== "POST") { + return res.status(405).json({ error: "Method not allowed. Use POST." }); + } - let filePath = null; + let filePath = null; - try { - // Parse file upload - const { filePath: tempFilePath, originalFilename } = await parseMultipartForm(req); - filePath = tempFilePath; + try { + // Parse file upload + const { filePath: tempFilePath, originalFilename } = await parseMultipartForm(req); + filePath = tempFilePath; - // Log file details - console.log("Uploaded file path:", filePath); - console.log("Original filename:", originalFilename); + // Log file details + console.log("Uploaded file path:", filePath); + console.log("Original filename:", originalFilename); - // Validate file extension - const allowedExtensions = ["mp3", "wav", "m4a"]; - const fileExtension = path.extname(originalFilename).toLowerCase().replace(".", ""); - if (!allowedExtensions.includes(fileExtension)) { - unlinkSync(filePath); - return res.status(400).json({ - error: `Invalid file format. Only ${allowedExtensions.join(", ")} are supported.`, - }); - } + // Validate file extension + const allowedExtensions = ["mp3", "wav", "m4a"]; + const fileExtension = path.extname(originalFilename).toLowerCase().replace(".", ""); + if (!allowedExtensions.includes(fileExtension)) { + unlinkSync(filePath); + return res.status(400).json({ + error: `Invalid file format. Only ${allowedExtensions.join(", ")} are supported.`, + }); + } - // Get transcription from OpenAI Whisper model - console.log("Requesting transcription..."); - const transcription = await openaiClient.audio.transcriptions.create({ - file: fs.createReadStream(filePath), // Pass the file stream here - model: "whisper-1", - response_format: "text", // Ensure this is set - }); + // Get transcription from OpenAI Whisper model + console.log("Requesting transcription..."); + const transcription = await openaiClient.audio.transcriptions.create({ + file: fs.createReadStream(filePath), // Pass the file stream here + model: "whisper-1", + response_format: "text", // Ensure this is set + }); - console.log("Transcription:", transcription); // Log the transcription response + console.log("Transcription:", transcription); // Log the transcription response - // Clean up temporary file - if (filePath && existsSync(filePath)) { - unlinkSync(filePath); - } + // Clean up temporary file + if (filePath && existsSync(filePath)) { + unlinkSync(filePath); + } - // Send response back to client - return res.status(200).json({ transcription: transcription.text }); - } catch (error) { - console.error("Error during transcription:", error); + // Send response back to client + return res.status(200).json({ transcription: transcription.text }); + } catch (error) { + console.error("Error during transcription:", error); - if (error instanceof AxiosError) { - console.error("OpenAI API error:", error.response?.data || error.message); - return res.status(error.response?.status || 500).json({ - error: error.response?.data?.error?.message || "OpenAI API Error.", - }); - } + if (error instanceof AxiosError) { + console.error("OpenAI API error:", error.response?.data || error.message); + return res.status(error.response?.status || 500).json({ + error: error.response?.data?.error?.message || "OpenAI API Error.", + }); + } - return res.status(500).json({ - error: "An unexpected error occurred.", - }); - } finally { - if (filePath) { - try { - if (existsSync(filePath)) { - unlinkSync(filePath); - } - } catch (err) { - console.error("Failed to clean up temporary file:", err); - } - } - } + return res.status(500).json({ + error: "An unexpected error occurred.", + }); + } finally { + if (filePath) { + try { + if (existsSync(filePath)) { + unlinkSync(filePath); + } + } catch (err) { + console.error("Failed to clean up temporary file:", err); + } + } + } } diff --git a/tsconfig.json b/tsconfig.json index 64f11d2..ea8727b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,6 @@ "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/app/api/connectDB.js", "src/lib/utils.js", "src/app/(web)/account/page.jsx", "src/app/(panels)/suite/patient/account/page.jsx", "src/app/(panels)/suite/patient/dashboard/MedicationTable.jsx", "src/app/(panels)/suite/patient/dashboard/page.jsx", "src/app/api/transcribe/route.js", "src/components/ui/calendar.jsx", "src/app/(web)/page.jsx", "src/app/(web)/transcribe/page.jsx", "src/app/(web)/login/page.jsx", "src/app/(panels)/suite/layout.jsx", "src/app/(panels)/suite/doctor/dashboard/page.jsx", "src/app/(panels)/suite/patient/chat/page.jsx", "src/app/(panels)/suite/doctor/dashboard/AppList.jsx", "src/app/(panels)/suite/doctor/patients/page.jsx", "src/app/(panels)/suite/doctor/dashboard/AgeChart.jsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/app/api/connectDB.js", "src/lib/utils.js", "src/app/(web)/account/page.jsx", "src/app/(panels)/suite/patient/account/page.jsx", "src/app/(panels)/suite/patient/dashboard/MedicationTable.jsx", "src/app/(panels)/suite/patient/dashboard/page.jsx", "src/app/api/transcribe/route.js", "src/components/ui/calendar.jsx", "src/app/(web)/page.jsx", "src/app/(web)/transcribe/textsp.jsx", "src/app/(web)/login/page.jsx", "src/app/(panels)/suite/layout.jsx", "src/app/(panels)/suite/doctor/dashboard/page.jsx", "src/app/(panels)/suite/patient/chat/page.jsx", "src/app/(panels)/suite/doctor/dashboard/AppList.jsx", "src/app/(panels)/suite/doctor/patients/page.jsx", "src/app/(panels)/suite/doctor/dashboard/AgeChart.jsx", "src/app/(web)/transcribe/textsp.jsx", "src/app/(web)/transcribe/page.jsx"], "exclude": ["node_modules"] }