diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adeee01..3f89770 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,8 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.head_ref }} token: ${{ secrets.GITHUB_TOKEN }} - + - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -32,9 +31,21 @@ jobs: - name: Format code run: npm run format - + + # For pushes to main or PRs from same repo, commit formatting changes - name: Commit changes + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "style: format code with prettier" - branch: ${{ github.head_ref }} \ No newline at end of file + branch: ${{ github.event_name == 'push' && 'main' || github.head_ref }} + + # For PRs from forks, fail the check if there are formatting changes required + - name: Check for uncommitted changes + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + run: | + if [[ -n "$(git status --porcelain)" ]]; then + echo "::error::Code formatting issues found. Please run 'npm run format' locally and commit the changes." + git diff + exit 1 + fi diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000..439495c --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,31 @@ +name: Integration test + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test diff --git a/example/index.ts b/example/index.ts index d06280e..532ba04 100644 --- a/example/index.ts +++ b/example/index.ts @@ -10,8 +10,8 @@ const filePath = path.resolve(__dirname, AUDIO_FILE) async function convert() { try { await nodewhisper(filePath, { - modelName: 'base.en', - autoDownloadModelName: 'base.en', + modelName: 'tiny.en', + autoDownloadModelName: 'tiny.en', whisperOptions: { outputInVtt: true, // Default is 20 which is too long @@ -20,6 +20,7 @@ async function convert() { }) } catch (exc) { console.error(exc) + process.exit(1) } } diff --git a/src/WhisperHelper.ts b/src/WhisperHelper.ts index 066b5db..39cdee3 100644 --- a/src/WhisperHelper.ts +++ b/src/WhisperHelper.ts @@ -1,7 +1,7 @@ import path from 'path' import fs from 'fs' -import { MODELS, MODELS_LIST, MODEL_OBJECT } from './constants' +import { MODELS_LIST, MODEL_OBJECT, WHISPER_CPP_PATH, WHISPER_CPP_MAIN_PATH } from './constants' import { IOptions } from '.' export const constructCommand = (filePath: string, args: IOptions): string => { @@ -15,7 +15,7 @@ export const constructCommand = (filePath: string, args: IOptions): string => { errors.push(`[Nodejs-whisper] Error: Enter a valid model name. Available models are: ${MODELS_LIST.join(', ')}`) } - const modelPath = path.join(__dirname, '..', 'cpp', 'whisper.cpp', 'models', MODEL_OBJECT[args.modelName]) + const modelPath = path.join(WHISPER_CPP_PATH, 'models', MODEL_OBJECT[args.modelName]) if (!fs.existsSync(modelPath)) { errors.push( '[Nodejs-whisper] Error: Model file does not exist. Please ensure the model is downloaded and correctly placed.' @@ -27,7 +27,7 @@ export const constructCommand = (filePath: string, args: IOptions): string => { } const modelName = MODEL_OBJECT[args.modelName as keyof typeof MODEL_OBJECT] - let command = `./main ${constructOptionsFlags(args)} -l ${args.whisperOptions?.language ? args.whisperOptions?.language : 'auto'} -m "./models/${modelName}" -f "${filePath}"` + let command = `${WHISPER_CPP_MAIN_PATH} ${constructOptionsFlags(args)} -l ${args.whisperOptions?.language ? args.whisperOptions?.language : 'auto'} -m "./models/${modelName}" -f "${filePath}"` return command } diff --git a/src/autoDownloadModel.ts b/src/autoDownloadModel.ts index feadaaf..ba05c9e 100644 --- a/src/autoDownloadModel.ts +++ b/src/autoDownloadModel.ts @@ -1,7 +1,7 @@ import path from 'path' import shell from 'shelljs' import fs from 'fs' -import { MODELS_LIST, MODELS } from './constants' +import { MODEL_OBJECT, MODELS_LIST, WHISPER_CPP_PATH } from './constants' export default async function autoDownloadModel( logger = console, @@ -19,9 +19,9 @@ export default async function autoDownloadModel( } try { - const modelDirectory = path.join(__dirname, '..', 'cpp', 'whisper.cpp', 'models') + const modelDirectory = path.join(WHISPER_CPP_PATH, 'models') shell.cd(modelDirectory) - const modelAlreadyExist = fs.existsSync(path.join(modelDirectory, autoDownloadModelName)) + const modelAlreadyExist = fs.existsSync(path.join(modelDirectory, MODEL_OBJECT[autoDownloadModelName])) if (modelAlreadyExist) { logger.debug(`[Nodejs-whisper] ${autoDownloadModel} already exist. Skipping download.`) diff --git a/src/constants.ts b/src/constants.ts index 716a8fc..b4dee17 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,5 @@ +import path from 'path' + export const MODELS_LIST = [ 'tiny', 'tiny.en', @@ -41,3 +43,8 @@ export const MODEL_OBJECT = { } export const DEFAULT_MODEL = 'tiny.en' + +export const WHISPER_CPP_PATH = path.join(__dirname, '..', 'cpp', 'whisper.cpp') + +export const WHISPER_CPP_MAIN_PATH = + process.platform === 'win32' ? 'build\\bin\\Release\\whisper-cli.exe' : './build/bin/whisper-cli' diff --git a/src/downloadModel.ts b/src/downloadModel.ts index afdd3d9..03f51db 100644 --- a/src/downloadModel.ts +++ b/src/downloadModel.ts @@ -5,7 +5,7 @@ import path from 'path' import shell from 'shelljs' import readlineSync from 'readline-sync' -import { MODELS_LIST, DEFAULT_MODEL, MODELS } from './constants' +import { MODELS_LIST, DEFAULT_MODEL, MODELS, WHISPER_CPP_PATH, MODEL_OBJECT } from './constants' import fs from 'fs' const askForModel = async (logger = console): Promise => { @@ -48,12 +48,12 @@ const askIfUserWantToUseCuda = async (logger = console) => { async function downloadModel(logger = console) { try { - shell.cd(path.join(__dirname, '..', './cpp/whisper.cpp/models')) + shell.cd(path.join(WHISPER_CPP_PATH, 'models')) let anyModelExist = [] MODELS.forEach(model => { - if (!fs.existsSync(path.join(__dirname, '..', `./cpp/whisper.cpp/models/${model}`))) { + if (!fs.existsSync(path.join(WHISPER_CPP_PATH, 'models', MODEL_OBJECT[model]))) { } else { anyModelExist.push(model) } diff --git a/src/whisper.ts b/src/whisper.ts index b4486c7..1a37f61 100644 --- a/src/whisper.ts +++ b/src/whisper.ts @@ -1,10 +1,6 @@ -import fs from 'fs' -import path from 'path' import shell from 'shelljs' -import { MODELS } from './constants' +import { WHISPER_CPP_PATH, WHISPER_CPP_MAIN_PATH } from './constants' -const WHISPER_CPP_PATH = path.join(__dirname, '..', 'cpp', 'whisper.cpp') -const WHISPER_CPP_MAIN_PATH = './main' const projectDir = process.cwd() export interface IShellOptions { @@ -57,13 +53,13 @@ export async function whisperShell( export async function executeCppCommand(command: string, logger = console, withCuda: boolean): Promise { try { shell.cd(WHISPER_CPP_PATH) - if (!shell.which(WHISPER_CPP_MAIN_PATH)) { + if (!shell.which(WHISPER_CPP_MAIN_PATH.replace(/\\/g, '/'))) { logger.debug('[Nodejs-whisper] whisper.cpp not initialized.') const makeCommand = withCuda ? 'WHISPER_CUDA=1 make -j' : 'make -j' shell.exec(makeCommand) - if (!shell.which(WHISPER_CPP_MAIN_PATH)) { + if (!shell.which(WHISPER_CPP_MAIN_PATH.replace(/\\/g, '/'))) { throw new Error( "[Nodejs-whisper] 'make' command failed. Please run 'make' command in /whisper.cpp directory." )