มาสร้างเว็บแอปที่ถอดเสียงและแปลเสียงโดยใช้ 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 ฉันหวังว่าคุณจะสนุกกับการสร้างมันและเรียนรู้สิ่งใหม่จากบทความนี้ จากนั้นคุณยังสามารถเปลี่ยนพารามิเตอร์เพื่อทดลองดูและเปรียบเทียบผลลัพธ์เพื่อให้เข้าใจได้ดีขึ้นว่าอะไรทำงานได้ดีในสถานการณ์ใด

ขอบคุณสำหรับการอ่านบทความ บทความอื่นๆ ที่คุณต้องอ่านหลังจากบทความนี้ได้แก่: