feat: implement Whisper transcription engine and project documentation
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const https = require('https')
|
||||
const AdmZip = require('adm-zip')
|
||||
|
||||
const binDir = path.join(__dirname, '../bin')
|
||||
const modelsDir = path.join(binDir, 'models')
|
||||
|
||||
if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true })
|
||||
if (!fs.existsSync(modelsDir)) fs.mkdirSync(modelsDir, { recursive: true })
|
||||
|
||||
const downloadFile = (url, dest) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Check if we need to follow redirects
|
||||
const req = https.get(url, (res) => {
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
return downloadFile(res.headers.location, dest).then(resolve).catch(reject)
|
||||
}
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
return reject(new Error(`Failed to download: ${res.statusCode} ${res.statusMessage}`))
|
||||
}
|
||||
|
||||
const file = fs.createWriteStream(dest)
|
||||
res.pipe(file)
|
||||
file.on('finish', () => {
|
||||
file.close(resolve)
|
||||
})
|
||||
})
|
||||
|
||||
req.on('error', (err) => {
|
||||
fs.unlink(dest, () => reject(err))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
try {
|
||||
console.log('Downloading Const-me Whisper (v1.12)...')
|
||||
const whisperZipPath = path.join(binDir, 'cli.zip')
|
||||
await downloadFile('https://github.com/Const-me/Whisper/releases/download/1.12.0/cli.zip', whisperZipPath)
|
||||
|
||||
console.log('Extracting Whisper...')
|
||||
const zip = new AdmZip(whisperZipPath)
|
||||
zip.extractAllTo(path.join(binDir, 'whisper_temp'), true)
|
||||
|
||||
// Find executable and dlls
|
||||
const extractPath = path.join(binDir, 'whisper_temp')
|
||||
const files = fs.readdirSync(extractPath)
|
||||
|
||||
// In Const-me Whisper release, there's usually a cli.exe or main.exe
|
||||
let exeFound = false
|
||||
files.forEach(file => {
|
||||
if (file.endsWith('.exe')) {
|
||||
// We'll rename the primary exe to whisper.exe
|
||||
if (!exeFound) {
|
||||
fs.copyFileSync(path.join(extractPath, file), path.join(binDir, 'whisper.exe'))
|
||||
exeFound = true
|
||||
}
|
||||
} else if (file.endsWith('.dll')) {
|
||||
fs.copyFileSync(path.join(extractPath, file), path.join(binDir, file))
|
||||
}
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
fs.rmSync(extractPath, { recursive: true, force: true })
|
||||
fs.unlinkSync(whisperZipPath)
|
||||
|
||||
console.log('Downloading Base Model (140MB)...')
|
||||
const modelPath = path.join(modelsDir, 'ggml-base.bin')
|
||||
if (!fs.existsSync(modelPath)) {
|
||||
await downloadFile('https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin', modelPath)
|
||||
}
|
||||
|
||||
console.log('Setup Complete!')
|
||||
} catch (error) {
|
||||
console.error('Setup failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
setup()
|
||||
@@ -0,0 +1,49 @@
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
$binDir = "bin"
|
||||
$modelsDir = "bin/models"
|
||||
|
||||
# Cleanup existing lock files if any
|
||||
if (Test-Path "$binDir/ffmpeg.zip") { Remove-Item "$binDir/ffmpeg.zip" -Force }
|
||||
if (Test-Path "$binDir/whisper.zip") { Remove-Item "$binDir/whisper.zip" -Force }
|
||||
|
||||
if (-not (Test-Path $binDir)) { New-Item -ItemType Directory -Path $binDir }
|
||||
if (-not (Test-Path $modelsDir)) { New-Item -ItemType Directory -Path $modelsDir }
|
||||
|
||||
Write-Host "Downloading FFmpeg..." -ForegroundColor Cyan
|
||||
$ffmpegZip = "$binDir/ffmpeg_dl.zip"
|
||||
Invoke-WebRequest -Uri "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" -OutFile $ffmpegZip
|
||||
|
||||
Write-Host "Downloading Const-me Whisper (v1.12)..." -ForegroundColor Cyan
|
||||
$whisperZip = "$binDir/whisper_dl.zip"
|
||||
# User provided link: https://github.com/Const-me/Whisper/releases/tag/1.12.0
|
||||
# Direct download link for Whisper.zip
|
||||
Invoke-WebRequest -Uri "https://github.com/Const-me/Whisper/releases/download/1.12.0/Library.zip" -OutFile $whisperZip
|
||||
|
||||
Write-Host "Downloading Base Model (140MB)..." -ForegroundColor Cyan
|
||||
$modelFile = "$modelsDir/ggml-base.bin"
|
||||
if (-not (Test-Path $modelFile)) {
|
||||
Invoke-WebRequest -Uri "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin" -OutFile $modelFile
|
||||
}
|
||||
|
||||
Write-Host "Extracting FFmpeg..." -ForegroundColor Green
|
||||
Expand-Archive -Path $ffmpegZip -DestinationPath "$binDir/ffmpeg_temp" -Force
|
||||
$ffmpegExe = Get-ChildItem -Path "$binDir/ffmpeg_temp" -Filter "ffmpeg.exe" -Recurse | Select-Object -First 1
|
||||
Copy-Item $ffmpegExe.FullName -Destination "$binDir/ffmpeg.exe"
|
||||
Remove-Item -Path "$binDir/ffmpeg_temp" -Recurse -Force
|
||||
Remove-Item $ffmpegZip
|
||||
|
||||
Write-Host "Extracting Whisper..." -ForegroundColor Green
|
||||
Expand-Archive -Path $whisperZip -DestinationPath "$binDir/whisper_temp" -Force
|
||||
# Const-me zip might have WhisperDesktop.exe and Whisper.dll
|
||||
# We look for any exe that looks like a CLI or the main app
|
||||
$whisperExe = Get-ChildItem -Path "$binDir/whisper_temp" -Filter "*.exe" -Recurse | Select-Object -First 1
|
||||
Copy-Item $whisperExe.FullName -Destination "$binDir/whisper.exe"
|
||||
# Also copy DLLs if any
|
||||
Get-ChildItem -Path "$binDir/whisper_temp" -Filter "*.dll" -Recurse | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination "$binDir/$($_.Name)"
|
||||
}
|
||||
Remove-Item -Path "$binDir/whisper_temp" -Recurse -Force
|
||||
Remove-Item $whisperZip
|
||||
|
||||
Write-Host "Setup Complete!" -ForegroundColor Yellow
|
||||
Reference in New Issue
Block a user