diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dac0e4..6dffe17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,81 +1,69 @@ name: CI on: - pull_request_target: + push: branches: - master -permissions: - pull-requests: write + pull_request: + branches: + - master + + merge_group: {} jobs: - job1: - name: Check Not Allowed File Changes + lint: runs-on: ubuntu-latest - outputs: - markdown_change: ${{ steps.filter_markdown.outputs.change }} - markdown_files: ${{ steps.filter_markdown.outputs.change_files }} steps: + - uses: actions/checkout@v3 - - name: Check Not Allowed File Changes - uses: dorny/paths-filter@v2 - id: filter_not_allowed - with: - list-files: json - filters: | - change: - - 'package-lock.json' - - 'yarn.lock' - - 'pnpm-lock.yaml' - - # ref: https://github.com/github/docs/blob/main/.github/workflows/triage-unallowed-contributions.yml - - name: Comment About Changes We Can't Accept - if: ${{ steps.filter_not_allowed.outputs.change == 'true' }} - uses: actions/github-script@v6 - with: - script: | - let workflowFailMessage = "It looks like you've modified some files that we can't accept as contributions." - try { - const badFilesArr = [ - 'package-lock.json', - 'yarn.lock', - 'pnpm-lock.yaml', - ] - const badFiles = badFilesArr.join('\n- ') - const reviewMessage = `👋 Hey there spelunker. It looks like you've modified some files that we can't accept as contributions. The complete list of files we can't accept are:\n- ${badFiles}\n\nYou'll need to revert all of the files you changed in that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit) or \`git checkout origin/main \`. Once you get those files reverted, we can continue with the review process. :octocat:\n\nMore discussion:\n- https://github.com/electron-vite/electron-vite-vue/issues/192` - createdComment = await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.number, - body: reviewMessage, - }) - workflowFailMessage = `${workflowFailMessage} Please see ${createdComment.data.html_url} for details.` - } catch(err) { - console.log("Error creating comment.", err) - } - core.setFailed(workflowFailMessage) - - - name: Check Not Linted Markdown - if: ${{ always() }} - uses: dorny/paths-filter@v2 - id: filter_markdown + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - name: Set node + uses: actions/setup-node@v3 with: - list-files: shell - filters: | - change: - - added|modified: '*.md' + node-version: 18 + cache: pnpm + - name: Install + run: pnpm i + + - name: Lint + run: pnpm run lint + + test: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + include: + - os: macos-latest + node_version: 18 + - os: windows-latest + node_version: 18 - job2: - name: Lint Markdown - runs-on: ubuntu-latest - needs: job1 - if: ${{ always() && needs.job1.outputs.markdown_change == 'true' }} steps: - - name: Checkout Code - uses: actions/checkout@v3 + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - uses: actions/checkout@v3 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - name: Set node ${{ matrix.node_version }} + uses: actions/setup-node@v3 with: - ref: ${{ github.event.pull_request.head.sha }} + node-version: ${{ matrix.node_version }} + cache: pnpm + + - run: corepack enable + + - name: Install + run: pnpm i - - name: Lint markdown - run: npx markdownlint-cli ${{ needs.job1.outputs.markdown_files }} --ignore node_modules + - name: Test + run: pnpm run test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 268e3a4..78e9c88 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ dist-electron lib public/resources/*addon.node -public/resources/*onnx \ No newline at end of file +public/resources/*onnx +test/**/ggml-*.bin \ No newline at end of file diff --git a/auto-imports.d.ts b/auto-imports.d.ts index af14a13..61bc6ac 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -3,14 +3,8 @@ export {} declare global { const CONFIG_NAME: typeof import('./src/renderer/store/config')['CONFIG_NAME'] const EffectScope: typeof import('vue')['EffectScope'] - const afterAll: typeof import('vitest')['afterAll'] - const afterEach: typeof import('vitest')['afterEach'] - const assert: typeof import('vitest')['assert'] const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] - const beforeAll: typeof import('vitest')['beforeAll'] - const beforeEach: typeof import('vitest')['beforeEach'] - const chai: typeof import('vitest')['chai'] const computed: typeof import('vue')['computed'] const computedAsync: typeof import('@vueuse/core')['computedAsync'] const computedEager: typeof import('@vueuse/core')['computedEager'] @@ -31,10 +25,8 @@ declare global { const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch'] const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] const defineComponent: typeof import('vue')['defineComponent'] - const describe: typeof import('vitest')['describe'] const eagerComputed: typeof import('@vueuse/core')['eagerComputed'] const effectScope: typeof import('vue')['effectScope'] - const expect: typeof import('vitest')['expect'] const extendRef: typeof import('@vueuse/core')['extendRef'] const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentScope: typeof import('vue')['getCurrentScope'] @@ -47,7 +39,6 @@ declare global { const isReactive: typeof import('vue')['isReactive'] const isReadonly: typeof import('vue')['isReadonly'] const isRef: typeof import('vue')['isRef'] - const it: typeof import('vitest')['it'] const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] const markRaw: typeof import('vue')['markRaw'] const nextTick: typeof import('vue')['nextTick'] @@ -93,11 +84,9 @@ declare global { const shallowReadonly: typeof import('vue')['shallowReadonly'] const shallowRef: typeof import('vue')['shallowRef'] const statusStore: typeof import('./src/renderer/store/status')['statusStore'] - const suite: typeof import('vitest')['suite'] const syncRef: typeof import('@vueuse/core')['syncRef'] const syncRefs: typeof import('@vueuse/core')['syncRefs'] const templateRef: typeof import('@vueuse/core')['templateRef'] - const test: typeof import('vitest')['test'] const throttledRef: typeof import('@vueuse/core')['throttledRef'] const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] const toRaw: typeof import('vue')['toRaw'] @@ -268,8 +257,6 @@ declare global { const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus'] const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] - const vi: typeof import('vitest')['vi'] - const vitest: typeof import('vitest')['vitest'] const watch: typeof import('vue')['watch'] const watchArray: typeof import('@vueuse/core')['watchArray'] const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] diff --git a/src/main/whisper/index.ts b/src/main/whisper/index.ts index 45b81a3..6fce97c 100644 --- a/src/main/whisper/index.ts +++ b/src/main/whisper/index.ts @@ -1,7 +1,8 @@ import path from "path"; const prod = import.meta.env.PROD -const resourcesPath = prod ? process.resourcesPath : path.join(__dirname, "../../public/resources") +const test = import.meta.env.TEST +const resourcesPath = prod ? process.resourcesPath : path.join(__dirname, "../../../public/resources") const { whisper } = require(path.join( resourcesPath, @@ -17,8 +18,6 @@ type WhisperAsync = (options: { max_len?: number /** default: false */ translate?: boolean - /** default: false */ - no_timestamps?: boolean }) => Promise{ - it("savePath 1", ()=>{ - const path = "" - const result = safePath(path) - expect(result).toBe("") - }) - it("savePath 2", ()=>{ - const path = "e:\\test" - const result = safePath(path) - expect(result).toBe("e:\\\\test") - }) - it("savePath 3", ()=>{ - const path = "e:\\\\test" - const result = safePath(path) - expect(result).toBe("e:\\\\test") - }) - it("savePath 4", ()=>{ - const path = "e:\\te st" - const result = safePath(path) - expect(result).toBe("e:\\\\te st") - }) - it("savePath 5", ()=>{ - const path = "e:\\te\ st" - const result = safePath(path) - expect(result).toBe("e:\\\\te st") - }) - it("savePath 6", ()=>{ - const path = "/te st" - const result = safePath(path) - expect(result).toBe("/te st") - }) - it("savePath 7", ()=>{ - const path = "/te\ st" - const result = safePath(path) - expect(result).toBe("/te st") - }) -}) diff --git a/test/unit/whisper/index.spec.ts b/test/unit/whisper/index.spec.ts new file mode 100644 index 0000000..1a94a9d --- /dev/null +++ b/test/unit/whisper/index.spec.ts @@ -0,0 +1,49 @@ +import got from "got" +import fs from "node:fs" +import path from "node:path" +import { transcribe } from "~~/whisper" + +const modelPath = path.resolve(__dirname, "ggml-base.bin"); + +function downloadModel(){ + return new Promise((resolve, reject) => { + const modelFile = fs.createWriteStream(modelPath); + got.stream("https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin") + .on("downloadProgress", ({ transferred, total }) => { + const progress = (100.0 * transferred / total).toFixed(2) // 当前进度 + const currProgress = (transferred / 1048576).toFixed(2) // 当前下了多少 + console.log("data", progress, currProgress, total / 1048576) + }) + .pipe(modelFile).on("finish", ()=>{ + console.log("downloaded") + modelFile.close(); + resolve() + }) + .on("error", (err)=>{ + console.error(err) + modelFile.close(); + fs.unlinkSync(modelPath) + reject() + }) + }) +} + +beforeEach(async () => { + if(!fs.existsSync(modelPath)) { + try { + await downloadModel() + }catch(e) { + if(fs.existsSync(modelPath)) { + fs.unlinkSync(modelPath) + } + } + } +}, 100000) + +describe("whisper", () => { + it("transcribe ", async () => { + const wavFilePath = path.resolve(__dirname, "./jfk.wav"); + const result = await transcribe(modelPath, wavFilePath) + expect(result.length).toBe(2) + }) +}) \ No newline at end of file diff --git a/test/unit/whisper/jfk.wav b/test/unit/whisper/jfk.wav new file mode 100644 index 0000000..3184d37 Binary files /dev/null and b/test/unit/whisper/jfk.wav differ diff --git a/tsconfig.node.json b/tsconfig.node.json index afba423..bbf035c 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -6,6 +6,9 @@ "moduleResolution": "node", "jsx": "preserve", "resolveJsonModule": true, + "types": [ + "vitest/globals" + ], "paths": { "~~/*": [ "./src/main/*" diff --git a/vite.config.ts b/vite.config.ts index a1ded88..a528c63 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -22,10 +22,12 @@ export default defineConfig({ __VUE_OPTIONS_API__: false, // 不使用 Options Api }, test: { + include: [path.resolve(__dirname, "./test/**/*.spec.ts")], alias: [ {find: "@", replacement: path.resolve(__dirname, "./src/renderer/")}, {find: "~~", replacement: path.resolve(__dirname, "./src/main/")}, ], + globals: true, }, plugins: [ vue(), @@ -39,7 +41,7 @@ export default defineConfig({ /\.vue$/, /\.vue\?vue/, // .vue ], - imports: ["vue", "vue-router", "@vueuse/core", "vitest", "vue-i18n"], + imports: ["vue", "vue-router", "@vueuse/core", "vue-i18n"], dirs: ["src/renderer/hooks", "src/renderer/store", "src/renderer/utils", "src/renderer/api"], dts: true, }),