มาสร้างเว็บแอปที่ถอดเสียงและแปลเสียงโดยใช้ Whisper Model ของ OpenAI กันดีกว่า
สวัสดีทุกคน! ฉันหวังว่าพวกคุณทุกคนจะสบายดี วันนี้ เราจะสร้างเว็บแอปคำพูดเป็นข้อความโดยใช้ Node.js และ API ของ OpenAI เราจะใช้ API ของ OpenAI เพื่อใช้ Whisper Model ซึ่งช่วยให้เราอัปโหลดไฟล์เสียงในรูปแบบ MP3 และจัดเตรียมการถอดเสียงให้กับเรา มันยังสามารถแปลเสียงในภาษาอื่นเป็นข้อความภาษาอังกฤษได้ซึ่งน่าทึ่งมาก
ก่อนอื่น เราจะตั้งค่าโปรเจ็กต์ Node.js ใหม่เพื่อที่เราจะได้เริ่มสร้างแอปพลิเคชันของเราได้ ดังนั้น เราจะสร้างโฟลเดอร์ที่เราต้องการสร้างโปรเจ็กต์ของเราและย้ายไปยังโฟลเดอร์นั้นโดยใช้บรรทัดคำสั่ง จากนั้นเราสามารถตั้งค่าโปรเจ็กต์ Node.js ใหม่โดยใช้คำสั่งต่อไปนี้:
npm init
หลังจากรันคำสั่งนี้แล้ว มันจะถามคำถามหลายข้อ เช่น ชื่อแอป จุดเข้าใช้งาน ฯลฯ ซึ่งเราสามารถคงไว้เป็นค่าเริ่มต้นได้ในตอนนี้ หลังจากนี้ คุณจะเห็นว่ามันสร้างไฟล์ package.json
ไฟล์นี้จะมีข้อมูลเกี่ยวกับแอปพลิเคชันของเราและแพ็คเกจที่เราได้ติดตั้งสำหรับแอปพลิเคชันนี้
ดังนั้น ขั้นตอนต่อไปคือการติดตั้งโมดูลโหนดที่จำเป็น เช่น แพ็คเกจ ลงในแอปพลิเคชันของเรา เพื่อที่เราจะได้พร้อมที่จะเริ่มสร้างแอปพลิเคชัน เราสามารถทำได้โดยใช้คำสั่งด้านล่าง:
npm install express multer openai cors --save
เราติดตั้งแพ็คเกจทั้งสี่นี้และใช้ --save
เพื่อเพิ่มแพ็คเกจเหล่านี้ลงในไฟล์ package.json
ช่วยให้ผู้ที่โคลนพื้นที่เก็บข้อมูลติดตั้งแพ็กเกจที่จำเป็นทั้งหมดได้ง่ายขึ้นโดยการรันคำสั่ง npm install
เพียงครั้งเดียว
นอกจากนี้เรายังต้องการใช้แพ็คเกจ nodemon ในแอปพลิเคชันของเราเพื่อช่วยเรารีเฟรชและโหลดเซิร์ฟเวอร์ใหม่โดยอัตโนมัติเมื่อตรวจพบการเปลี่ยนแปลงในโค้ด เพื่อที่เราจะได้ไม่ต้องรีสตาร์ทเซิร์ฟเวอร์ด้วยตนเองซ้ำแล้วซ้ำอีกหลังจากการเปลี่ยนแปลงแต่ละครั้ง ดังนั้น เราจะเพิ่มมันเป็นการพึ่งพาการพัฒนา เนื่องจากมันจะถูกใช้เพื่อช่วยในการพัฒนาเท่านั้น และเราจะไม่ใช้มันโดยตรงในโค้ด เราสามารถติดตั้งได้โดยใช้คำสั่งต่อไปนี้:
npm install --save-dev nodemon
ตอนนี้เรามีแพ็คเกจที่จำเป็นทั้งหมดเพื่อเริ่มงานพัฒนาของเรา ดังที่เราเห็นในไฟล์ package.json
จะมีโมดูลและแพ็คเกจทั้งหมดที่เราติดตั้ง พร้อมด้วยรายละเอียดเล็กน้อยเกี่ยวกับแอปพลิเคชัน ไฟล์ package.json
จะมีลักษณะดังนี้:
{ "name": "speechtext", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", "multer": "^1.4.5-lts.1", "openai": "^3.2.1" }, "devDependencies": { "nodemon": "^2.0.22" } }
อย่างที่เราเห็น index.js
เขียนอยู่ใน main
ซึ่งหมายความว่าไฟล์ index.js
เป็นจุดเริ่มต้นสำหรับแอปพลิเคชันของเรา หากคุณจำได้ ระบบจะถามในระหว่างขั้นตอนการตั้งค่าเมื่อเรารันคำสั่ง npm init
หากคุณจะปล่อยให้มันเป็นค่าเริ่มต้น คุณจะมีจุดเริ่มต้นเดียวกัน มิฉะนั้น คุณจะมีสิ่งที่คุณกำหนดไว้ในขณะนั้น
ตอนนี้เราจะสร้างไฟล์ใหม่ชื่อ index.js
คุณสามารถตั้งชื่อไฟล์ตามที่คุณต้องการตามจุดเริ่มต้นที่คุณกำหนด เรากำลังพิจารณา index.js
ในเรื่องเดียวกัน
ดัชนี js
ตอนนี้เราจะเริ่มสร้างไฟล์ index.js
เราจะเริ่มต้นด้วยการนำเข้าโมดูลที่จำเป็นลงในแอปพลิเคชันของเรา สำหรับไฟล์ดัชนี เราต้องการ express
และ cors
ดังนั้นเราจึงเริ่มต้นด้วยการกำหนดสองโมดูลนี้:
const express = require('express'); const cors = require('cors');
ต่อไป เราจะสร้างอินสแตนซ์ใหม่ของแอปพลิเคชัน express
นอกจากนี้ เราจะตั้งค่าแอปพลิเคชันของเราให้ใช้ cors จัดการข้อมูล json และทำให้โฟลเดอร์ public
มีไฟล์คงที่ ซึ่งจากนั้นจะสามารถเข้าถึงได้โดยฝั่งไคลเอ็นต์หรือส่วนหน้า
const app = express(); app.use(express.static('public')); app.use(express.json()); app.use(cors());
ต่อไป เราต้องการมีไฟล์แยกต่างหากที่เราจะกำหนด API เราจะสร้างโฟลเดอร์ชื่อ routes
และภายในนั้น เราจะมีไฟล์ชื่อ api.js
ซึ่งจะกำหนด GET และ POST API ที่จำเป็นในแอปพลิเคชัน เพื่อแจ้งให้แอปพลิเคชันทราบเกี่ยวกับเรื่องนี้ เราจะเพิ่มบรรทัดโค้ดนี้ที่เรากำหนด URL พื้นฐานและตำแหน่งของไฟล์ที่จะกำหนด API ทั้งหมด เป็นมิดเดิลแวร์ที่ช่วยเรากำหนดเส้นทางสำหรับแอปพลิเคชัน
app.use('/', require('./routes/api'));
ต่อไป เราใช้ฟังก์ชันมิดเดิลแวร์จัดการข้อผิดพลาดซึ่งจะใช้เพื่อจัดการกับข้อผิดพลาดใดๆ ที่เกิดขึ้นในแอปพลิเคชัน
app.use(function(err,req,res,next){ res.status(422).send({error: err.message}); });
สุดท้าย เราตั้งค่าแอปพลิเคชันให้ฟังคำขอขาเข้าบนหมายเลขพอร์ตที่ระบุ ซึ่งเราสามารถตั้งค่าได้โดยใช้ตัวแปรสภาพแวดล้อมหรือกำหนดง่ายๆ
app.listen(process.env.PORT || 4000, function(){ console.log('Ready to Go!'); });
เราใช้พอร์ต 4000 สำหรับแอปพลิเคชันของเรา นอกจากนี้เรายังมี console.log
แบบธรรมดาอยู่ข้างใน ซึ่งจะพิมพ์ข้อความที่บันทึกลงในคอนโซลเมื่อแอปพลิเคชันพร้อมที่จะรับคำขอ
ไฟล์ index.js
ที่สมบูรณ์:
const express = require('express'); const cors = require('cors'); const app = express(); app.use(express.static('public')); app.use(express.json()); app.use(cors()); app.use('/', require('./routes/api')); app.use(function(err,req,res,next){ res.status(422).send({error: err.message}); }); app.listen(process.env.PORT || 4000, function(){ console.log('Ready to Go!'); });
ต่อไป เราจะย้ายไปยังไฟล์ api.js
ซึ่งเราสร้างขึ้นภายในโฟลเดอร์ routes
api.js
ตอนนี้เราจะเริ่มสร้างไฟล์ api.js
เราจะเริ่มต้นสิ่งนี้ด้วยการนำเข้าโมดูลที่จำเป็นลงในไฟล์ เราจะนำเข้าไลบรารี express
, multer
และ openai
const express = require("express"); const multer = require("multer"); const { Configuration, OpenAIApi } = require("openai");
Multer เป็นมิดเดิลแวร์ที่เราใช้จัดการ multipart/form-data
เนื่องจากเราจะจัดการกับการอัปโหลดไฟล์เสียง
จาก openai
เราต้องการโมดูล Configuration
และ OpenAIApi
ที่เราจะใช้ในการโพสต์คำขอ API ไปยังโมเดล Whisper
จากนั้นเราจะตั้งค่าเราเตอร์ด่วนและสร้างอินสแตนซ์ของมิดเดิลแวร์หลายตัว
const router = express.Router(); const upload = multer();
ต่อไป เราจะกำหนดค่า OpenAI และสร้างอินสแตนซ์การกำหนดค่าใหม่ เราต้องการคีย์ลับ OpenAI ซึ่งเราต้องใส่ไว้ที่นี่เป็นคีย์ API คุณสามารถรับรหัสลับได้จาก "ที่นี่"
const configuration = new Configuration({ apiKey: process.env.OPENAI_KEY, });
ตอนนี้ เราสร้างฟังก์ชัน async ซึ่งยอมรับบัฟเฟอร์ที่มีข้อมูลเพลง และส่งคืนการตอบสนองที่ได้รับจากโมเดล Whisper ของ OpenAI เมื่อเราเรียกใช้ API
async function transcribe(buffer) { const openai = new OpenAIApi(configuration); const response = await openai.createTranscription( buffer, // The audio file to transcribe. "whisper-1", // The model to use for transcription. undefined, // The prompt to use for transcription. 'json', // The format of the transcription. 1, // Temperature 'en' // Language ) return response; }
ดังที่คุณเห็นข้างต้น ก่อนอื่นเราจะสร้างอินสแตนซ์ใหม่ของคลาส OpenAI โดยใช้การกำหนดค่าที่เรากำหนดไว้ก่อนหน้าในโค้ดของเรา จากนั้นเราจะเรียกใช้ฟังก์ชัน createTranscription
ของ OpenAI และเราใช้คีย์เวิร์ด await
เพื่อรอการตอบกลับก่อนจึงจะดำเนินการต่อ
เราส่งพารามิเตอร์ที่จำเป็นในฟังก์ชัน ซึ่งประกอบด้วยบัฟเฟอร์ซึ่งมีข้อมูลเพลง และโมเดลที่จะใช้สำหรับการถอดเสียง ซึ่งก็คือ whisper-1
ในกรณีของเรา จากนั้นเราจะปล่อยให้พรอมต์ไม่ได้กำหนดไว้ คุณสามารถให้ข้อความแจ้งได้เช่นกัน หากต้องการ ซึ่งจะช่วยให้โมเดลสามารถถอดเสียงได้ดียิ่งขึ้นโดยมีสไตล์ที่คล้ายกับข้อความแจ้งที่คุณให้ไว้ เรากำหนดประเภทข้อมูลที่เราได้รับเป็น json
ตั้งอุณหภูมิเป็น 1 และกำหนดภาษาที่เราต้องการส่งออก
ต่อไปเราจะกำหนดคำขอ GET เราใช้ sendFile
เพื่อส่งไฟล์ HTML ซึ่งมีแบบฟอร์มของเราซึ่งผู้ใช้สามารถอัปโหลดไฟล์เสียงได้ เราจะสร้างไฟล์ HTML ในภายหลัง เรากำลังให้บริการบน URL ฐาน
router.get("/", (req, res) => { res.sendFile(path.join(__dirname, "../public", "index.html")); });
ต่อไป เราจะกำหนดคำขอ POST ซึ่งจะจัดการการอัปโหลดไฟล์เสียง เราใช้มิดเดิลแวร์หลายตัวเพื่อจัดการส่วนที่อัพโหลดไฟล์ จากนั้นเราสร้างบัฟเฟอร์จากไฟล์เสียง ซึ่งจะมีข้อมูลของไฟล์เสียงในรูปแบบที่สามารถส่งไปยัง OpenAI API ได้ จากนั้นเราตั้งชื่อให้กับบัฟเฟอร์โดยใช้ชื่อดั้งเดิมของไฟล์เสียงที่อัพโหลด
จากนั้นเราจะเรียกใช้ฟังก์ชัน transcribe
และเมื่อได้รับการตอบกลับ เราจะส่ง JSON กลับไปยังไคลเอ็นต์ เราส่งการถอดเสียงและชื่อไฟล์เสียงกลับไปที่ส่วนหน้า เรายังมีวิธีตรวจจับเพื่อจัดการกับข้อผิดพลาดอีกด้วย
router.post("/", upload.any('file'), (req, res) => { audio_file = req.files[0]; buffer = audio_file.buffer; buffer.name = audio_file.originalname; const response = transcribe(buffer); response.then((data) => { res.send({ type: "POST", transcription: data.data.text, audioFileName: buffer.name }); }).catch((err) => { res.send({ type: "POST", message: err }); }); });
สุดท้าย เราส่งออกโมดูล router
ซึ่งจะอนุญาตให้ไฟล์อื่นๆ นำเข้าได้
module.exports = router;
ดังนั้น รหัสที่สมบูรณ์สำหรับไฟล์ api.js
:
const express = require("express"); const multer = require("multer"); const { Configuration, OpenAIApi } = require("openai"); const router = express.Router(); const upload = multer(); const configuration = new Configuration({ apiKey: process.env.OPENAI_KEY, }); async function transcribe(buffer) { const openai = new OpenAIApi(configuration); const response = await openai.createTranscription( buffer, // The audio file to transcribe. "whisper-1", // The model to use for transcription. undefined, // The prompt to use for transcription. 'json', // The format of the transcription. 1, // Temperature 'en' // Language ) return response; } router.get("/", (req, res) => { res.sendFile(path.join(__dirname, "../public", "index.html")); }); router.post("/", upload.any('file'), (req, res) => { audio_file = req.files[0]; buffer = audio_file.buffer; buffer.name = audio_file.originalname; const response = transcribe(buffer); response.then((data) => { res.send({ type: "POST", transcription: data.data.text, audioFileName: buffer.name }); }).catch((err) => { res.send({ type: "POST", message: err }); }); }); module.exports = router;
ตอนนี้เราได้ทำส่วนแบ็กเอนด์ทั้งหมดเสร็จแล้ว ตอนนี้เราจะเขียนไฟล์ HTML และเขียนโค้ดจาวาสคริปต์ส่วนหน้าเพื่อจัดการการส่งแบบฟอร์มและการบันทึกข้อมูลใน "ที่จัดเก็บในตัวเครื่อง" และการดึงข้อมูลจากที่จัดเก็บในตัวเครื่อง
เราสร้างโฟลเดอร์ public
ซึ่งภายในเราจะสร้างไฟล์ HTML สองไฟล์ — index.html
และ transcribe.html
เราจะเริ่มต้นด้วยไฟล์ index.html
:
ดัชนี.html
ดังนั้นในไฟล์นี้ เราจะสร้างเพจที่เราแสดงแบบฟอร์มเพื่ออัปโหลดไฟล์เสียง เราจะใช้ Bootstrap CSS เพื่อนำเข้าผ่าน CDN นอกจากนี้เรายังรวม Bootstrap JS ผ่าน CDN ไว้ที่ส่วนท้ายของไฟล์ HTML
จากนั้นเราจะสร้างการ์ดง่ายๆ ที่ฉันขอให้ผู้ใช้อัปโหลดไฟล์เสียง ฉันแน่ใจว่าไฟล์ที่ส่งอยู่ในรูปแบบ .mp3
เนื่องจากเป็นรูปแบบเดียวที่ API ของ OpenAI ยอมรับ เราแสดงปุ่มซึ่งเมื่อคลิกแล้วจะส่งแบบฟอร์ม
จากนั้นเราก็มีโค้ดจาวาสคริปต์ซึ่งเราใช้ในการจัดการการส่งแบบฟอร์ม ดังนั้น ในตอนแรก เราหยุดไม่ให้รีเฟรชเพจโดยป้องกันพฤติกรรมเริ่มต้นของเหตุการณ์การส่งแบบฟอร์ม จากนั้นเราจะรับข้อมูลในแบบฟอร์ม เช่น ไฟล์เสียง และส่งเป็นคำขอ POST ไปยังแบ็กเอนด์ จากนั้นเรารอการตอบสนองและเก็บไว้ในตัวแปรข้อมูล
หากข้อมูลมีการถอดเสียง เราจะจัดเก็บการถอดเสียงและชื่อไฟล์เสียงไว้ใน Local Storage เพื่อให้เราสามารถเข้าถึงได้ในหน้าถัดไปที่เราจำเป็นต้องแสดงการถอดเสียง มีหลายวิธีในการส่งข้อมูลเหมือนกับที่เราสามารถส่งข้อมูลผ่าน URI ได้ แต่ที่นี่ เราใช้ Local Storage เพื่อดำเนินการดังกล่าว
หลังจากบันทึกข้อมูลลงในที่จัดเก็บในตัวเครื่องแล้ว เราจะเปลี่ยนตำแหน่งหน้าต่างเพื่อโหลดไฟล์ transcribe.html
<!DOCTYPE html> <html> <head> <title>Speech to Text</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous"> </head> <body style="background-color: #f2f2f2;"> <div class="container mt-5"> <div class="row justify-content-center"> <div class="col-md-6"> <div class="card"> <div class="card-header"> Upload Audio File </div> <div class="card-body"> <form id="transcription-form" enctype="multipart/form-data"> <div class="form-group"> <label for="file-upload"><b>Select file:</b></label> <input id="file-upload" type="file" name="file" class="form-control-file" accept=".mp3" style="margin-bottom: 20px"> </div> <input type="submit" value="Transcribe" class="btn btn-primary"></input> </form> </div> </div> </div> </div> </div> <script> document.getElementById("transcription-form").addEventListener("submit", async function (event) { event.preventDefault(); const formData = new FormData(event.target); const response = await fetch("/", { method: "POST", body: formData, }); const data = await response.json(); if (data.transcription) { localStorage.setItem("transcription", data.transcription); localStorage.setItem("audioFileName", data.audioFileName); window.location.href = "/transcribe.html"; } else { console.error("Error:", data.message); } }); </script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script> </body> </html>
ดังนั้นโค้ดด้านบนจะสร้างไฟล์ index.html
ซึ่งจะแสดงแบบฟอร์มให้กับผู้ใช้ซึ่งผู้ใช้สามารถอัปโหลดไฟล์เสียงได้
นี่คือภาพหน้าจอหนึ่งที่แสดงให้เห็นว่ามีลักษณะอย่างไร:
ต่อไปเราจะสร้างไฟล์ transcribe.html
ถอดเสียง.html
ดังนั้นในไฟล์นี้ เราจะแสดงสำเนาของไฟล์เสียงที่ผู้ใช้อัปโหลด ดังนั้นเราจะใช้ Bootstrap CSS และ JS อีกครั้งเพื่อรวมสิ่งเหล่านั้นผ่าน CDN
จากนั้นเราจะกำหนด CSS ที่กำหนดเองเพื่อจัดสไตล์องค์ประกอบเพื่อให้ดูดีขึ้น จากนั้นเราจะแสดงชื่อไฟล์เสียงและการถอดเสียงของไฟล์เสียงนั้นในคอนเทนเนอร์
ในโค้ดจาวาสคริปต์ที่ด้านล่างของหน้านี้ เราได้รับชื่อไฟล์เสียงและการถอดเสียงจากที่จัดเก็บในตัวเครื่อง และส่งข้อมูลนั้นไปยังองค์ประกอบ HTML ที่เกี่ยวข้องโดยใช้รหัส
<!DOCTYPE html> <html> <head> <title>Transcription</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous"> <style> h1 { margin-top: 20px; margin-bottom: 10px; font-size: 2.5rem; font-weight: bold; color: #333; } p { font-size: 1.2rem; color: #333; margin-bottom: 30px; } .container { margin-top: 50px; margin-bottom: 50px; max-width: 600px; padding: 30px; background-color: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.2); border-radius: 5px; } </style> </head> <body style="background-color: #f2f2f2;"> <div class="container"> <h1>Audio File:</h1> <p id="audioFileName"></p> <h1>Transcription:</h1> <p id="transcription"></p> </div> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script> <script> const audioFileName = localStorage.getItem("audioFileName"); const transcription = localStorage.getItem("transcription"); document.getElementById("audioFileName").innerHTML = audioFileName; document.getElementById("transcription").innerHTML = transcription; </script> </body> </html>
ฉันได้ลองถอดเสียงไฟล์เสียงขนาดเล็กสองไฟล์ที่ฉันบันทึกไว้เป็นการส่วนตัว ไฟล์หนึ่งเป็นภาษาอังกฤษและอีกไฟล์เป็นภาษาฮินดี แม้ว่าไฟล์เสียงที่สองจะถูกบันทึกเป็นภาษาฮินดี แต่ฉันก็อยากเห็นผลลัพธ์เป็นภาษาอังกฤษ ดังนั้นจึงต้องทดสอบความสามารถในการแปลด้วย มีความแม่นยำสูงในการถอดเสียงไฟล์เสียงทั้งสองไฟล์ แม้ว่าในการรันหลายครั้ง บางครั้งจะมีการถอดเสียงที่คลุมเครือซึ่งไม่ถูกต้อง แต่หลายครั้ง การถอดเสียงส่วนใหญ่ถูกต้อง
ฉันกำลังแนบภาพหน้าจอการถอดเสียงด้านล่าง สิ่งเหล่านั้นไม่ถูกต้องทั้งหมด แต่ฉันจะบอกว่ามันถูกต้องประมาณ 85–90% ในการถอดเสียงสิ่งที่ฉันบันทึกไว้จริงในไฟล์เสียง
ดังนั้นเราจึงสร้างเว็บแอปคำพูดเป็นข้อความได้สำเร็จโดยใช้ API ของ OpenAI และ Node.js ฉันหวังว่าคุณจะสนุกกับการสร้างมันและเรียนรู้สิ่งใหม่จากบทความนี้ จากนั้นคุณยังสามารถเปลี่ยนพารามิเตอร์เพื่อทดลองดูและเปรียบเทียบผลลัพธ์เพื่อให้เข้าใจได้ดีขึ้นว่าอะไรทำงานได้ดีในสถานการณ์ใด
ขอบคุณสำหรับการอ่านบทความ บทความอื่นๆ ที่คุณต้องอ่านหลังจากบทความนี้ได้แก่: