From bd206d3804402d3cdadea758fb5556e074f95e8c Mon Sep 17 00:00:00 2001 From: Ben Marshall Date: Fri, 8 Nov 2024 16:32:41 -0500 Subject: [PATCH 1/3] playing with stdin --- cmd/root.go | 2 +- cmd/transcribe.go | 100 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 4a2ed179..2e54e269 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -10,7 +10,7 @@ var rootCmd = &cobra.Command{ Use: "prattl", Short: "Prattl is a transcription tool", Long: "A transcription tool built with Go and Python.\nComplete documentation is available at https://github.com/prattlOrg/prattl", - Version: "v0.2.2", + Version: "v0.3.0", } func Execute() { diff --git a/cmd/transcribe.go b/cmd/transcribe.go index 27829568..509b9782 100644 --- a/cmd/transcribe.go +++ b/cmd/transcribe.go @@ -1,10 +1,9 @@ package cmd import ( + "bufio" "bytes" - "encoding/json" "fmt" - "io" "os" "strings" @@ -22,44 +21,83 @@ var transcribeCmd = &cobra.Command{ Use: "transcribe ", Short: "Transcribe the provided audio file (file path)", Long: "This command transcribes the provided audiofile and prints the resulting string", - Args: cobra.MinimumNArgs(1), + // Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - _ = isPipeInput() - // fmt.Println(isPipe) - fmt.Printf("Transcribing...") - transcriptionMap := make(map[string]string) - transcriptions, err := transcribe(args) + isStdin, err := checkStdin() if err != nil { return err } - - for i, trans := range transcriptions { - transcriptionMap[args[i]] = trans - // fmt.Printf("%v\n", trans) - // _, err := io.WriteString(os.Stdout, trans+"\n") - // if err != nil { - // return fmt.Errorf("error writing to stdout: %v", err) - // } - } - - jsonOutput, err := json.Marshal(transcriptionMap) - if err != nil { - return fmt.Errorf("error marshaling to JSON: %v", err) + if isStdin { + fileBytes, err := readStdin() + if err != nil { + return err + } + fmt.Println(fileBytes) + fmt.Println(string(fileBytes)) + } else { + if len(args) == 0 { + return fmt.Errorf("requires at least 1 arg(s), only received 0") + } + fmt.Println("using filepath") } - - clearLine() - _, err = io.WriteString(os.Stdout, string(jsonOutput)+"\n") - if err != nil { - return fmt.Errorf("error writing to stdout: %v", err) - } - return nil + // fmt.Printf("Transcribing...") + // transcriptionMap := make(map[string]string) + // transcriptions, err := transcribe(args) + // if err != nil { + // return err + // } + + // for i, trans := range transcriptions { + // transcriptionMap[args[i]] = trans + // // fmt.Printf("%v\n", trans) + // // _, err := io.WriteString(os.Stdout, trans+"\n") + // // if err != nil { + // // return fmt.Errorf("error writing to stdout: %v", err) + // // } + // } + + // jsonOutput, err := json.Marshal(transcriptionMap) + // if err != nil { + // return fmt.Errorf("error marshaling to JSON: %v", err) + // } + + // clearLine() + // _, err = io.WriteString(os.Stdout, string(jsonOutput)+"\n") + // if err != nil { + // return fmt.Errorf("error writing to stdout: %v", err) + // } + + // return nil }, } -func isPipeInput() bool { - fileInfo, _ := os.Stdin.Stat() - return fileInfo.Mode()&os.ModeCharDevice == 0 +func checkStdin() (bool, error) { + fileStat, err := os.Stdin.Stat() + if err != nil { + return false, fmt.Errorf("getting stdin stat failed: %v", err) + } + // check if stdin is pipe + if fileStat.Mode()&os.ModeNamedPipe == 0 { + return false, nil + } else { + return true, nil + } +} + +func readStdin() ([]byte, error) { + scanner := bufio.NewScanner(os.Stdin) + scannerBytes := make([]byte, 0) + for scanner.Scan() { + if len(scanner.Bytes()) == 0 { + return nil, fmt.Errorf("stdin is empty") + } + scannerBytes = append(scannerBytes, scanner.Bytes()...) + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("reading from stdin failed: %v", err) + } + return scannerBytes, nil } func transcribe(fps []string) ([]string, error) { From 80a1f9adf4c236255b1d81f337f0c5e5811a6032 Mon Sep 17 00:00:00 2001 From: Ben Marshall Date: Mon, 11 Nov 2024 23:31:40 -0500 Subject: [PATCH 2/3] fixed harcoded version number in rootcmd with goreleaser, added stdin file read for transcription; tests failing --- .goreleaser.yaml | 2 + Makefile | 6 +- cmd/clean.go | 2 +- cmd/compress.go | 4 +- cmd/prepare.go | 2 +- cmd/report.go | 2 +- cmd/root.go | 12 +++- cmd/transcribe.go | 148 ++++++++++++++++++++++------------------- cmd/transcribe_test.go | 39 +++++++++++ 9 files changed, 140 insertions(+), 77 deletions(-) create mode 100644 cmd/transcribe_test.go diff --git a/.goreleaser.yaml b/.goreleaser.yaml index a6211959..1b12e30a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -17,6 +17,8 @@ builds: goarch: 386 - goos: windows goarch: arm64 + ldflags: + - -s -w -X cmd.version={{.Version}} -X cmd.commit={{.Commit}} -X cmd.date={{.Date}} -X cmd.builtBy=goreleaser universal_binaries: - replace: true diff --git a/Makefile b/Makefile index 8610b957..853e4aed 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,6 @@ local: - goreleaser release --snapshot --clean \ No newline at end of file + goreleaser release --snapshot --clean +test-stdin: + go test ./cmd -run TestStdin -count=1 -v +test-fp: + go test ./cmd -run TestFp -count=1 -v \ No newline at end of file diff --git a/cmd/clean.go b/cmd/clean.go index cb4e1aa0..42a4f98c 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -14,7 +14,7 @@ var Confirm bool func init() { cleanCmd.Flags().BoolVarP(&Confirm, "confirm", "y", false, "skips confirmation prompt") - rootCmd.AddCommand(cleanCmd) + RootCmd.AddCommand(cleanCmd) } var cleanCmd = &cobra.Command{ diff --git a/cmd/compress.go b/cmd/compress.go index bc233d86..4a7e196c 100644 --- a/cmd/compress.go +++ b/cmd/compress.go @@ -8,8 +8,8 @@ import ( ) func init() { - rootCmd.AddCommand(compressCommand) - rootCmd.AddCommand(decompressCommand) + RootCmd.AddCommand(compressCommand) + RootCmd.AddCommand(decompressCommand) } var compressCommand = &cobra.Command{ diff --git a/cmd/prepare.go b/cmd/prepare.go index 4b820086..47fe62c3 100644 --- a/cmd/prepare.go +++ b/cmd/prepare.go @@ -8,7 +8,7 @@ import ( ) func init() { - rootCmd.AddCommand(prepareCmd) + RootCmd.AddCommand(prepareCmd) } var prepareCmd = &cobra.Command{ diff --git a/cmd/report.go b/cmd/report.go index f930cccd..2df542b5 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -12,7 +12,7 @@ import ( ) func init() { - rootCmd.AddCommand(reportCommand) + RootCmd.AddCommand(reportCommand) } // ripped straight from stack overflow: https://stackoverflow.com/questions/32482673/how-to-get-directory-total-size diff --git a/cmd/root.go b/cmd/root.go index 2e54e269..3753926f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,15 +6,21 @@ import ( "github.com/spf13/cobra" ) -var rootCmd = &cobra.Command{ +var ( + version = "dev" + // commit = "none" + // date = "unknown" +) + +var RootCmd = &cobra.Command{ Use: "prattl", Short: "Prattl is a transcription tool", Long: "A transcription tool built with Go and Python.\nComplete documentation is available at https://github.com/prattlOrg/prattl", - Version: "v0.3.0", + Version: version, } func Execute() { - if err := rootCmd.Execute(); err != nil { + if err := RootCmd.Execute(); err != nil { os.Exit(1) } } diff --git a/cmd/transcribe.go b/cmd/transcribe.go index 509b9782..a3ecaac1 100644 --- a/cmd/transcribe.go +++ b/cmd/transcribe.go @@ -3,7 +3,10 @@ package cmd import ( "bufio" "bytes" + "encoding/json" + "errors" "fmt" + "io" "os" "strings" @@ -14,7 +17,7 @@ import ( ) func init() { - rootCmd.AddCommand(transcribeCmd) + RootCmd.AddCommand(transcribeCmd) } var transcribeCmd = &cobra.Command{ @@ -32,82 +35,70 @@ var transcribeCmd = &cobra.Command{ if err != nil { return err } - fmt.Println(fileBytes) - fmt.Println(string(fileBytes)) + err = transcribeStdin(fileBytes) + if err != nil { + return err + } } else { if len(args) == 0 { return fmt.Errorf("requires at least 1 arg(s), only received 0") } - fmt.Println("using filepath") + err = transcribeFp(args...) + if err != nil { + return err + } } + return nil - // fmt.Printf("Transcribing...") - // transcriptionMap := make(map[string]string) - // transcriptions, err := transcribe(args) - // if err != nil { - // return err - // } - - // for i, trans := range transcriptions { - // transcriptionMap[args[i]] = trans - // // fmt.Printf("%v\n", trans) - // // _, err := io.WriteString(os.Stdout, trans+"\n") - // // if err != nil { - // // return fmt.Errorf("error writing to stdout: %v", err) - // // } - // } - - // jsonOutput, err := json.Marshal(transcriptionMap) - // if err != nil { - // return fmt.Errorf("error marshaling to JSON: %v", err) - // } - - // clearLine() - // _, err = io.WriteString(os.Stdout, string(jsonOutput)+"\n") - // if err != nil { - // return fmt.Errorf("error writing to stdout: %v", err) - // } - - // return nil }, } func checkStdin() (bool, error) { - fileStat, err := os.Stdin.Stat() - if err != nil { - return false, fmt.Errorf("getting stdin stat failed: %v", err) - } - // check if stdin is pipe - if fileStat.Mode()&os.ModeNamedPipe == 0 { - return false, nil - } else { - return true, nil - } + // fileStat, err := os.Stdin.Stat() + // if err != nil { + // return false, fmt.Errorf("getting stdin stat failed: %v", err) + // } + // // check if stdin is pipe + // return fileStat.Mode()&os.ModeNamedPipe != 0, nil + return true, nil } func readStdin() ([]byte, error) { - scanner := bufio.NewScanner(os.Stdin) - scannerBytes := make([]byte, 0) - for scanner.Scan() { - if len(scanner.Bytes()) == 0 { - return nil, fmt.Errorf("stdin is empty") + reader := bufio.NewReader(os.Stdin) + var fileBytes []byte + for { + b, err := reader.ReadByte() + if err != nil && !errors.Is(err, io.EOF) { + return nil, fmt.Errorf("failed to read file byte: %v", err) } - scannerBytes = append(scannerBytes, scanner.Bytes()...) - } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("reading from stdin failed: %v", err) + // process the one byte b + if err != nil { + // end of file + break + } + fileBytes = append(fileBytes, b) } - return scannerBytes, nil + return fileBytes, nil } -func transcribe(fps []string) ([]string, error) { - returnStrings := []string{} +func transcribeStdin(fileBytes []byte) error { + fmt.Fprintln(os.Stderr, "Transcribing..") + transcription, err := transcribe(fileBytes) + if err != nil { + return err + } + clearLine() + fmt.Println(transcription[0]) + return nil +} +func transcribeFp(fps ...string) error { + fmt.Fprintln(os.Stderr, "Transcribing..") var allBytes []byte for i, fp := range fps { fileBytes, err := os.ReadFile(fp) if err != nil { - return returnStrings, fmt.Errorf("error reading file: %v", err) + return fmt.Errorf("error reading file: %v", err) } allBytes = append(allBytes, fileBytes...) @@ -116,44 +107,65 @@ func transcribe(fps []string) ([]string, error) { } } + transcriptionMap := make(map[string]string) + transcriptions, err := transcribe(allBytes) + if err != nil { + return err + } + for i, trans := range transcriptions { + transcriptionMap[fps[i]] = trans + } + jsonOutput, err := json.Marshal(transcriptionMap) + if err != nil { + return fmt.Errorf("marshaling to JSON failed: %v", err) + } + clearLine() + _, err = io.WriteString(os.Stdout, string(jsonOutput)+"\n") + if err != nil { + return fmt.Errorf("writing to stdout failed: %v", err) + } + return nil +} +func transcribe(file []byte) ([]string, error) { + fmt.Println(file) program, err := pysrc.ReturnFile("transcribe.py") if err != nil { - return returnStrings, err + return nil, err } env, err := pysrc.GetPrattlEnv() if err != nil { - return returnStrings, err + return nil, err } + cmd, err := env.ExecutePython("-c", program) if err != nil { - return returnStrings, err + return nil, err } + var out bytes.Buffer var stderr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stderr stdin, err := cmd.StdinPipe() if err != nil { - return returnStrings, fmt.Errorf("error instantiating pipe: %v", err) + return nil, fmt.Errorf("error instantiating pipe: %v", stderr.String()) } - cmd.Stdout = &out - cmd.Stderr = &stderr if err = cmd.Start(); err != nil { - return returnStrings, fmt.Errorf("error starting command: %v", err) + return nil, fmt.Errorf("error starting command: %v", stderr.String()) } - _, err = stdin.Write(allBytes) + _, err = stdin.Write(file) if err != nil { - return returnStrings, fmt.Errorf("error writing to stdin: %v", err) + return nil, fmt.Errorf("error writing to stdin: %v", stderr.String()) } stdin.Close() if err = cmd.Wait(); err != nil { - return returnStrings, fmt.Errorf("error waiting for command: %v", err) + return nil, fmt.Errorf("error waiting for command: %v", stderr.String()) } output := out.String() - // fmt.Println(output) - - returnStrings = strings.Split(strings.ToLower(output), embed.SeparatorExpectedString) + returnStrings := strings.Split(strings.ToLower(output), embed.SeparatorExpectedString) for _, str := range returnStrings { str = fmt.Sprintf("---%s---\n", str) diff --git a/cmd/transcribe_test.go b/cmd/transcribe_test.go new file mode 100644 index 00000000..0d381bc8 --- /dev/null +++ b/cmd/transcribe_test.go @@ -0,0 +1,39 @@ +package cmd_test + +import ( + "bytes" + "os" + "path/filepath" + "testing" + + "github.com/prattlOrg/prattl/cmd" +) + +var audio00 = filepath.Clean("../test_audio/test.mp3") +var audio01 = filepath.Clean("../test_audio/transcribing_1.mp3") + +func TestStdin(t *testing.T) { + dat, err := os.ReadFile(audio00) + if err != nil { + t.Fatal(err) + } + // t.Log(dat) + + root := cmd.RootCmd + in := bytes.NewBuffer(dat) + root.SetIn(in) + root.SetArgs([]string{"transcribe"}) + err = root.Execute() + if err != nil { + t.FailNow() + } +} + +func TestFp(t *testing.T) { + root := cmd.RootCmd + root.SetArgs([]string{"transcribe", audio00, audio01}) + err := root.Execute() + if err != nil { + t.FailNow() + } +} From 6684e7028c4263cf65f35eea9a2dfe603576e1ca Mon Sep 17 00:00:00 2001 From: Ben Marshall Date: Sat, 16 Nov 2024 15:45:02 -0500 Subject: [PATCH 3/3] TestStdin passing --- .goreleaser.yaml | 42 +++++++++++++++++++++++++++++++++++++++++- cmd/transcribe.go | 24 +++++++++++++----------- cmd/transcribe_test.go | 24 ++++++++++++++++++++---- 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 1b12e30a..3998ba64 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -20,6 +20,12 @@ builds: ldflags: - -s -w -X cmd.version={{.Version}} -X cmd.commit={{.Commit}} -X cmd.date={{.Date}} -X cmd.builtBy=goreleaser +# binary_signs: +# - {} + +# signs: +# - artifacts: checksum + universal_binaries: - replace: true @@ -68,7 +74,7 @@ brews: chocolateys: - title: prattl authors: Ben Marshall, Ezra Klitsie - project_url: https://github.com/prattlOrg/prattl + project_url: https://prattl.co/ url_template: "https://github.com/prattlOrg/prattl/releases/download/{{ .Tag }}/{{ .ArtifactName }}" copyright: 2024 Prattl Org package_source_url: https://github.com/prattlOrg/prattl @@ -90,8 +96,42 @@ chocolateys: source_repo: "https://push.chocolatey.org/" skip_publish: false +nfpms: + - package_name: prattl + file_name_template: >- + {{ .ProjectName }}_{{ .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}{{ .Arm }}{{ end }} + vendor: Prattl Org. + homepage: https://prattl.co/ + maintainer: Benjamin Marshall + description: |- + Prattl installer package. + CLI tool for transcribing audio to text. + license: MIT + formats: + - apk + - deb + - rpm + - termux.deb + - archlinux + dependencies: + - ffmpeg + # Changelog YAML file, see: https://github.com/goreleaser/chglog + # + # You can use goreleaser/chglog to create the changelog for your project, + # pass that changelog yaml file to GoReleaser, + # and it should in turn setup it accordingly for the given available + # formats (deb and rpm at the moment). + # + # Experimental. + # changelog: changelog.yaml + changelog: sort: asc + use: github filters: exclude: - "^docs:" diff --git a/cmd/transcribe.go b/cmd/transcribe.go index a3ecaac1..510ec0ac 100644 --- a/cmd/transcribe.go +++ b/cmd/transcribe.go @@ -48,19 +48,22 @@ var transcribeCmd = &cobra.Command{ return err } } - return nil }, } func checkStdin() (bool, error) { - // fileStat, err := os.Stdin.Stat() - // if err != nil { - // return false, fmt.Errorf("getting stdin stat failed: %v", err) - // } + fileStat, err := os.Stdin.Stat() + if err != nil { + return false, fmt.Errorf("getting stdin stat failed: %v", err) + } + if fileStat.Size() == 0 { + return false, nil + } + return true, nil + // // check if stdin is pipe // return fileStat.Mode()&os.ModeNamedPipe != 0, nil - return true, nil } func readStdin() ([]byte, error) { @@ -82,18 +85,15 @@ func readStdin() ([]byte, error) { } func transcribeStdin(fileBytes []byte) error { - fmt.Fprintln(os.Stderr, "Transcribing..") transcription, err := transcribe(fileBytes) if err != nil { return err } - clearLine() fmt.Println(transcription[0]) return nil } func transcribeFp(fps ...string) error { - fmt.Fprintln(os.Stderr, "Transcribing..") var allBytes []byte for i, fp := range fps { fileBytes, err := os.ReadFile(fp) @@ -119,7 +119,6 @@ func transcribeFp(fps ...string) error { if err != nil { return fmt.Errorf("marshaling to JSON failed: %v", err) } - clearLine() _, err = io.WriteString(os.Stdout, string(jsonOutput)+"\n") if err != nil { return fmt.Errorf("writing to stdout failed: %v", err) @@ -128,7 +127,7 @@ func transcribeFp(fps ...string) error { } func transcribe(file []byte) ([]string, error) { - fmt.Println(file) + fmt.Fprintln(os.Stderr, "Transcribing..") program, err := pysrc.ReturnFile("transcribe.py") if err != nil { return nil, err @@ -171,6 +170,9 @@ func transcribe(file []byte) ([]string, error) { str = fmt.Sprintf("---%s---\n", str) } + // not working frfr + clearLine() + return returnStrings, nil } diff --git a/cmd/transcribe_test.go b/cmd/transcribe_test.go index 0d381bc8..c2cb8f37 100644 --- a/cmd/transcribe_test.go +++ b/cmd/transcribe_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "bytes" "os" "path/filepath" "testing" @@ -17,16 +16,33 @@ func TestStdin(t *testing.T) { if err != nil { t.Fatal(err) } - // t.Log(dat) + + tmpfile, err := os.CreateTemp("../test_audio", "*.mp3") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) // clean up + if _, err := tmpfile.Write(dat); err != nil { + t.Fatal(err) + } + if _, err := tmpfile.Seek(0, 0); err != nil { + t.Fatal(err) + } + oldStdin := os.Stdin + defer func() { os.Stdin = oldStdin }() // Restore original Stdin + os.Stdin = tmpfile root := cmd.RootCmd - in := bytes.NewBuffer(dat) - root.SetIn(in) + root.SetIn(nil) root.SetArgs([]string{"transcribe"}) err = root.Execute() if err != nil { t.FailNow() } + + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } } func TestFp(t *testing.T) {