From 651e05fd7fa6c942966a7be0d857122e3ceda231 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 2 Jan 2020 15:45:26 +0100 Subject: [PATCH 1/4] Add more tutorial in the guide book --- doc/SUMMARY.md | 3 +++ doc/g_flite_intro.md | 23 +++++++++++++++++++++++ doc/g_flite_setup.md | 28 ++++++++++++++++++++++++++++ doc/g_flite_wasm.md | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 doc/g_flite_intro.md create mode 100644 doc/g_flite_setup.md create mode 100644 doc/g_flite_wasm.md diff --git a/doc/SUMMARY.md b/doc/SUMMARY.md index 2a2f8c9..84efba9 100644 --- a/doc/SUMMARY.md +++ b/doc/SUMMARY.md @@ -1,4 +1,7 @@ # Summary - [Introduction](./index.md) +- [g-flite: step-by-step](./g_flite_intro.md) + - [Set up Cargo](./g_flite_setup.md) + - [Compile flite to Wasm](./g_flite_wasm.md) - [API documentation](./api_docs.md) diff --git a/doc/g_flite_intro.md b/doc/g_flite_intro.md new file mode 100644 index 0000000..b15af93 --- /dev/null +++ b/doc/g_flite_intro.md @@ -0,0 +1,23 @@ +# g-flite: step-by-step + +In this tutorial, we will build a minimalistic version of [g-flite] app, +fully functional, albeit devoid of unnecessary features such as animated +progressbar. + +The idea behind the app is very simple: we want to run the [flite] text-to-speech +program, compiled to Wasm (currently, gWasm requires apps to target `wasm32-unknown-emscripten` +target), distributed across the Golem Network. Thus, given a text input, our app +needs to: +1. package the Wasm binary +2. split the input into some nonoverlapping chunks of text for processing with each + chunk processed in parallel by some Golem node +3. prepare a gWasm task using `gwasm-api`, and send it to our Golem instance for + distributing across the Golem Network +4. and finally, combine the resultant WAV chunks into one final WAV which represents + our input text converted to speech + +The step 3. described above is the one where we will interface with `gwasm-api` crate, +and this is the step where we can orchestrate progress updates to the user. + +[g-flite]: https://github.com/golemfactory/g-flite +[flite]: http://www.festvox.org/flite/ diff --git a/doc/g_flite_setup.md b/doc/g_flite_setup.md new file mode 100644 index 0000000..14f97f9 --- /dev/null +++ b/doc/g_flite_setup.md @@ -0,0 +1,28 @@ +# Set up Cargo + +In this tutorial, we will be building an app, so go ahead and create +a Rust executable by running: + +``` +cargo new --bin g-flite +``` + +Next, let us specify some dependencies ahead of time in `Cargo.toml`: + +``` +# Cargo.toml +[package] +name = "g-flite" +version = "0.1.0" +authors = ["Jakub Konka "] + +[dependencies] +anyhow = "1.0" +appdirs = "0.2" +gwasm-api = "0.1" +hound = { git = "https://github.com/kubkon/hound" } +openssl = "0.10.20" + +[features] +openssl_vendored = ["openssl/vendored"] +``` diff --git a/doc/g_flite_wasm.md b/doc/g_flite_wasm.md new file mode 100644 index 0000000..ec67e6f --- /dev/null +++ b/doc/g_flite_wasm.md @@ -0,0 +1,32 @@ +# Compile flite to Wasm + +We will not compile [flite] to Wasm ourselves. Instead, we will use already +precompiled binary. Go ahead and download the binary from [here]. You will +need both the JavaScript file and the Wasm binary: + +``` +# https://github.com/golemfactory/g-flite/tree/master/assets +.. +flite.js +flite.wasm +``` + +Download them and save them in the `assets` folder: + +``` +g-flite/ +| +|- assets/ +| | +| |- flite.js +| |- flite.wasm +| +|- src/ +| | +| |- main.rs +| +|- Cargo.toml +``` + +[flite]: http://www.festvox.org/flite/ +[here]: https://github.com/golemfactory/g-flite/tree/master/assets From ff8bc42d912a7329add98536bce3aaaa6cb5fcad Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 2 Jan 2020 20:40:33 +0100 Subject: [PATCH 2/4] Describe each Cargo depedency --- doc/g_flite_setup.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/g_flite_setup.md b/doc/g_flite_setup.md index 14f97f9..2da3942 100644 --- a/doc/g_flite_setup.md +++ b/doc/g_flite_setup.md @@ -26,3 +26,23 @@ openssl = "0.10.20" [features] openssl_vendored = ["openssl/vendored"] ``` + +A few words of explanation are in order here: +* We use the [anyhow] crate to handle errors in a hassle-free way. +* [appdirs] will allow us to specify where the default Golem client + configuration is in a cross-platform manner. +* `gwasm-api` refers to this crate. +* We use the [hound] crate to handle concatenating of WAV files + which we expect after each gWasm subtask completes---note that we use + my fork of the crate since `flite` seems not to follow the WAV format + to the letter and hence I've had to introduce some tweaks to be able to + read and concatenate the resultant WAV files in one final file. +* Even though we don't make use of the [openssl] crate directly, we specify + it here, so that on Linux and macOS we can rely on prepackaged openssl lib; + on Windows, you'll need to install it by hand. You can find the [binaries here]. + +[anyhow]: https://github.com/dtolnay/anyhow +[appdirs]: https://github.com/djc/appdirs-rs +[hound]: https://github.com/kubkon/hound +[openssl]: https://github.com/sfackler/rust-openssl +[binaries here]: https://slproweb.com/products/Win32OpenSSL.html From 5caf236dbb443dd9fe1e555bc031165f79a7aa18 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Jan 2020 18:31:25 +0100 Subject: [PATCH 3/4] Add basics of the app's logic --- doc/SUMMARY.md | 2 ++ doc/g_flite_app_split_input.md | 1 + doc/g_flite_apps_logic.md | 59 ++++++++++++++++++++++++++++++++++ doc/g_flite_setup.md | 5 --- 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 doc/g_flite_app_split_input.md create mode 100644 doc/g_flite_apps_logic.md diff --git a/doc/SUMMARY.md b/doc/SUMMARY.md index 84efba9..2c99792 100644 --- a/doc/SUMMARY.md +++ b/doc/SUMMARY.md @@ -4,4 +4,6 @@ - [g-flite: step-by-step](./g_flite_intro.md) - [Set up Cargo](./g_flite_setup.md) - [Compile flite to Wasm](./g_flite_wasm.md) + - [Write the app's logic](./g_flite_apps_logic.md) + - [Split the input](./g_flite_app_split_input.md) - [API documentation](./api_docs.md) diff --git a/doc/g_flite_app_split_input.md b/doc/g_flite_app_split_input.md new file mode 100644 index 0000000..5fb02c1 --- /dev/null +++ b/doc/g_flite_app_split_input.md @@ -0,0 +1 @@ +# Split the input diff --git a/doc/g_flite_apps_logic.md b/doc/g_flite_apps_logic.md new file mode 100644 index 0000000..b938198 --- /dev/null +++ b/doc/g_flite_apps_logic.md @@ -0,0 +1,59 @@ +# Write the app's logic + +The app will consist of 3 bits of functionality which will be executed sequentially: +1. splitting the input text into smaller chunks, +2. packaging each chunk and the `flite` Wasm binary into a `gWasm` task and executing + it on the Golem Network, and +3. collecting the resultant WAV files and combining them into one final WAV file. + +In this tutorial, we will go ahead and implement everything using only the `main.rs` +module. If you were writing a real app (and especially one that is more complicated +than this one, you'd probably want to split the app's functionality into a number of +different modules). We will also specifically not propagate any errors and instead +panic on each (you don't want to do that in your real app). + +Fire up your favourite editor and open `main.rs`, and add the basic skeleton for the app: + +```rust +use gwasm_api::prelude::*; +use std::{env, fs, process}; + +fn split_input(text: String) -> Vec { + unimplemented!() +} + +fn run_on_golem(chunks: Vec) -> ComputedTask { + unimplemented!() +} + +fn combine_output(computed_task: ComputedTask) -> Vec { + unimplemented!() +} + +const FLITE_JS: &[u8] = include_bytes!("../assets/flite.js"); +const FLITE_WASM: &[u8] = include_bytes!("../assets/flite.wasm"); + +fn main() { + // Read in the input text file + let filename = if let Some(filename) = env::args().nth(1) { + filename + } else { + eprintln!("No input file specified!"); + process::exit(1); + } + let contents = fs::read(&self.input).unwrap(); + let text = String::from_utf8(contents).unwrap(); + + // Split the input + let chunks = split_input(text); + + // Run on Golem using gwasm-api + let computed_task = run_on_golem(chunks); + + // Combine the output + let output_wav = combine_output(computed_task); + + // Write to file + fs::write("output.wav", output_wav).unwrap(); +} +``` diff --git a/doc/g_flite_setup.md b/doc/g_flite_setup.md index 2da3942..3f29ebf 100644 --- a/doc/g_flite_setup.md +++ b/doc/g_flite_setup.md @@ -17,7 +17,6 @@ version = "0.1.0" authors = ["Jakub Konka "] [dependencies] -anyhow = "1.0" appdirs = "0.2" gwasm-api = "0.1" hound = { git = "https://github.com/kubkon/hound" } @@ -28,9 +27,6 @@ openssl_vendored = ["openssl/vendored"] ``` A few words of explanation are in order here: -* We use the [anyhow] crate to handle errors in a hassle-free way. -* [appdirs] will allow us to specify where the default Golem client - configuration is in a cross-platform manner. * `gwasm-api` refers to this crate. * We use the [hound] crate to handle concatenating of WAV files which we expect after each gWasm subtask completes---note that we use @@ -41,7 +37,6 @@ A few words of explanation are in order here: it here, so that on Linux and macOS we can rely on prepackaged openssl lib; on Windows, you'll need to install it by hand. You can find the [binaries here]. -[anyhow]: https://github.com/dtolnay/anyhow [appdirs]: https://github.com/djc/appdirs-rs [hound]: https://github.com/kubkon/hound [openssl]: https://github.com/sfackler/rust-openssl From f767d1e78f373633c72d39212eae141c94235162 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 4 Jan 2020 11:35:22 +0100 Subject: [PATCH 4/4] Fix compilation and refactor Cargo.toml --- doc/g_flite_apps_logic.md | 9 ++++++--- doc/g_flite_setup.md | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/g_flite_apps_logic.md b/doc/g_flite_apps_logic.md index b938198..815629a 100644 --- a/doc/g_flite_apps_logic.md +++ b/doc/g_flite_apps_logic.md @@ -12,7 +12,9 @@ than this one, you'd probably want to split the app's functionality into a numbe different modules). We will also specifically not propagate any errors and instead panic on each (you don't want to do that in your real app). -Fire up your favourite editor and open `main.rs`, and add the basic skeleton for the app: +Fire up your favourite editor and open `src/main.rs`. + +## src/main.rs ```rust use gwasm_api::prelude::*; @@ -40,8 +42,9 @@ fn main() { } else { eprintln!("No input file specified!"); process::exit(1); - } - let contents = fs::read(&self.input).unwrap(); + }; + + let contents = fs::read(filename).unwrap(); let text = String::from_utf8(contents).unwrap(); // Split the input diff --git a/doc/g_flite_setup.md b/doc/g_flite_setup.md index 3f29ebf..12abdb4 100644 --- a/doc/g_flite_setup.md +++ b/doc/g_flite_setup.md @@ -10,17 +10,19 @@ cargo new --bin g-flite Next, let us specify some dependencies ahead of time in `Cargo.toml`: ``` -# Cargo.toml [package] name = "g-flite" version = "0.1.0" authors = ["Jakub Konka "] +edition = 2018 + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] appdirs = "0.2" gwasm-api = "0.1" hound = { git = "https://github.com/kubkon/hound" } -openssl = "0.10.20" +openssl = "0.10" [features] openssl_vendored = ["openssl/vendored"]