├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── README.md ├── audio │ └── bueller.wav ├── manage │ ├── billing.rs │ ├── invitations.rs │ ├── keys.rs │ ├── members.rs │ ├── projects.rs │ ├── scopes.rs │ └── usage.rs ├── speak │ └── rest │ │ ├── text_to_speech_to_file.rs │ │ └── text_to_speech_to_stream.rs └── transcription │ ├── rest │ ├── callback.rs │ ├── make_prerecorded_request_builder.rs │ ├── prerecorded_from_file.rs │ └── prerecorded_from_url.rs │ └── websocket │ ├── callback_stream.rs │ ├── microphone_stream.rs │ └── simple_stream.rs └── src ├── common ├── audio_source.rs ├── batch_response.rs ├── mod.rs ├── options.rs └── stream_response.rs ├── lib.rs ├── listen ├── mod.rs ├── rest.rs └── websocket.rs ├── manage ├── billing.rs ├── billing │ └── response.rs ├── invitations.rs ├── invitations │ └── response.rs ├── keys.rs ├── keys │ ├── options.rs │ └── response.rs ├── members.rs ├── members │ └── response.rs ├── mod.rs ├── projects.rs ├── projects │ ├── options.rs │ └── response.rs ├── scopes.rs ├── scopes │ └── response.rs ├── usage.rs └── usage │ ├── get_fields_options.rs │ ├── get_usage_options.rs │ ├── list_requests_options.rs │ └── response.rs └── speak ├── mod.rs ├── options.rs └── rest.rs /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something is occurring that I think is wrong 4 | title: '' 5 | labels: "bug" 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## What is the current behavior? 11 | 12 | 13 | 14 | ## Steps to reproduce 15 | 16 | 17 | 18 | ## Expected behavior 19 | 20 | 21 | 22 | ## Please tell us about your environment 23 | 24 | - **`deepgram` Package Version:** 25 | - **Operating System/Version:** 26 | - **Rust Version:** 27 | 28 | ## Other information 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: DeepgramAI on Twitter 4 | url: https://twitter.com/DeepgramAI 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: I think X would be a cool addition or change. 4 | title: '' 5 | labels: "enhancement" 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Proposed changes 11 | 12 | 13 | 14 | ## Context 15 | 16 | 17 | 18 | ## Possible Implementation 19 | 20 | 21 | 22 | ## Other information 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | ## Proposed changes 13 | 14 | 15 | 16 | ## Types of changes 17 | 18 | 19 | 20 | 21 | - [ ] Bugfix (non-breaking change which fixes an issue) 22 | - [ ] New feature (non-breaking change which adds functionality) 23 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 24 | - [ ] Documentation update or tests (if none of the other choices apply) 25 | 26 | ## Checklist 27 | 28 | 29 | 30 | 31 | - [ ] I have read the [CONTRIBUTING.md](../CONTRIBUTING.md) doc 32 | - [ ] I have added tests and/or examples that prove my fix is effective or that my feature works 33 | - [ ] I have added necessary documentation (if appropriate) 34 | 35 | ## Further comments 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: CI 4 | env: 5 | CARGO_TERM_COLOR: always 6 | RUSTFLAGS: -D warnings 7 | RUSTDOCFLAGS: -D warnings 8 | PKG_CONFIG_PATH: /usr/lib/pkgconfig 9 | 10 | jobs: 11 | Features: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Install dependencies 16 | run: | 17 | sudo apt-get update 18 | sudo apt-get install -y alsa pkg-config libasound2-dev 19 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 20 | - name: Check no features 21 | run: cargo check --all-targets --no-default-features 22 | - name: Check listen feature 23 | run: cargo check --all-targets --no-default-features --features=listen 24 | - name: Check speak feature 25 | run: cargo check --all-targets --no-default-features --features=speak 26 | - name: Check manage feature 27 | run: cargo check --all-targets --no-default-features --features=manage 28 | Build: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v3 32 | - name: Install dependencies 33 | run: | 34 | sudo apt-get update 35 | sudo apt-get install -y alsa pkg-config libasound2-dev 36 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 37 | - name: Cargo Build 38 | run: cargo build --all-targets --all-features 39 | Clippy: 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v3 43 | - name: Install dependencies 44 | run: | 45 | sudo apt-get update 46 | sudo apt-get install -y alsa pkg-config libasound2-dev 47 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 48 | - name: Cargo Clippy 49 | run: cargo clippy --all-targets --all-features 50 | Test: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v3 54 | - name: Install dependencies 55 | run: | 56 | sudo apt-get update 57 | sudo apt-get install -y alsa pkg-config libasound2-dev 58 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 59 | - name: Cargo Test 60 | run: cargo test --all --all-features 61 | Format: 62 | runs-on: ubuntu-latest 63 | steps: 64 | - uses: actions/checkout@v3 65 | - name: Cargo Fmt 66 | run: cargo fmt --check --all 67 | Documentation: 68 | runs-on: ubuntu-latest 69 | steps: 70 | - uses: actions/checkout@v3 71 | - name: Install dependencies 72 | run: | 73 | sudo apt-get update 74 | sudo apt-get install -y alsa pkg-config libasound2-dev 75 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 76 | - name: Cargo Doc 77 | run: cargo doc --workspace --all-features 78 | Audit: 79 | runs-on: ubuntu-latest 80 | steps: 81 | - uses: actions/checkout@v3 82 | - name: Install dependencies 83 | run: sudo apt-get update 84 | - name: Install cargo-audit 85 | run: cargo install --locked cargo-audit 86 | - name: Remove Dev Dependencies 87 | run: | 88 | cargo install --locked cargo-hack 89 | cargo hack --remove-dev-deps 90 | cargo generate-lockfile 91 | - name: Cargo Audit 92 | run: cargo audit 93 | Minimal-Versions: 94 | runs-on: ubuntu-latest 95 | steps: 96 | - uses: actions/checkout@v3 97 | - name: Install dependencies 98 | run: | 99 | sudo apt-get update 100 | sudo apt-get install -y alsa pkg-config libasound2-dev 101 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 102 | - name: Install Rust Nightly 103 | run: rustup toolchain install nightly 104 | - name: Cargo Build 105 | run: rustup run nightly cargo build --all-targets --all-features -Z minimal-versions 106 | - name: Cargo Test 107 | run: rustup run nightly cargo test --all --all-features -Z minimal-versions 108 | - name: Remove Dev Dependencies 109 | run: | 110 | cargo install --locked cargo-hack 111 | cargo hack --remove-dev-deps 112 | rustup run nightly cargo generate-lockfile -Z minimal-versions 113 | - name: Cargo Build Without Dev Dependencies 114 | run: rustup run nightly cargo build --all-features -Z minimal-versions 115 | SemVer: 116 | runs-on: ubuntu-latest 117 | steps: 118 | - uses: actions/checkout@v3 119 | - name: Install dependencies 120 | run: | 121 | sudo apt-get update 122 | sudo apt-get install -y alsa pkg-config libasound2-dev 123 | export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH 124 | - name: Install cargo-semver-checks 125 | run: cargo install --locked cargo-semver-checks 126 | - name: Cargo SemVer Checks 127 | run: cargo semver-checks check-release --verbose 128 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | your_output_file.wav -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased](https://github.com/deepgram/deepgram-rust-sdk/compare/0.6.2...HEAD) 8 | 9 | - Update documentation to point to 10 | [deepgram/deepgram-rust-sdk](https://github.com/deepgram/deepgram-rust-sdk). 11 | 12 | ## [0.6.1](https://github.com/deepgram/deepgram-rust-sdk/compare/0.6.1...0.6.2) 13 | 14 | - 15 | ## [0.6.1](https://github.com/deepgram/deepgram-rust-sdk/compare/0.6.0...0.6.1) 16 | 17 | - Implement `From` for `Model`, `Language`, and `Redact` 18 | - Add callback support to websocket connections. 19 | 20 | ## [0.6.0](https://github.com/deepgram/deepgram-rust-sdk/compare/0.5.0...0.6.0) - 2024-08-08 21 | 22 | ### Migrating from 0.4.0 -> 0.6.0 23 | 24 | #### Module Imports 25 | 26 | ```rust 27 | use deepgram::{ 28 | --- transcription::prerecorded::{ 29 | +++ common::{ 30 | audio_source::AudioSource, 31 | options::{Language, Options}, 32 | }, 33 | Deepgram, DeepgramError, 34 | }; 35 | ``` 36 | 37 | #### Streaming Changes 38 | 39 | We have exposed a low-level, message-based interface to the websocket API: 40 | 41 | ```rust 42 | use futures::select; 43 | 44 | let mut handle = dg 45 | .transcription() 46 | .stream_request() 47 | .handle() 48 | .await?; 49 | 50 | loop { 51 | select! { 52 | _ = tokio::time::sleep(Duration::from_secs(3)) => handle.keep_alive().await, 53 | _ = handle.send_data(data_chunk()).fuse() => {} 54 | response = handle.receive().fuse() => { 55 | match response { 56 | Some(response) => println!("{response:?}"), 57 | None => break, 58 | } 59 | } 60 | } 61 | } 62 | handle.close_stream().await; 63 | ``` 64 | 65 | No need to call `.start()` to begin streaming data. 66 | 67 | ```rust 68 | let mut results = dg 69 | .transcription() 70 | .stream_request_with_options(Some(&options)) 71 | .file(PATH_TO_FILE, AUDIO_CHUNK_SIZE, Duration::from_millis(16)) 72 | --- .await 73 | --- .start() 74 | .await; 75 | ``` 76 | 77 | Now you can pass Options using stream_request_with_options 78 | 79 | ```rust 80 | let options = Options::builder() 81 | .smart_format(true) 82 | .language(Language::en_US) 83 | .build(); 84 | 85 | let mut results = dg 86 | .transcription() 87 | .stream_request_with_options(Some(&options)) 88 | .file(PATH_TO_FILE, AUDIO_CHUNK_SIZE, Duration::from_millis(16)) 89 | .await? 90 | ``` 91 | 92 | Some Enums have changed and may need to be updated 93 | 94 | ### Changed 95 | 96 | - Add streaming features 97 | - Add support for pre-recorded features when streaming 98 | - Add Speech to Text 99 | - Reorganize Code 100 | 101 | 102 | ### Streaming Features 103 | - endpointing 104 | - utterance_end_ms 105 | - interim_results 106 | - no_delay 107 | - vad_events 108 | 109 | ### Streaming Functions 110 | - keep_alive 111 | 112 | ### New Streaming Message Types 113 | - Utterance End 114 | - Speech Started 115 | 116 | ### Pre-Recorded Features 117 | - encoding 118 | - smart_format 119 | - callback 120 | - callback_method 121 | - filler_words 122 | - paragraphs 123 | - diarize_version 124 | - dictation 125 | - measurements 126 | - extra 127 | 128 | ### Pre-Recorded Audio Intelligence Features 129 | - detect_entities 130 | - sentiment 131 | - topics 132 | - summarize 133 | - intents 134 | - custom_intents 135 | - custom_intent_mode 136 | - topics 137 | - custom_topics 138 | - custom_topic_mode 139 | 140 | ## [0.5.0](https://github.com/deepgram/deepgram-rust-sdk/compare/0.4.0...0.5.0) - 2024-07-08 141 | 142 | - Deprecate tiers and add explicit support for all currently available models. 143 | - Expand language enum to include all currently-supported languages. 144 | - Add (default on) feature flags for live and prerecorded transcription. 145 | - Support arbitrary query params in transcription options. 146 | 147 | ## [0.4.0](https://github.com/deepgram/deepgram-rust-sdk/compare/0.3.0...0.4.0) - 2023-11-01 148 | 149 | ### Added 150 | - `detect_language` option. 151 | 152 | ### Changed 153 | - Remove generic from `Deepgram` struct. 154 | - Upgrade dependencies: `tungstenite`, `tokio-tungstenite`, `reqwest`. 155 | 156 | ## [0.3.0](https://github.com/deepgram/deepgram-rust-sdk/compare/0.2.1...0.3.0) - 2023-07-26 157 | 158 | ### Added 159 | - Derive `Serialize` for all response types. 160 | 161 | ### Fixed 162 | - Use the users builder options when building a streaming URL. 163 | - Make sure that `Future` returned from `StreamRequestBuilder::start()` is `Send`. 164 | 165 | ### Changed 166 | - Use Rustls instead of OpenSSL. 167 | 168 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | The Deepgram Community Code of Conduct can be found at -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | **NOTICE**: *For the majority of situations, please use the dev branch as the base for your pull request. 2 | We only update the main branch when we release a new version of the package. 3 | [More info](https://github.com/deepgram/deepgram-rust-sdk/wiki/Branches).* 4 | 5 | # Contributing Guidelines 6 | 7 | Want to contribute to this project? We ❤️ it! 8 | 9 | Here are a few types of contributions that we would be interested in hearing about. 10 | 11 | * Bug fixes 12 | * If you find a bug, please first report it using GitHub Issues. 13 | * Issues that have already been identified as a bug will be labeled `bug`. 14 | * If you'd like to submit a fix for a bug, send a Pull Request from your own fork and mention the Issue number. 15 | * Include a test that isolates the bug and verifies that it was fixed. 16 | * New Features 17 | * If you'd like to accomplish something in the extension that it doesn't already do, describe the problem in a new GitHub Issue. 18 | * Issues that have been identified as a feature request will be labeled `enhancement`. 19 | * If you'd like to implement the new feature, please wait for feedback from the project maintainers before spending 20 | too much time writing the code. In some cases, `enhancement`s may not align well with the project objectives at 21 | the time. 22 | * Tests, Documentation, Miscellaneous 23 | * If you think the test coverage could be improved, the documentation could be clearer, you've got an alternative 24 | implementation of something that may have more advantages, or any other change we would still be glad hear about 25 | it. 26 | * If it's a trivial change, go ahead and send a Pull Request with the changes you have in mind. 27 | * If not, open a GitHub Issue to discuss the idea first. 28 | 29 | We also welcome anyone to work on any existing issues with the `good first issue` tag. 30 | 31 | ## Requirements 32 | 33 | For a contribution to be accepted: 34 | 35 | * The test suite must be complete and pass 36 | * Code must follow existing styling conventions 37 | * Commit messages must be descriptive. Related issues should be mentioned by number. 38 | 39 | If the contribution doesn't meet these criteria, a maintainer will discuss it with you. You can still 40 | continue to add more commits to the branch you have sent the Pull Request from. 41 | 42 | ## How To 43 | 44 | 1. Fork this repository on GitHub. 45 | 2. Clone/fetch your fork to your local development machine. 46 | 3. Create a new branch and check it out. 47 | 4. Make your changes and commit them. (Did the tests pass? No linting errors?) 48 | 5. Push your new branch to your fork. 49 | 6. Open a Pull Request from your new branch to the [`deepgram/deepgram-rust-sdk`](https://github.com/deepgram/deepgram-rust-sdk)'s `dev` branch. 50 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deepgram" 3 | version = "0.6.8" 4 | authors = ["Deepgram "] 5 | edition = "2021" 6 | description = "Community Rust SDK for Deepgram's automated speech recognition APIs." 7 | license = "MIT" 8 | repository = "https://github.com/deepgram/deepgram-rust-sdk" 9 | keywords = [ 10 | "transcription", 11 | "voice-ai", 12 | "text-to-speech", 13 | "speech-to-text", 14 | "asr", 15 | ] 16 | categories = ["api-bindings", "multimedia::audio"] 17 | 18 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 19 | 20 | [dependencies] 21 | # TODO Investigate which of these dependencies can go behind features. 22 | audio = "0.2.0" 23 | bytes = "1" 24 | futures = "0.3" 25 | http = "0.2" 26 | pin-project = "1" 27 | reqwest = { version = "0.11.22", default-features = false, features = [ 28 | "json", 29 | "rustls-tls", 30 | "stream", 31 | ] } 32 | rodio = { version = "0.17.0", optional = true } 33 | serde = { version = "1.0.215", features = ["derive"] } 34 | serde_json = "1" 35 | serde_urlencoded = "0.7" 36 | thiserror = "1" 37 | tokio = { version = "1.38.0", features = ["full"] } 38 | tokio-stream = "0.1.15" 39 | tokio-tungstenite = { version = "0.20.1", features = [ 40 | "rustls-tls-webpki-roots", 41 | ], optional = true } 42 | tokio-util = { version = "0.7.1", features = ["codec", "io"] } 43 | tungstenite = { version = "0.20.1", optional = true } 44 | url = "2" 45 | uuid = { version = "1", features = ["serde"] } 46 | # Dependencies below are specified only to satisfy minimal-versions. 47 | proc-macro2 = "1.0.60" 48 | pkg-config = { version = "0.3.30", optional = true } 49 | sha256 = "1.5.0" 50 | anyhow = "1.0.86" 51 | 52 | [dev-dependencies] 53 | cpal = "0.13" 54 | crossbeam = "0.8" 55 | 56 | [features] 57 | default = ["manage", "listen", "speak"] 58 | manage = [] 59 | listen = ["dep:tungstenite", "dep:tokio-tungstenite"] 60 | speak = ["dep:rodio", "dep:pkg-config"] 61 | 62 | [[example]] 63 | name = "prerecorded_from_file" 64 | path = "examples/transcription/rest/prerecorded_from_file.rs" 65 | required-features = ["listen"] 66 | 67 | [[example]] 68 | name = "callback" 69 | path = "examples/transcription/rest/callback.rs" 70 | required-features = ["listen"] 71 | 72 | [[example]] 73 | name = "make_prerecorded_request_builder" 74 | path = "examples/transcription/rest/make_prerecorded_request_builder.rs" 75 | required-features = ["listen"] 76 | 77 | [[example]] 78 | name = "prerecorded_from_url" 79 | path = "examples/transcription/rest/prerecorded_from_url.rs" 80 | required-features = ["listen"] 81 | 82 | [[example]] 83 | name = "simple_stream" 84 | path = "examples/transcription/websocket/simple_stream.rs" 85 | required-features = ["listen"] 86 | 87 | [[example]] 88 | name = "callback_stream" 89 | path = "examples/transcription/websocket/callback_stream.rs" 90 | required-features = ["listen"] 91 | 92 | [[example]] 93 | name = "microphone_stream" 94 | path = "examples/transcription/websocket/microphone_stream.rs" 95 | required-features = ["listen"] 96 | 97 | [[example]] 98 | name = "text_to_speech_to_file" 99 | path = "examples/speak/rest/text_to_speech_to_file.rs" 100 | required-features = ["speak"] 101 | 102 | [[example]] 103 | name = "text_to_speech_to_stream" 104 | path = "examples/speak/rest/text_to_speech_to_stream.rs" 105 | required-features = ["speak"] 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Deepgram 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deepgram Rust SDK 2 | 3 | [![Discord](https://dcbadge.vercel.app/api/server/xWRaCDBtW4?style=flat)](https://discord.gg/xWRaCDBtW4) 4 | [![CI](https://github.com/deepgram/deepgram-rust-sdk/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/deepgram/deepgram-rust-sdk/actions/workflows/ci.yaml) 5 | [![crates.io](https://img.shields.io/crates/v/deepgram)](https://crates.io/crates/deepgram) 6 | [![downloads](https://img.shields.io/crates/d/deepgram)](https://crates.io/crates/deepgram) 7 | [![docs](https://img.shields.io/docsrs/deepgram)](https://docs.rs/deepgram) 8 | [![license](https://img.shields.io/crates/l/deepgram)](./LICENSE) 9 | 10 | A Community Rust SDK for [Deepgram](https://www.deepgram.com/). Start building with our powerful transcription & speech understanding API. 11 | 12 | ## SDK Documentation 13 | 14 | This SDK implements the Deepgram API found at [https://developers.deepgram.com](https://developers.deepgram.com). 15 | 16 | Documentation and examples can be found on our [Docs.rs page](https://docs.rs/deepgram/latest/deepgram/). 17 | 18 | ## Getting an API Key 19 | 20 | 🔑 To access the Deepgram API you will need a [free Deepgram API Key](https://console.deepgram.com/signup?jump=keys). 21 | 22 | 23 | ## Current Status 24 | 25 | This SDK is currently Community owned but is moving to a stable `1.0` version soon. 26 | 27 | ## Install 28 | 29 | From within your Cargo project directory, run the following command: 30 | 31 | ```sh 32 | cargo add deepgram 33 | ``` 34 | 35 | You will also probably need to install [`tokio`](https://crates.io/crates/tokio): 36 | 37 | ```sh 38 | cargo add tokio --features full 39 | ``` 40 | 41 | ## Development and Contributing 42 | 43 | Interested in contributing? We ❤️ pull requests! 44 | 45 | To make sure our community is safe for all, be sure to review and agree to our 46 | [Code of Conduct](./CODE_OF_CONDUCT.md) and review our 47 | [Contributing Guidelines](./CONTRIBUTING.md). 48 | 49 | ### Build the SDK 50 | 51 | ```sh 52 | cargo build 53 | ``` 54 | 55 | ## Getting Help 56 | 57 | We love to hear from you so if you have questions, comments or find a bug in the 58 | project, let us know! You can either: 59 | 60 | - [Open an issue in this repository](https://github.com/deepgram/deepgram-rust-sdk/issues/new) 61 | - [Join the Deepgram Github Discussions Community](https://github.com/orgs/deepgram/discussions) 62 | - [Join the Deepgram Discord Community](https://discord.gg/xWRaCDBtW4) 63 | 64 | [license]: LICENSE.txt 65 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Running Examples 2 | 3 | ### Setting Env Vars 4 | 5 | ```sh 6 | export FILENAME=./examples/audio/bueller.wav 7 | ``` 8 | 9 | ### Running the examples 10 | 11 | ```sh 12 | cargo run --example prerecorded_from_url 13 | ``` 14 | 15 | ```sh 16 | cargo run --example simple_stream 17 | ``` 18 | 19 | ```sh 20 | cargo run --example callback 21 | ``` 22 | 23 | ```sh 24 | cargo run --example make_prerecorded_request_builder 25 | ``` 26 | 27 | ```sh 28 | cargo run --example microphone_stream 29 | ``` 30 | 31 | ```sh 32 | cargo run --example text_to_speech_to_file 33 | ``` 34 | 35 | ```sh 36 | cargo run --example text_to_speech_to_stream 37 | ``` 38 | -------------------------------------------------------------------------------- /examples/audio/bueller.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepgram/deepgram-rust-sdk/0b59d08d4a489d1c28b81ec81f2bfd20f39a2ec0/examples/audio/bueller.wav -------------------------------------------------------------------------------- /examples/manage/billing.rs: -------------------------------------------------------------------------------- 1 | use deepgram::{Deepgram, DeepgramError}; 2 | use std::env; 3 | 4 | #[tokio::main] 5 | async fn main() -> Result<(), DeepgramError> { 6 | let deepgram_api_key = 7 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 8 | 9 | let project_id = 10 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 11 | 12 | let balance_id = 13 | env::var("DEEPGRAM_BALANCE_ID").expect("DEEPGRAM_BALANCE_ID environmental variable"); 14 | 15 | let dg_client = Deepgram::new(&deepgram_api_key); 16 | 17 | let all_balances = dg_client.billing().list_balance(&project_id).await?; 18 | println!("{:#?}", all_balances); 19 | 20 | let specific_balance = dg_client 21 | .billing() 22 | .get_balance(&project_id, &balance_id) 23 | .await?; 24 | println!("{:#?}", specific_balance); 25 | 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /examples/manage/invitations.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{Deepgram, DeepgramError}; 4 | 5 | #[tokio::main] 6 | async fn main() -> Result<(), DeepgramError> { 7 | let deepgram_api_key = 8 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 9 | 10 | let project_id = 11 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 12 | 13 | let dg_client = Deepgram::new(&deepgram_api_key); 14 | 15 | let message = dg_client.invitations().leave_project(&project_id).await?; 16 | println!("{:#?}", message); 17 | 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /examples/manage/keys.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{keys::options::Options, Deepgram, DeepgramError}; 4 | 5 | #[tokio::main] 6 | async fn main() -> Result<(), DeepgramError> { 7 | let deepgram_api_key = 8 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 9 | 10 | let project_id = 11 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 12 | 13 | let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 14 | 15 | let dg_client = Deepgram::new(&deepgram_api_key); 16 | 17 | let keys = dg_client.keys().list(&project_id).await?; 18 | println!("{:#?}", keys); 19 | 20 | let key = dg_client.keys().get(&project_id, &key_id).await?; 21 | println!("{:#?}", key); 22 | 23 | let options = Options::builder("New Key", ["member"]).build(); 24 | let new_key = dg_client.keys().create(&project_id, &options).await?; 25 | println!("{:#?}", new_key); 26 | 27 | let message = dg_client.keys().delete(&project_id, &key_id).await?; 28 | println!("{}", message.message); 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /examples/manage/members.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{Deepgram, DeepgramError}; 4 | 5 | #[tokio::main] 6 | async fn main() -> Result<(), DeepgramError> { 7 | let deepgram_api_key = 8 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 9 | 10 | let project_id = 11 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 12 | 13 | let member_id = 14 | env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 15 | 16 | let dg_client = Deepgram::new(&deepgram_api_key); 17 | 18 | let members = dg_client.members().list_members(&project_id).await?; 19 | println!("{:#?}", members); 20 | 21 | let message = dg_client 22 | .members() 23 | .remove_member(&project_id, &member_id) 24 | .await?; 25 | println!("{}", message.message); 26 | 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /examples/manage/projects.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{projects::options::Options, Deepgram, DeepgramError}; 4 | 5 | #[tokio::main] 6 | async fn main() -> Result<(), DeepgramError> { 7 | let deepgram_api_key = 8 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 9 | 10 | let project_id = 11 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 12 | 13 | let dg_client = Deepgram::new(&deepgram_api_key); 14 | 15 | let projects = dg_client.projects().list().await?; 16 | println!("{:#?}", projects); 17 | 18 | let project = dg_client.projects().get(&project_id).await?; 19 | println!("{:#?}", project); 20 | 21 | let options = Options::builder() 22 | .name("The Transcribinator") 23 | .company("Doofenshmirtz Evil Incorporated") 24 | .build(); 25 | let message = dg_client.projects().update(&project_id, &options).await?; 26 | println!("{}", message.message); 27 | 28 | let message = dg_client.projects().delete(&project_id).await?; 29 | println!("{}", message.message); 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /examples/manage/scopes.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{Deepgram, DeepgramError}; 4 | 5 | #[tokio::main] 6 | async fn main() -> Result<(), DeepgramError> { 7 | let deepgram_api_key = 8 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 9 | 10 | let project_id = 11 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 12 | 13 | let member_id = 14 | env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 15 | 16 | let dg_client = Deepgram::new(&deepgram_api_key); 17 | 18 | let scopes = dg_client 19 | .scopes() 20 | .get_scope(&project_id, &member_id) 21 | .await?; 22 | println!("{:#?}", scopes); 23 | 24 | let message = dg_client 25 | .scopes() 26 | .update_scope(&project_id, &member_id, "member") 27 | .await?; 28 | println!("{}", message.message); 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /examples/manage/usage.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{ 4 | usage::{get_fields_options, get_usage_options, list_requests_options}, 5 | Deepgram, DeepgramError, 6 | }; 7 | 8 | #[tokio::main] 9 | async fn main() -> Result<(), DeepgramError> { 10 | let deepgram_api_key = 11 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 12 | 13 | let project_id = 14 | env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 15 | 16 | let request_id = 17 | env::var("DEEPGRAM_REQUEST_ID").expect("DEEPGRAM_REQUEST_ID environmental variable"); 18 | 19 | let dg_client = Deepgram::new(&deepgram_api_key); 20 | 21 | let options = list_requests_options::Options::builder().build(); 22 | let requests = dg_client 23 | .usage() 24 | .list_requests(&project_id, &options) 25 | .await?; 26 | println!("{:#?}", requests); 27 | 28 | let request = dg_client 29 | .usage() 30 | .get_request(&project_id, &request_id) 31 | .await?; 32 | println!("{:#?}", request); 33 | 34 | let options = get_usage_options::Options::builder().build(); 35 | let summary = dg_client.usage().get_usage(&project_id, &options).await?; 36 | println!("{:#?}", summary); 37 | 38 | let options = get_fields_options::Options::builder().build(); 39 | let summary = dg_client.usage().get_fields(&project_id, &options).await?; 40 | println!("{:#?}", summary); 41 | 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /examples/speak/rest/text_to_speech_to_file.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path::Path, time::Instant}; 2 | 3 | use deepgram::{ 4 | speak::options::{Container, Encoding, Model, Options}, 5 | Deepgram, DeepgramError, 6 | }; 7 | 8 | #[tokio::main] 9 | async fn main() -> Result<(), DeepgramError> { 10 | let deepgram_api_key = 11 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 12 | 13 | let dg_client = Deepgram::new(&deepgram_api_key)?; 14 | 15 | let options = Options::builder() 16 | .model(Model::AuraAsteriaEn) 17 | .encoding(Encoding::Linear16) 18 | .sample_rate(16000) 19 | .container(Container::Wav) 20 | .build(); 21 | 22 | let text = "Hello, how can I help you today? This is a longer sentence to increase the time taken to process the audio, so that the streaming shows the full delta vs downloading the whole file."; 23 | let output_file = Path::new("your_output_file.wav"); 24 | 25 | // Record the start time 26 | let start_time = Instant::now(); 27 | 28 | dg_client 29 | .text_to_speech() 30 | .speak_to_file(text, &options, output_file) 31 | .await?; 32 | 33 | let elapsed_time = start_time.elapsed(); 34 | println!("Time to download audio: {:.2?}", elapsed_time); 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /examples/speak/rest/text_to_speech_to_stream.rs: -------------------------------------------------------------------------------- 1 | use audio::channel::LinearChannel; 2 | use audio::Buf; 3 | use bytes::BytesMut; 4 | use deepgram::speak::options::{Container, Encoding, Model}; 5 | use deepgram::{speak::options::Options, Deepgram, DeepgramError}; 6 | use futures::stream::StreamExt; 7 | use rodio::buffer::SamplesBuffer; 8 | use rodio::{OutputStream, Sink}; 9 | use std::env; 10 | use std::time::Instant; 11 | 12 | #[derive(Clone)] 13 | pub struct Linear16AudioSource { 14 | sample_rate: u32, 15 | channels: u16, 16 | buffer: Vec, 17 | } 18 | 19 | impl Linear16AudioSource { 20 | pub fn new(sample_rate: u32, channels: u16) -> Self { 21 | Self { 22 | sample_rate, 23 | channels, 24 | buffer: Vec::new(), 25 | } 26 | } 27 | 28 | pub fn push_samples(&mut self, samples: &[i16]) { 29 | self.buffer.extend_from_slice(samples); 30 | } 31 | 32 | pub fn sample_rate(&self) -> u32 { 33 | self.sample_rate 34 | } 35 | 36 | pub fn channels(&self) -> u16 { 37 | self.channels 38 | } 39 | 40 | pub fn take_buffer(&mut self) -> Vec { 41 | std::mem::take(&mut self.buffer) 42 | } 43 | } 44 | 45 | impl Buf for Linear16AudioSource { 46 | type Sample = i16; 47 | 48 | type Channel<'this> 49 | = LinearChannel<'this, i16> 50 | where 51 | Self: 'this; 52 | 53 | type IterChannels<'this> 54 | = std::vec::IntoIter> 55 | where 56 | Self: 'this; 57 | 58 | fn frames_hint(&self) -> Option { 59 | Some(self.buffer.len() / self.channels as usize) 60 | } 61 | 62 | fn channels(&self) -> usize { 63 | self.channels as usize 64 | } 65 | 66 | fn get_channel(&self, channel: usize) -> Option> { 67 | if channel < self.channels as usize { 68 | Some(LinearChannel::new(&self.buffer[channel..])) 69 | } else { 70 | None 71 | } 72 | } 73 | 74 | fn iter_channels(&self) -> Self::IterChannels<'_> { 75 | (0..self.channels as usize) 76 | .map(|channel| LinearChannel::new(&self.buffer[channel..])) 77 | .collect::>() 78 | .into_iter() 79 | } 80 | } 81 | 82 | pub fn play_audio(sink: &Sink, sample_rate: u32, channels: u16, samples: Vec) { 83 | // Create a rodio source from the raw audio data 84 | let source = SamplesBuffer::new(channels, sample_rate, samples); 85 | 86 | // Play the audio 87 | sink.append(source); 88 | } 89 | 90 | #[tokio::main] 91 | async fn main() -> Result<(), DeepgramError> { 92 | let deepgram_api_key = 93 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 94 | 95 | let dg_client = Deepgram::new(&deepgram_api_key)?; 96 | 97 | let sample_rate = 16000; 98 | let channels = 1; 99 | 100 | let options = Options::builder() 101 | .model(Model::AuraAsteriaEn) 102 | .encoding(Encoding::Linear16) 103 | .sample_rate(sample_rate) 104 | .container(Container::Wav) 105 | .build(); 106 | 107 | let text = "Hello, how can I help you today? This is a longer sentence to increase the time taken to process the audio, so that the streaming shows the full delta vs downloading the whole file."; 108 | 109 | // Record the start time 110 | let start_time = Instant::now(); 111 | 112 | let audio_stream = dg_client 113 | .text_to_speech() 114 | .speak_to_stream(text, &options) 115 | .await?; 116 | 117 | // Set up audio output 118 | let (_stream, stream_handle) = OutputStream::try_default().unwrap(); 119 | let sink = Sink::try_new(&stream_handle).unwrap(); 120 | 121 | // Create the audio source 122 | let mut source = Linear16AudioSource::new(sample_rate, channels); 123 | 124 | // Use the audio_stream for streaming audio and play it 125 | let mut stream = audio_stream; 126 | let mut buffer = BytesMut::new(); 127 | let mut extra_byte: Option = None; 128 | 129 | // Define a threshold for the buffer (e.g., 32000 bytes for 1 second) 130 | let buffer_threshold = 0; // increase for slow networks 131 | 132 | // Flag to indicate if timing information has been printed 133 | let mut time_to_first_byte_printed = false; 134 | 135 | // Accumulate initial buffer 136 | while let Some(data) = stream.next().await { 137 | // Print timing information if not already printed 138 | if !time_to_first_byte_printed { 139 | let elapsed_time = start_time.elapsed(); 140 | println!("Time to first audio byte: {:.2?}", elapsed_time); 141 | time_to_first_byte_printed = true; 142 | } 143 | 144 | // Process and accumulate the audio data here 145 | buffer.extend_from_slice(&data); 146 | 147 | // Prepend the extra byte if present 148 | if let Some(byte) = extra_byte.take() { 149 | let mut new_buffer = BytesMut::with_capacity(buffer.len() + 1); 150 | new_buffer.extend_from_slice(&[byte]); 151 | new_buffer.extend_from_slice(&buffer); 152 | buffer = new_buffer; 153 | } 154 | 155 | // Check if buffer has reached the initial threshold 156 | if buffer.len() >= buffer_threshold { 157 | // Convert buffer to i16 samples and push to source 158 | if buffer.len() % 2 != 0 { 159 | extra_byte = Some(buffer.split_off(buffer.len() - 1)[0]); 160 | } 161 | 162 | let samples: Vec = buffer 163 | .chunks_exact(2) 164 | .map(|chunk| i16::from_le_bytes([chunk[0], chunk[1]])) 165 | .collect(); 166 | source.push_samples(&samples); 167 | 168 | println!("Playing {} bytes of audio data", buffer.len()); 169 | 170 | // Start playing the audio 171 | play_audio(&sink, sample_rate, channels, source.take_buffer()); 172 | 173 | // Clear the buffer 174 | buffer.clear(); 175 | } 176 | } 177 | 178 | // Play any remaining buffered data 179 | if !buffer.is_empty() { 180 | // Prepend the extra byte if present 181 | if let Some(byte) = extra_byte { 182 | let mut new_buffer = BytesMut::with_capacity(buffer.len() + 1); 183 | new_buffer.extend_from_slice(&[byte]); 184 | new_buffer.extend_from_slice(&buffer); 185 | buffer = new_buffer; 186 | } 187 | 188 | let samples: Vec = buffer 189 | .chunks_exact(2) 190 | .map(|chunk| i16::from_le_bytes([chunk[0], chunk[1]])) 191 | .collect(); 192 | source.push_samples(&samples); 193 | 194 | // Play the remaining audio 195 | play_audio(&sink, sample_rate, channels, source.take_buffer()); 196 | } 197 | 198 | println!("Received all audio data"); 199 | 200 | // Ensure all audio is played before exiting 201 | sink.sleep_until_end(); 202 | 203 | Ok(()) 204 | } 205 | -------------------------------------------------------------------------------- /examples/transcription/rest/callback.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{ 4 | common::{ 5 | audio_source::AudioSource, 6 | options::{Language, Options}, 7 | }, 8 | Deepgram, DeepgramError, 9 | }; 10 | 11 | static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 12 | 13 | #[tokio::main] 14 | async fn main() -> Result<(), DeepgramError> { 15 | let deepgram_api_key = 16 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 17 | 18 | let dg_client = Deepgram::new(&deepgram_api_key)?; 19 | 20 | let source = AudioSource::from_url(AUDIO_URL); 21 | 22 | let options = Options::builder() 23 | .punctuate(true) 24 | .language(Language::en_US) 25 | .build(); 26 | 27 | let callback_url = 28 | env::var("DEEPGRAM_CALLBACK_URL").expect("DEEPGRAM_CALLBACK_URL environmental variable"); 29 | 30 | let response = dg_client 31 | .transcription() 32 | .prerecorded_callback(source, &options, &callback_url) 33 | .await?; 34 | 35 | println!("{}", response.request_id); 36 | 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /examples/transcription/rest/make_prerecorded_request_builder.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{ 4 | common::{ 5 | audio_source::AudioSource, 6 | batch_response::Response, 7 | options::{Language, Options}, 8 | }, 9 | Deepgram, DeepgramError, 10 | }; 11 | 12 | static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 13 | 14 | #[tokio::main] 15 | async fn main() -> Result<(), DeepgramError> { 16 | let deepgram_api_key = 17 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 18 | 19 | let dg_client = Deepgram::new(&deepgram_api_key)?; 20 | 21 | let source = AudioSource::from_url(AUDIO_URL); 22 | 23 | let options = Options::builder() 24 | .punctuate(true) 25 | .language(Language::en_US) 26 | .build(); 27 | 28 | let request_builder = dg_client 29 | .transcription() 30 | .make_prerecorded_request_builder(source, &options); 31 | 32 | // Customize the RequestBuilder here 33 | let customized_request_builder = request_builder 34 | .query(&[("custom_query_key", "custom_query_value")]) 35 | .header("custom_header_key", "custom_header_value"); 36 | 37 | // It is necessary to annotate the type of response here 38 | // That way it knows what type to deserialize the JSON into 39 | let response: Response = customized_request_builder.send().await?.json().await?; 40 | 41 | let transcript = &response.results.channels[0].alternatives[0].transcript; 42 | println!("{}", transcript); 43 | 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /examples/transcription/rest/prerecorded_from_file.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use deepgram::{ 4 | common::{ 5 | audio_source::AudioSource, 6 | options::{Language, Options}, 7 | }, 8 | Deepgram, DeepgramError, 9 | }; 10 | use tokio::fs::File; 11 | 12 | static PATH_TO_FILE: &str = "examples/audio/bueller.wav"; 13 | 14 | #[tokio::main] 15 | async fn main() -> Result<(), DeepgramError> { 16 | let deepgram_api_key = 17 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 18 | 19 | let dg_client = Deepgram::new(&deepgram_api_key)?; 20 | 21 | let file = File::open(PATH_TO_FILE).await.unwrap(); 22 | 23 | let source = AudioSource::from_buffer_with_mime_type(file, "audio/wav"); 24 | 25 | let options = Options::builder() 26 | .punctuate(true) 27 | .language(Language::en_US) 28 | .build(); 29 | 30 | let response = dg_client 31 | .transcription() 32 | .prerecorded(source, &options) 33 | .await?; 34 | 35 | let transcript = &response.results.channels[0].alternatives[0].transcript; 36 | println!("{}", transcript); 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /examples/transcription/rest/prerecorded_from_url.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, env}; 2 | 3 | use deepgram::{ 4 | common::{ 5 | audio_source::AudioSource, 6 | options::{CustomIntentMode, DetectLanguage, Encoding, Language, Model, Options, Redact}, 7 | }, 8 | Deepgram, DeepgramError, 9 | }; 10 | 11 | static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 12 | 13 | #[tokio::main] 14 | async fn main() -> Result<(), DeepgramError> { 15 | let deepgram_api_key = 16 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 17 | 18 | let dg_client = Deepgram::new(&deepgram_api_key)?; 19 | 20 | let source = AudioSource::from_url(AUDIO_URL); 21 | 22 | let options = Options::builder() 23 | .model(Model::CustomId(String::from("nova-2-general"))) 24 | .punctuate(true) 25 | .paragraphs(true) 26 | .redact([Redact::Pci, Redact::Other(String::from("cvv"))]) 27 | .detect_language(DetectLanguage::Restricted(vec![Language::en, Language::es])) 28 | .diarize(true) 29 | .diarize_version("2021-07-14.0") 30 | .filler_words(true) 31 | .smart_format(true) 32 | .encoding(Encoding::Linear16) 33 | .language(Language::en_US) 34 | .detect_entities(true) 35 | .intents(true) 36 | .custom_intent_mode(CustomIntentMode::Extended) 37 | .custom_intents(["Phone repair", "Phone cancellation"]) 38 | .sentiment(true) 39 | .topics(true) 40 | .custom_intent_mode(CustomIntentMode::Strict) 41 | .custom_intents(["Get support", "Complain"]) 42 | .summarize(true) 43 | .dictation(true) 44 | .measurements(true) 45 | .extra(HashMap::from([("key".to_string(), "value".to_string())])) 46 | .build(); 47 | 48 | let response = dg_client 49 | .transcription() 50 | .prerecorded(source, &options) 51 | .await?; 52 | 53 | let transcript = &response.results.channels[0].alternatives[0].transcript; 54 | println!("{}", transcript); 55 | 56 | println!("{:?}", response); 57 | 58 | Ok(()) 59 | } 60 | -------------------------------------------------------------------------------- /examples/transcription/websocket/callback_stream.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::time::Duration; 3 | 4 | use futures::stream::StreamExt; 5 | 6 | use deepgram::{ 7 | common::options::{Encoding, Endpointing, Language, Options}, 8 | Deepgram, DeepgramError, 9 | }; 10 | 11 | static PATH_TO_FILE: &str = "examples/audio/bueller.wav"; 12 | static AUDIO_CHUNK_SIZE: usize = 3174; 13 | static FRAME_DELAY: Duration = Duration::from_millis(16); 14 | 15 | #[tokio::main] 16 | async fn main() -> Result<(), DeepgramError> { 17 | let deepgram_api_key = 18 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 19 | 20 | let dg_client = Deepgram::new(&deepgram_api_key)?; 21 | 22 | let options = Options::builder() 23 | .smart_format(true) 24 | .language(Language::en_US) 25 | .build(); 26 | 27 | let callback_url = env::var("DEEPGRAM_CALLBACK_URL") 28 | .expect("DEEPGRAM_CALLBACK_URL environmental variable") 29 | .parse() 30 | .expect("DEEPGRAM_CALLBACK_URL not a valid URL"); 31 | 32 | let mut results = dg_client 33 | .transcription() 34 | .stream_request_with_options(options) 35 | .keep_alive() 36 | .encoding(Encoding::Linear16) 37 | .sample_rate(44100) 38 | .channels(2) 39 | .endpointing(Endpointing::CustomDurationMs(300)) 40 | .interim_results(true) 41 | .utterance_end_ms(1000) 42 | .vad_events(true) 43 | .no_delay(true) 44 | .callback(callback_url) 45 | .file(PATH_TO_FILE, AUDIO_CHUNK_SIZE, FRAME_DELAY) 46 | .await?; 47 | 48 | println!("Deepgram Request ID: {}", results.request_id()); 49 | while let Some(result) = results.next().await { 50 | println!("got: {:?}", result); 51 | } 52 | 53 | Ok(()) 54 | } 55 | -------------------------------------------------------------------------------- /examples/transcription/websocket/microphone_stream.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::thread; 3 | 4 | use bytes::{BufMut, Bytes, BytesMut}; 5 | use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; 6 | use cpal::Sample; 7 | use crossbeam::channel::RecvError; 8 | use deepgram::common::options::Encoding; 9 | use futures::channel::mpsc::{self, Receiver as FuturesReceiver}; 10 | use futures::stream::StreamExt; 11 | use futures::SinkExt; 12 | 13 | use deepgram::{Deepgram, DeepgramError}; 14 | 15 | fn microphone_as_stream() -> FuturesReceiver> { 16 | let (sync_tx, sync_rx) = crossbeam::channel::unbounded(); 17 | let (mut async_tx, async_rx) = mpsc::channel(1); 18 | 19 | thread::spawn(move || { 20 | let host = cpal::default_host(); 21 | let device = host.default_input_device().unwrap(); 22 | 23 | // let config = device.supported_input_configs().unwrap(); 24 | // for config in config { 25 | // dbg!(&config); 26 | // } 27 | 28 | let config = device.default_input_config().unwrap(); 29 | 30 | // dbg!(&config); 31 | 32 | let stream = match config.sample_format() { 33 | cpal::SampleFormat::F32 => device 34 | .build_input_stream( 35 | &config.into(), 36 | move |data: &[f32], _: &_| { 37 | let mut bytes = BytesMut::with_capacity(data.len() * 2); 38 | for sample in data { 39 | bytes.put_i16_le(sample.to_i16()); 40 | } 41 | sync_tx.send(bytes.freeze()).unwrap(); 42 | }, 43 | |_| panic!(), 44 | ) 45 | .unwrap(), 46 | cpal::SampleFormat::I16 => device 47 | .build_input_stream( 48 | &config.into(), 49 | move |data: &[i16], _: &_| { 50 | let mut bytes = BytesMut::with_capacity(data.len() * 2); 51 | for sample in data { 52 | bytes.put_i16_le(*sample); 53 | } 54 | sync_tx.send(bytes.freeze()).unwrap(); 55 | }, 56 | |_| panic!(), 57 | ) 58 | .unwrap(), 59 | cpal::SampleFormat::U16 => device 60 | .build_input_stream( 61 | &config.into(), 62 | move |data: &[u16], _: &_| { 63 | let mut bytes = BytesMut::with_capacity(data.len() * 2); 64 | for sample in data { 65 | bytes.put_i16_le(sample.to_i16()); 66 | } 67 | sync_tx.send(bytes.freeze()).unwrap(); 68 | }, 69 | |_| panic!(), 70 | ) 71 | .unwrap(), 72 | }; 73 | 74 | stream.play().unwrap(); 75 | 76 | loop { 77 | thread::park(); 78 | } 79 | }); 80 | 81 | tokio::spawn(async move { 82 | loop { 83 | let data = sync_rx.recv(); 84 | async_tx.send(data).await.unwrap(); 85 | } 86 | }); 87 | 88 | async_rx 89 | } 90 | 91 | #[tokio::main] 92 | async fn main() -> Result<(), DeepgramError> { 93 | let deepgram_api_key = 94 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 95 | 96 | let dg_client = Deepgram::new(&deepgram_api_key)?; 97 | 98 | let mut results = dg_client 99 | .transcription() 100 | .stream_request() 101 | .keep_alive() 102 | .encoding(Encoding::Linear16) 103 | // TODO Specific to my machine, not general enough example. 104 | .sample_rate(44100) 105 | // TODO Specific to my machine, not general enough example. 106 | .channels(2) 107 | .stream(microphone_as_stream()) 108 | .await?; 109 | 110 | println!("Deepgram Request ID: {}", results.request_id()); 111 | while let Some(result) = results.next().await { 112 | println!("got: {:?}", result); 113 | } 114 | 115 | Ok(()) 116 | } 117 | -------------------------------------------------------------------------------- /examples/transcription/websocket/simple_stream.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::time::Duration; 3 | 4 | use futures::stream::StreamExt; 5 | 6 | use deepgram::{ 7 | common::options::{Encoding, Endpointing, Language, Options}, 8 | Deepgram, DeepgramError, 9 | }; 10 | 11 | static PATH_TO_FILE: &str = "examples/audio/bueller.wav"; 12 | static AUDIO_CHUNK_SIZE: usize = 3174; 13 | static FRAME_DELAY: Duration = Duration::from_millis(16); 14 | 15 | #[tokio::main] 16 | async fn main() -> Result<(), DeepgramError> { 17 | let deepgram_api_key = 18 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 19 | 20 | let dg_client = Deepgram::new(&deepgram_api_key)?; 21 | 22 | let options = Options::builder() 23 | .smart_format(true) 24 | .language(Language::en_US) 25 | .build(); 26 | 27 | let mut results = dg_client 28 | .transcription() 29 | .stream_request_with_options(options) 30 | .keep_alive() 31 | .encoding(Encoding::Linear16) 32 | .sample_rate(44100) 33 | .channels(2) 34 | .endpointing(Endpointing::CustomDurationMs(300)) 35 | .interim_results(true) 36 | .utterance_end_ms(1000) 37 | .vad_events(true) 38 | .no_delay(true) 39 | .file(PATH_TO_FILE, AUDIO_CHUNK_SIZE, FRAME_DELAY) 40 | .await?; 41 | 42 | println!("Deepgram Request ID: {}", results.request_id()); 43 | while let Some(result) = results.next().await { 44 | println!("got: {:?}", result); 45 | } 46 | 47 | Ok(()) 48 | } 49 | -------------------------------------------------------------------------------- /src/common/audio_source.rs: -------------------------------------------------------------------------------- 1 | //! Sources of audio that can be transcribed. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 6 | 7 | use reqwest::{header::CONTENT_TYPE, RequestBuilder}; 8 | use serde::Serialize; 9 | 10 | /// Used as a parameter for [`Transcription::prerecorded`](crate::Transcription::prerecorded) and similar functions. 11 | #[derive(Debug)] 12 | pub struct AudioSource(InternalAudioSource); 13 | 14 | #[derive(Debug)] 15 | enum InternalAudioSource { 16 | Url(String), 17 | Buffer { 18 | buffer: reqwest::Body, 19 | mime_type: Option, 20 | }, 21 | } 22 | 23 | impl AudioSource { 24 | /// Constructs an [`AudioSource`] that will instruct Deepgram to download the audio from the specified URL. 25 | pub fn from_url(url: impl Into) -> Self { 26 | Self(InternalAudioSource::Url(url.into())) 27 | } 28 | 29 | /// Constructs an [`AudioSource`] that will upload the raw binary audio data to Deepgram as part of the request. 30 | /// 31 | /// The buffer can be any type that implements [`Into`], such as a [`tokio::fs::File`]. 32 | /// See [trait implementations for `reqwest::Body`](reqwest::Body#trait-implementations) 33 | /// for a list of types that already implement it. 34 | /// 35 | /// Use [`AudioSource::from_buffer_with_mime_type`] if you want to specify a [MIME type][mime]. 36 | /// 37 | /// [mime]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#audio_and_video_types 38 | pub fn from_buffer(buffer: impl Into) -> Self { 39 | Self(InternalAudioSource::Buffer { 40 | buffer: buffer.into(), 41 | mime_type: None, 42 | }) 43 | } 44 | 45 | /// Same as [`AudioSource::from_buffer`], but allows you to specify a [MIME type][mime]. 46 | /// 47 | /// [mime]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#audio_and_video_types 48 | pub fn from_buffer_with_mime_type( 49 | buffer: impl Into, 50 | mime_type: impl Into, 51 | ) -> Self { 52 | Self(InternalAudioSource::Buffer { 53 | buffer: buffer.into(), 54 | mime_type: Some(mime_type.into()), 55 | }) 56 | } 57 | 58 | #[allow(missing_docs)] 59 | pub fn fill_body(self, request_builder: RequestBuilder) -> RequestBuilder { 60 | match self.0 { 61 | InternalAudioSource::Url(url) => { 62 | #[derive(Serialize)] 63 | struct UrlSource { 64 | url: String, 65 | } 66 | 67 | request_builder.json(&UrlSource { url }) 68 | } 69 | InternalAudioSource::Buffer { buffer, mime_type } => { 70 | let request_builder = request_builder.body(buffer); 71 | 72 | if let Some(mime_type) = mime_type { 73 | request_builder.header(CONTENT_TYPE, mime_type) 74 | } else { 75 | request_builder 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/common/batch_response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram pre-recorded transcription API response types. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded-responses 6 | 7 | use serde::{Deserialize, Serialize}; 8 | use uuid::Uuid; 9 | 10 | /// Returned by [`Transcription::prerecorded`](crate::Transcription::prerecorded). 11 | /// 12 | /// See the [Deepgram API Reference][api] for more info. 13 | /// 14 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 15 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 16 | #[non_exhaustive] 17 | pub struct Response { 18 | #[allow(missing_docs)] 19 | pub metadata: ListenMetadata, 20 | 21 | #[allow(missing_docs)] 22 | pub results: ListenResults, 23 | } 24 | 25 | /// Returned by [`Transcription::prerecorded_callback`](crate::Transcription::prerecorded_callback). 26 | /// 27 | /// See the [Deepgram Callback feature docs][docs] for more info. 28 | /// 29 | /// [docs]: https://developers.deepgram.com/documentation/features/callback/ 30 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 31 | #[non_exhaustive] 32 | pub struct CallbackResponse { 33 | #[allow(missing_docs)] 34 | pub request_id: Uuid, 35 | } 36 | 37 | /// Metadata about the transcription. 38 | /// 39 | /// See the [Deepgram API Reference][api] for more info. 40 | /// 41 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 42 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 43 | #[non_exhaustive] 44 | pub struct ListenMetadata { 45 | #[allow(missing_docs)] 46 | pub request_id: Uuid, 47 | 48 | #[allow(missing_docs)] 49 | pub transaction_key: String, 50 | 51 | #[allow(missing_docs)] 52 | pub sha256: String, 53 | 54 | #[allow(missing_docs)] 55 | pub created: String, 56 | 57 | #[allow(missing_docs)] 58 | pub duration: f64, 59 | 60 | #[allow(missing_docs)] 61 | pub channels: usize, 62 | } 63 | 64 | /// Transcription results. 65 | /// 66 | /// See the [Deepgram API Reference][api] for more info. 67 | /// 68 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 69 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 70 | #[non_exhaustive] 71 | pub struct ListenResults { 72 | #[allow(missing_docs)] 73 | pub channels: Vec, 74 | 75 | /// [`None`] unless the [Utterances feature][docs] is set. 76 | /// 77 | /// [docs]: https://developers.deepgram.com/documentation/features/utterances/ 78 | pub utterances: Option>, 79 | 80 | #[allow(missing_docs)] 81 | pub intents: Option, 82 | 83 | #[allow(missing_docs)] 84 | pub sentiments: Option, 85 | 86 | #[allow(missing_docs)] 87 | pub topics: Option, 88 | 89 | #[allow(missing_docs)] 90 | pub summary: Option, 91 | } 92 | 93 | /// Transcription results for a single audio channel. 94 | /// 95 | /// See the [Deepgram API Reference][api] 96 | /// and the [Deepgram Multichannel feature docs][docs] for more info. 97 | /// 98 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 99 | /// [docs]: https://developers.deepgram.com/documentation/features/multichannel/ 100 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 101 | #[non_exhaustive] 102 | pub struct ChannelResult { 103 | /// [`None`] unless the [Search feature][docs] is set. 104 | /// 105 | /// [docs]: https://developers.deepgram.com/docs/search/ 106 | pub search: Option>, 107 | 108 | #[allow(missing_docs)] 109 | pub alternatives: Vec, 110 | 111 | /// [BCP-47][bcp47] language tag for the dominant language identified in the channel. 112 | /// 113 | /// [`None`] unless the [Language Detection feature][docs] is set. 114 | /// 115 | /// [bcp47]: https://tools.ietf.org/html/bcp47 116 | /// [docs]: https://developers.deepgram.com/docs/language-detection/ 117 | pub detected_language: Option, 118 | } 119 | 120 | /// Transcription results for a single utterance. 121 | /// 122 | /// See the [Deepgram Utterance feature docs][docs] for more info. 123 | /// 124 | /// [docs]: https://developers.deepgram.com/documentation/features/utterances/ 125 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 126 | #[non_exhaustive] 127 | pub struct Utterance { 128 | #[allow(missing_docs)] 129 | pub start: f64, 130 | 131 | #[allow(missing_docs)] 132 | pub end: f64, 133 | 134 | #[allow(missing_docs)] 135 | pub confidence: f64, 136 | 137 | #[allow(missing_docs)] 138 | pub channel: usize, 139 | 140 | #[allow(missing_docs)] 141 | pub transcript: String, 142 | 143 | #[allow(missing_docs)] 144 | pub words: Vec, 145 | 146 | /// [`None`] unless the [Diarization feature][docs] is set. 147 | /// 148 | /// [docs]: https://developers.deepgram.com/docs/diarization 149 | pub speaker: Option, 150 | 151 | #[allow(missing_docs)] 152 | pub id: Uuid, 153 | } 154 | 155 | /// Search results. 156 | /// 157 | /// See the [Deepgram API Reference][api] 158 | /// and the [Deepgram Search feature docs][docs] for more info. 159 | /// 160 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 161 | /// [docs]: https://developers.deepgram.com/documentation/features/search/ 162 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 163 | #[non_exhaustive] 164 | pub struct SearchResults { 165 | #[allow(missing_docs)] 166 | pub query: String, 167 | 168 | #[allow(missing_docs)] 169 | pub hits: Vec, 170 | } 171 | 172 | /// Sentence 173 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 174 | pub struct Sentence { 175 | text: String, 176 | start: f64, 177 | end: f64, 178 | } 179 | 180 | /// Paragraph 181 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 182 | pub struct Paragraph { 183 | sentences: Vec, 184 | num_words: usize, 185 | start: f64, 186 | end: f64, 187 | } 188 | 189 | /// Paragraph results. 190 | /// 191 | /// See the [Deepgram API Reference][api] 192 | /// and the [Deepgram Search feature docs][docs] for more info. 193 | /// 194 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 195 | /// [docs]: https://developers.deepgram.com/docs/paragraphs 196 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 197 | pub struct Paragraphs { 198 | transcript: String, 199 | paragraphs: Vec, 200 | } 201 | 202 | /// Entity Detection results. 203 | /// 204 | /// See the [Deepgram API Reference][api] 205 | /// and the [Deepgram Search feature docs][docs] for more info. 206 | /// 207 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 208 | /// [docs]: https://developers.deepgram.com/docs/detect-entities 209 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 210 | pub struct Entity { 211 | label: String, 212 | value: String, 213 | confidence: f64, 214 | start_word: usize, 215 | end_word: usize, 216 | } 217 | 218 | /// Intent 219 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 220 | pub struct Intent { 221 | intent: String, 222 | confidence_score: f64, 223 | } 224 | 225 | /// Segment 226 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 227 | pub struct Segment { 228 | text: String, 229 | start_word: usize, 230 | end_word: usize, 231 | intents: Vec, 232 | } 233 | 234 | /// Intent Recognition results. 235 | /// 236 | /// See the [Deepgram API Reference][api] 237 | /// and the [Deepgram Search feature docs][docs] for more info. 238 | /// 239 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 240 | /// [docs]: https://developers.deepgram.com/docs/intent-recognition 241 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 242 | pub struct Intents { 243 | segments: Vec, 244 | } 245 | 246 | /// SentimentSegment 247 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 248 | pub struct SentimentSegment { 249 | text: String, 250 | start_word: usize, 251 | end_word: usize, 252 | sentiment: String, 253 | sentiment_score: f64, 254 | } 255 | 256 | /// SentimentAverage 257 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 258 | pub struct SentimentAverage { 259 | sentiment: String, 260 | sentiment_score: f64, 261 | } 262 | 263 | /// Sentiment Analysis results. 264 | /// 265 | /// See the [Deepgram API Reference][api] 266 | /// and the [Deepgram Search feature docs][docs] for more info. 267 | /// 268 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 269 | /// [docs]: https://developers.deepgram.com/docs/sentiment-analysis 270 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 271 | pub struct Sentiments { 272 | segments: Vec, 273 | average: SentimentAverage, 274 | } 275 | 276 | /// TopicDetail 277 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 278 | pub struct TopicDetail { 279 | topic: String, 280 | confidence_score: f64, 281 | } 282 | 283 | /// TopicSegment 284 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 285 | pub struct TopicSegment { 286 | text: String, 287 | start_word: usize, 288 | end_word: usize, 289 | topics: Vec, 290 | } 291 | 292 | /// Topics Detection results. 293 | /// 294 | /// See the [Deepgram API Reference][api] 295 | /// and the [Deepgram Search feature docs][docs] for more info. 296 | /// 297 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 298 | /// [docs]: https://developers.deepgram.com/docs/topic-detection 299 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 300 | pub struct Topics { 301 | segments: Vec, 302 | } 303 | 304 | /// Summary results. 305 | /// 306 | /// See the [Deepgram API Reference][api] 307 | /// and the [Deepgram Search feature docs][docs] for more info. 308 | /// 309 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 310 | /// [docs]: https://developers.deepgram.com/docs/summarization 311 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 312 | pub struct Summary { 313 | result: String, 314 | short: String, 315 | } 316 | 317 | /// Transcript alternatives. 318 | /// 319 | /// See the [Deepgram API Reference][api] for more info. 320 | /// 321 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 322 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 323 | #[non_exhaustive] 324 | pub struct ResultAlternative { 325 | #[allow(missing_docs)] 326 | pub transcript: String, 327 | 328 | #[allow(missing_docs)] 329 | pub confidence: f64, 330 | 331 | #[allow(missing_docs)] 332 | pub words: Vec, 333 | 334 | #[allow(missing_docs)] 335 | pub paragraphs: Option, 336 | 337 | #[allow(missing_docs)] 338 | pub entities: Option>, 339 | } 340 | 341 | /// A single transcribed word. 342 | /// 343 | /// See the [Deepgram API Reference][api] for more info. 344 | /// 345 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 346 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 347 | #[non_exhaustive] 348 | pub struct Word { 349 | #[allow(missing_docs)] 350 | pub word: String, 351 | 352 | #[allow(missing_docs)] 353 | pub start: f64, 354 | 355 | #[allow(missing_docs)] 356 | pub end: f64, 357 | 358 | #[allow(missing_docs)] 359 | pub confidence: f64, 360 | 361 | /// [`None`] unless the [Diarization feature][docs] is set. 362 | /// 363 | /// [docs]: https://developers.deepgram.com/documentation/features/diarize/ 364 | pub speaker: Option, 365 | 366 | /// [`None`] unless the [Punctuation feature][docs] is set. 367 | /// 368 | /// [docs]: https://developers.deepgram.com/documentation/features/punctuate/ 369 | pub punctuated_word: Option, 370 | } 371 | 372 | /// Search result. 373 | /// 374 | /// See the [Deepgram API Reference][api] 375 | /// and the [Deepgram Search feature docs][docs] for more info. 376 | /// 377 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 378 | /// [docs]: https://developers.deepgram.com/documentation/features/search/ 379 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 380 | #[non_exhaustive] 381 | pub struct Hit { 382 | #[allow(missing_docs)] 383 | pub confidence: f64, 384 | 385 | #[allow(missing_docs)] 386 | pub start: f64, 387 | 388 | #[allow(missing_docs)] 389 | pub end: f64, 390 | 391 | #[allow(missing_docs)] 392 | pub snippet: String, 393 | } 394 | -------------------------------------------------------------------------------- /src/common/mod.rs: -------------------------------------------------------------------------------- 1 | //! Common lib for other modules 2 | 3 | pub mod audio_source; 4 | pub mod batch_response; 5 | pub mod options; 6 | pub mod stream_response; 7 | -------------------------------------------------------------------------------- /src/common/stream_response.rs: -------------------------------------------------------------------------------- 1 | //! Stream Response module 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// A single transcribed word. 6 | /// 7 | /// See the [Deepgram API Reference][api] for more info. 8 | /// 9 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 10 | #[derive(Debug, Serialize, Deserialize)] 11 | pub struct Word { 12 | #[allow(missing_docs)] 13 | pub word: String, 14 | 15 | #[allow(missing_docs)] 16 | pub start: f64, 17 | 18 | #[allow(missing_docs)] 19 | pub end: f64, 20 | 21 | #[allow(missing_docs)] 22 | pub confidence: f64, 23 | 24 | #[allow(missing_docs)] 25 | pub speaker: Option, 26 | 27 | #[allow(missing_docs)] 28 | pub punctuated_word: Option, 29 | } 30 | 31 | /// Transcript alternatives. 32 | /// 33 | /// See the [Deepgram API Reference][api] for more info. 34 | /// 35 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 36 | #[derive(Debug, Serialize, Deserialize)] 37 | pub struct Alternatives { 38 | #[allow(missing_docs)] 39 | pub transcript: String, 40 | 41 | #[allow(missing_docs)] 42 | pub words: Vec, 43 | 44 | #[allow(missing_docs)] 45 | pub confidence: f64, 46 | } 47 | 48 | /// Transcription results for a single audio channel. 49 | /// 50 | /// See the [Deepgram API Reference][api] 51 | /// and the [Deepgram Multichannel feature docs][docs] for more info. 52 | /// 53 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 54 | /// [docs]: https://developers.deepgram.com/documentation/features/multichannel/ 55 | #[derive(Debug, Serialize, Deserialize)] 56 | pub struct Channel { 57 | #[allow(missing_docs)] 58 | pub alternatives: Vec, 59 | } 60 | 61 | /// Modle info 62 | #[derive(Debug, Serialize, Deserialize)] 63 | pub struct ModelInfo { 64 | #[allow(missing_docs)] 65 | pub name: String, 66 | 67 | #[allow(missing_docs)] 68 | pub version: String, 69 | 70 | #[allow(missing_docs)] 71 | pub arch: String, 72 | } 73 | 74 | /// Metadata about the transcription. 75 | /// 76 | /// See the [Deepgram API Reference][api] for more info. 77 | /// 78 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 79 | #[derive(Debug, Serialize, Deserialize)] 80 | pub struct Metadata { 81 | #[allow(missing_docs)] 82 | pub request_id: String, 83 | 84 | #[allow(missing_docs)] 85 | pub model_info: ModelInfo, 86 | 87 | #[allow(missing_docs)] 88 | pub model_uuid: String, 89 | } 90 | 91 | /// Possible websocket message types 92 | #[derive(Debug, Serialize, Deserialize)] 93 | #[serde(untagged)] 94 | #[non_exhaustive] 95 | pub enum StreamResponse { 96 | #[allow(missing_docs)] 97 | TranscriptResponse { 98 | #[allow(missing_docs)] 99 | #[serde(rename = "type")] 100 | type_field: String, 101 | 102 | #[allow(missing_docs)] 103 | start: f64, 104 | 105 | #[allow(missing_docs)] 106 | duration: f64, 107 | 108 | #[allow(missing_docs)] 109 | is_final: bool, 110 | 111 | #[allow(missing_docs)] 112 | speech_final: bool, 113 | 114 | #[allow(missing_docs)] 115 | from_finalize: bool, 116 | 117 | #[allow(missing_docs)] 118 | channel: Channel, 119 | 120 | #[allow(missing_docs)] 121 | metadata: Metadata, 122 | 123 | #[allow(missing_docs)] 124 | channel_index: Vec, 125 | }, 126 | #[allow(missing_docs)] 127 | TerminalResponse { 128 | #[allow(missing_docs)] 129 | request_id: String, 130 | 131 | #[allow(missing_docs)] 132 | created: String, 133 | 134 | #[allow(missing_docs)] 135 | duration: f64, 136 | 137 | #[allow(missing_docs)] 138 | channels: u32, 139 | }, 140 | #[allow(missing_docs)] 141 | SpeechStartedResponse { 142 | #[allow(missing_docs)] 143 | #[serde(rename = "type")] 144 | type_field: String, 145 | 146 | #[allow(missing_docs)] 147 | channel: Vec, 148 | 149 | #[allow(missing_docs)] 150 | timestamp: f64, 151 | }, 152 | #[allow(missing_docs)] 153 | UtteranceEndResponse { 154 | #[allow(missing_docs)] 155 | #[serde(rename = "type")] 156 | type_field: String, 157 | 158 | #[allow(missing_docs)] 159 | channel: Vec, 160 | 161 | #[allow(missing_docs)] 162 | last_word_end: f64, 163 | }, 164 | } 165 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unsafe_code)] 2 | #![warn(missing_debug_implementations, missing_docs, clippy::cargo)] 3 | #![allow(clippy::multiple_crate_versions, clippy::derive_partial_eq_without_eq)] 4 | 5 | //! Official Rust SDK for Deepgram's automated speech recognition APIs. 6 | //! 7 | //! Get started transcribing with a [`Transcription`] object. 8 | 9 | use core::fmt; 10 | use std::io; 11 | use std::ops::Deref; 12 | 13 | use reqwest::{ 14 | header::{HeaderMap, HeaderValue}, 15 | RequestBuilder, 16 | }; 17 | use serde::de::DeserializeOwned; 18 | use thiserror::Error; 19 | use url::Url; 20 | 21 | #[cfg(feature = "listen")] 22 | pub mod common; 23 | #[cfg(feature = "listen")] 24 | pub mod listen; 25 | #[cfg(feature = "manage")] 26 | pub mod manage; 27 | #[cfg(feature = "speak")] 28 | pub mod speak; 29 | 30 | static DEEPGRAM_BASE_URL: &str = "https://api.deepgram.com"; 31 | 32 | /// Transcribe audio using Deepgram's automated speech recognition. 33 | /// 34 | /// Constructed using [`Deepgram::transcription`]. 35 | /// 36 | /// See the [Deepgram API Reference][api] for more info. 37 | /// 38 | /// [api]: https://developers.deepgram.com/api-reference/#transcription 39 | #[derive(Debug, Clone)] 40 | pub struct Transcription<'a>(#[allow(unused)] pub &'a Deepgram); 41 | 42 | /// Generate speech from text using Deepgram's text to speech api. 43 | /// 44 | /// Constructed using [`Deepgram::text_to_speech`]. 45 | /// 46 | /// See the [Deepgram API Reference][api] for more info. 47 | /// 48 | /// [api]: https://developers.deepgram.com/reference/text-to-speech-api 49 | #[derive(Debug, Clone)] 50 | pub struct Speak<'a>(#[allow(unused)] pub &'a Deepgram); 51 | 52 | impl Deepgram { 53 | /// Construct a new [`Transcription`] from a [`Deepgram`]. 54 | pub fn transcription(&self) -> Transcription<'_> { 55 | self.into() 56 | } 57 | 58 | /// Construct a new [`Speak`] from a [`Deepgram`]. 59 | pub fn text_to_speech(&self) -> Speak<'_> { 60 | self.into() 61 | } 62 | } 63 | 64 | impl<'a> From<&'a Deepgram> for Transcription<'a> { 65 | /// Construct a new [`Transcription`] from a [`Deepgram`]. 66 | fn from(deepgram: &'a Deepgram) -> Self { 67 | Self(deepgram) 68 | } 69 | } 70 | 71 | impl<'a> From<&'a Deepgram> for Speak<'a> { 72 | /// Construct a new [`Speak`] from a [`Deepgram`]. 73 | fn from(deepgram: &'a Deepgram) -> Self { 74 | Self(deepgram) 75 | } 76 | } 77 | 78 | impl Transcription<'_> { 79 | /// Expose a method to access the inner `Deepgram` reference if needed. 80 | pub fn deepgram(&self) -> &Deepgram { 81 | self.0 82 | } 83 | } 84 | 85 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] 86 | pub(crate) struct RedactedString(pub String); 87 | 88 | impl fmt::Debug for RedactedString { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | f.write_str("***") 91 | } 92 | } 93 | 94 | impl Deref for RedactedString { 95 | type Target = str; 96 | 97 | fn deref(&self) -> &Self::Target { 98 | &self.0 99 | } 100 | } 101 | 102 | /// A client for the Deepgram API. 103 | /// 104 | /// Make transcriptions requests using [`Deepgram::transcription`]. 105 | #[derive(Debug, Clone)] 106 | pub struct Deepgram { 107 | #[cfg_attr(not(feature = "listen"), allow(unused))] 108 | api_key: Option, 109 | #[cfg_attr(not(feature = "listen"), allow(unused))] 110 | base_url: Url, 111 | #[cfg_attr(not(feature = "listen"), allow(unused))] 112 | client: reqwest::Client, 113 | } 114 | 115 | /// Errors that may arise from the [`deepgram`](crate) crate. 116 | // TODO sub-errors for the different types? 117 | #[derive(Debug, Error)] 118 | #[non_exhaustive] 119 | pub enum DeepgramError { 120 | /// The Deepgram API returned an error. 121 | #[error("The Deepgram API returned an error.")] 122 | DeepgramApiError { 123 | /// Error message from the Deepgram API. 124 | body: String, 125 | 126 | /// Underlying [`reqwest::Error`] from the HTTP request. 127 | err: reqwest::Error, 128 | }, 129 | 130 | /// Something went wrong when generating the http request. 131 | #[error("Something went wrong when generating the http request: {0}")] 132 | HttpError(#[from] http::Error), 133 | 134 | /// Something went wrong when making the HTTP request. 135 | #[error("Something went wrong when making the HTTP request: {0}")] 136 | ReqwestError(#[from] reqwest::Error), 137 | 138 | /// Something went wrong during I/O. 139 | #[error("Something went wrong during I/O: {0}")] 140 | IoError(#[from] io::Error), 141 | 142 | #[cfg(feature = "listen")] 143 | /// Something went wrong with WS. 144 | #[error("Something went wrong with WS: {0}")] 145 | WsError(#[from] tungstenite::Error), 146 | 147 | /// Something went wrong during serialization/deserialization. 148 | #[error("Something went wrong during json serialization/deserialization: {0}")] 149 | JsonError(#[from] serde_json::Error), 150 | 151 | /// Something went wrong during serialization/deserialization. 152 | #[error("Something went wrong during query serialization: {0}")] 153 | UrlencodedError(#[from] serde_urlencoded::ser::Error), 154 | 155 | /// The data stream produced an error 156 | #[error("The data stream produced an error: {0}")] 157 | StreamError(#[from] Box), 158 | 159 | /// The provided base url is not valid 160 | #[error("The provided base url is not valid")] 161 | InvalidUrl, 162 | 163 | /// A websocket close from was received indicating an error 164 | #[error("websocket close frame received with error content: code: {code}, reason: {reason}")] 165 | WebsocketClose { 166 | /// The numerical code indicating the reason for the error 167 | code: u16, 168 | /// A textual description of the error reason 169 | reason: String, 170 | }, 171 | 172 | /// An unexpected error occurred in the client 173 | #[error("an unepected error occurred in the deepgram client: {0}")] 174 | InternalClientError(anyhow::Error), 175 | 176 | /// A Deepgram API server response was not in the expected format. 177 | #[error("The Deepgram API server response was not in the expected format: {0}")] 178 | UnexpectedServerResponse(anyhow::Error), 179 | } 180 | 181 | #[cfg_attr(not(feature = "listen"), allow(unused))] 182 | type Result = std::result::Result; 183 | 184 | impl Deepgram { 185 | /// Construct a new Deepgram client. 186 | /// 187 | /// The client will be pointed at Deepgram's hosted API. 188 | /// 189 | /// Create your first API key on the [Deepgram Console][console]. 190 | /// 191 | /// [console]: https://console.deepgram.com/ 192 | /// 193 | /// # Errors 194 | /// 195 | /// Errors under the same conditions as [`reqwest::ClientBuilder::build`]. 196 | pub fn new>(api_key: K) -> Result { 197 | let api_key = Some(api_key.as_ref().to_owned()); 198 | // This cannot panic because we are converting a static value 199 | // that is known-good. 200 | let base_url = DEEPGRAM_BASE_URL.try_into().unwrap(); 201 | Self::inner_constructor(base_url, api_key) 202 | } 203 | 204 | /// Construct a new Deepgram client with the specified base URL. 205 | /// 206 | /// When using a self-hosted instance of deepgram, this will be the 207 | /// host portion of your own instance. For instance, if you would 208 | /// query your deepgram instance at `http://deepgram.internal/v1/listen`, 209 | /// the base_url will be `http://deepgram.internal`. 210 | /// 211 | /// Admin features, such as billing, usage, and key management will 212 | /// still go through the hosted site at `https://api.deepgram.com`. 213 | /// 214 | /// Self-hosted instances do not in general authenticate incoming 215 | /// requests, so unlike in [`Deepgram::new`], so no api key needs to be 216 | /// provided. The SDK will not include an `Authorization` header in its 217 | /// requests. If an API key is required, consider using 218 | /// [`Deepgram::with_base_url_and_api_key`]. 219 | /// 220 | /// [console]: https://console.deepgram.com/ 221 | /// 222 | /// # Example: 223 | /// 224 | /// ``` 225 | /// # use deepgram::Deepgram; 226 | /// let deepgram = Deepgram::with_base_url( 227 | /// "http://localhost:8080", 228 | /// ); 229 | /// ``` 230 | /// 231 | /// # Errors 232 | /// 233 | /// Errors under the same conditions as [`reqwest::Client::new`], or if `base_url` 234 | /// is not a valid URL. 235 | pub fn with_base_url(base_url: U) -> Result 236 | where 237 | U: TryInto, 238 | U::Error: std::fmt::Debug, 239 | { 240 | let base_url = base_url.try_into().map_err(|_| DeepgramError::InvalidUrl)?; 241 | Self::inner_constructor(base_url, None) 242 | } 243 | 244 | /// Construct a new Deepgram client with the specified base URL and 245 | /// API Key. 246 | /// 247 | /// When using a self-hosted instance of deepgram, this will be the 248 | /// host portion of your own instance. For instance, if you would 249 | /// query your deepgram instance at `http://deepgram.internal/v1/listen`, 250 | /// the base_url will be `http://deepgram.internal`. 251 | /// 252 | /// Admin features, such as billing, usage, and key management will 253 | /// still go through the hosted site at `https://api.deepgram.com`. 254 | /// 255 | /// [console]: https://console.deepgram.com/ 256 | /// 257 | /// # Example: 258 | /// 259 | /// ``` 260 | /// # use deepgram::Deepgram; 261 | /// let deepgram = Deepgram::with_base_url_and_api_key( 262 | /// "http://localhost:8080", 263 | /// "apikey12345", 264 | /// ).unwrap(); 265 | /// ``` 266 | /// 267 | /// # Errors 268 | /// 269 | /// Errors under the same conditions as [`reqwest::ClientBuilder::build`], or if `base_url` 270 | /// is not a valid URL. 271 | pub fn with_base_url_and_api_key(base_url: U, api_key: K) -> Result 272 | where 273 | U: TryInto, 274 | U::Error: std::fmt::Debug, 275 | K: AsRef, 276 | { 277 | let base_url = base_url.try_into().map_err(|_| DeepgramError::InvalidUrl)?; 278 | Self::inner_constructor(base_url, Some(api_key.as_ref().to_owned())) 279 | } 280 | 281 | fn inner_constructor(base_url: Url, api_key: Option) -> Result { 282 | static USER_AGENT: &str = concat!( 283 | env!("CARGO_PKG_NAME"), 284 | "/", 285 | env!("CARGO_PKG_VERSION"), 286 | " rust", 287 | ); 288 | 289 | if base_url.cannot_be_a_base() { 290 | return Err(DeepgramError::InvalidUrl); 291 | } 292 | let authorization_header = { 293 | let mut header = HeaderMap::new(); 294 | if let Some(api_key) = &api_key { 295 | if let Ok(value) = HeaderValue::from_str(&format!("Token {}", api_key)) { 296 | header.insert("Authorization", value); 297 | } 298 | } 299 | header 300 | }; 301 | 302 | Ok(Deepgram { 303 | api_key: api_key.map(RedactedString), 304 | base_url, 305 | client: reqwest::Client::builder() 306 | .user_agent(USER_AGENT) 307 | .default_headers(authorization_header) 308 | .build()?, 309 | }) 310 | } 311 | } 312 | 313 | /// Sends the request and checks the response for an error. 314 | /// 315 | /// If there is an error, it translates it into a [`DeepgramError::DeepgramApiError`]. 316 | /// Otherwise, it deserializes the JSON accordingly. 317 | #[cfg_attr(not(feature = "listen"), allow(unused))] 318 | async fn send_and_translate_response( 319 | request_builder: RequestBuilder, 320 | ) -> crate::Result { 321 | let response = request_builder.send().await?; 322 | 323 | match response.error_for_status_ref() { 324 | Ok(_) => Ok(response.json().await?), 325 | Err(err) => Err(DeepgramError::DeepgramApiError { 326 | body: response.text().await?, 327 | err, 328 | }), 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /src/listen/mod.rs: -------------------------------------------------------------------------------- 1 | //! Listen module 2 | 3 | pub mod rest; 4 | pub mod websocket; 5 | -------------------------------------------------------------------------------- /src/listen/rest.rs: -------------------------------------------------------------------------------- 1 | //! Types used for pre-recorded audio transcription. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 6 | 7 | use reqwest::RequestBuilder; 8 | use url::Url; 9 | 10 | use crate::common::audio_source::AudioSource; 11 | use crate::{send_and_translate_response, Transcription}; 12 | 13 | use crate::common::batch_response::{CallbackResponse, Response}; 14 | use crate::common::options::{Options, SerializableOptions}; 15 | 16 | static DEEPGRAM_API_URL_LISTEN: &str = "v1/listen"; 17 | 18 | impl Transcription<'_> { 19 | /// Sends a request to Deepgram to transcribe pre-recorded audio. 20 | /// If you wish to use the Callback feature, you should use [`Transcription::prerecorded_callback`] instead. 21 | /// 22 | /// See the [Deepgram API Reference][api] for more info. 23 | /// 24 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 25 | /// 26 | /// # Examples 27 | /// 28 | /// ```no_run 29 | /// # use std::env; 30 | /// # 31 | /// # use deepgram::{ 32 | /// # common::{ 33 | /// # audio_source::AudioSource, 34 | /// # options::{Language, Options}, 35 | /// # }, 36 | /// # Deepgram, DeepgramError, 37 | /// # }; 38 | /// # 39 | /// # static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 40 | /// # 41 | /// # #[tokio::main] 42 | /// # async fn main() -> Result<(), DeepgramError> { 43 | /// # let deepgram_api_key = 44 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 45 | /// # 46 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 47 | /// 48 | /// let source = AudioSource::from_url(AUDIO_URL); 49 | /// 50 | /// let options = Options::builder() 51 | /// .punctuate(true) 52 | /// .language(Language::en_US) 53 | /// .build(); 54 | /// 55 | /// let response = dg_client 56 | /// .transcription() 57 | /// .prerecorded(source, &options) 58 | /// .await?; 59 | /// # 60 | /// # Ok(()) 61 | /// # } 62 | /// ``` 63 | pub async fn prerecorded( 64 | &self, 65 | source: AudioSource, 66 | options: &Options, 67 | ) -> crate::Result { 68 | let request_builder = self.make_prerecorded_request_builder(source, options); 69 | 70 | send_and_translate_response(request_builder).await 71 | } 72 | 73 | /// Sends a request to Deepgram to transcribe pre-recorded audio using the Callback feature. 74 | /// Otherwise behaves similarly to [`Transcription::prerecorded`]. 75 | /// 76 | /// See the [Deepgram Callback feature docs][docs] for more info. 77 | /// 78 | /// [docs]: https://developers.deepgram.com/documentation/features/callback/ 79 | /// 80 | /// # Examples 81 | /// 82 | /// ```no_run 83 | /// # use std::env; 84 | /// # 85 | /// # use deepgram::{ 86 | /// # common::{ 87 | /// # audio_source::AudioSource, 88 | /// # options::{Language, Options}, 89 | /// # }, 90 | /// # Deepgram, DeepgramError, 91 | /// # }; 92 | /// # 93 | /// # static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 94 | /// # 95 | /// # #[tokio::main] 96 | /// # async fn main() -> Result<(), DeepgramError> { 97 | /// # let deepgram_api_key = 98 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 99 | /// # 100 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 101 | /// 102 | /// let source = AudioSource::from_url(AUDIO_URL); 103 | /// 104 | /// let options = Options::builder() 105 | /// .punctuate(true) 106 | /// .language(Language::en_US) 107 | /// .build(); 108 | /// 109 | /// # let callback_url = 110 | /// # env::var("DEEPGRAM_CALLBACK_URL").expect("DEEPGRAM_CALLBACK_URL environmental variable"); 111 | /// # 112 | /// let response = dg_client 113 | /// .transcription() 114 | /// .prerecorded_callback(source, &options, &callback_url) 115 | /// .await?; 116 | /// # 117 | /// # Ok(()) 118 | /// # } 119 | /// ``` 120 | pub async fn prerecorded_callback( 121 | &self, 122 | source: AudioSource, 123 | options: &Options, 124 | callback: &str, 125 | ) -> crate::Result { 126 | let request_builder = 127 | self.make_prerecorded_callback_request_builder(source, options, callback); 128 | 129 | send_and_translate_response(request_builder).await 130 | } 131 | 132 | /// Makes a [`reqwest::RequestBuilder`] without actually sending the request. 133 | /// This allows you to modify the request before it is sent. 134 | /// 135 | /// Avoid using this where possible. 136 | /// By customizing the request, there is less of a guarantee that it will conform to the Deepgram API. 137 | /// Prefer using [`Transcription::prerecorded`]. 138 | /// 139 | /// # Examples 140 | /// 141 | /// ```no_run 142 | /// # use std::env; 143 | /// # 144 | /// # use deepgram::{ 145 | /// # common::{ 146 | /// # audio_source::AudioSource, 147 | /// # options::{Language, Options}, 148 | /// # batch_response::{Response}, 149 | /// # }, 150 | /// # Deepgram, DeepgramError, 151 | /// # }; 152 | /// # 153 | /// # static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 154 | /// # 155 | /// # #[tokio::main] 156 | /// # async fn main() -> Result<(), DeepgramError> { 157 | /// # 158 | /// # let deepgram_api_key = 159 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 160 | /// # 161 | /// # let dg_client = Deepgram::new(&deepgram_api_key)?; 162 | /// # 163 | /// # let source = AudioSource::from_url(AUDIO_URL); 164 | /// # 165 | /// # let options = Options::builder() 166 | /// # .punctuate(true) 167 | /// # .language(Language::en_US) 168 | /// # .build(); 169 | /// # 170 | /// let request_builder = dg_client 171 | /// .transcription() 172 | /// .make_prerecorded_request_builder(source, &options); 173 | /// 174 | /// // Customize the RequestBuilder here 175 | /// let customized_request_builder = request_builder 176 | /// .query(&[("custom_query_key", "custom_query_value")]) 177 | /// .header("custom_header_key", "custom_header_value"); 178 | /// 179 | /// // It is necessary to annotate the type of response here 180 | /// // That way it knows what type to deserialize the JSON into 181 | /// let response: Response = customized_request_builder.send().await?.json().await?; 182 | /// # 183 | /// # Ok(()) 184 | /// # } 185 | /// ``` 186 | pub fn make_prerecorded_request_builder( 187 | &self, 188 | source: AudioSource, 189 | options: &Options, 190 | ) -> RequestBuilder { 191 | let request_builder = self 192 | .0 193 | .client 194 | .post(self.listen_url()) 195 | .query(&SerializableOptions(options)); 196 | 197 | source.fill_body(request_builder) 198 | } 199 | 200 | /// Similar to [`Transcription::make_prerecorded_request_builder`], 201 | /// but for the purposes of a [callback request][callback]. 202 | /// 203 | /// You should avoid using this where possible too, preferring [`Transcription::prerecorded_callback`]. 204 | /// 205 | /// [callback]: https://developers.deepgram.com/documentation/features/callback/ 206 | /// 207 | /// # Examples 208 | /// 209 | /// ```no_run 210 | /// # use std::env; 211 | /// # 212 | /// # use deepgram::{ 213 | /// # common::{ 214 | /// # audio_source::AudioSource, 215 | /// # options::{Language, Options}, 216 | /// # batch_response::{Response, CallbackResponse}, 217 | /// # }, 218 | /// # Deepgram, DeepgramError, 219 | /// # }; 220 | /// # 221 | /// # static AUDIO_URL: &str = "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"; 222 | /// # 223 | /// # #[tokio::main] 224 | /// # async fn main() -> Result<(), DeepgramError> { 225 | /// # 226 | /// # let deepgram_api_key = 227 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 228 | /// # 229 | /// # let dg_client = Deepgram::new(&deepgram_api_key)?; 230 | /// # 231 | /// # let source = AudioSource::from_url(AUDIO_URL); 232 | /// # 233 | /// # let options = Options::builder() 234 | /// # .punctuate(true) 235 | /// # .language(Language::en_US) 236 | /// # .build(); 237 | /// # 238 | /// # let callback_url = 239 | /// # env::var("DEEPGRAM_CALLBACK_URL").expect("DEEPGRAM_CALLBACK_URL environmental variable"); 240 | /// # 241 | /// let request_builder = dg_client 242 | /// .transcription() 243 | /// .make_prerecorded_callback_request_builder(source, &options, &callback_url); 244 | /// 245 | /// // Customize the RequestBuilder here 246 | /// let customized_request_builder = request_builder 247 | /// .query(&[("custom_query_key", "custom_query_value")]) 248 | /// .header("custom_header_key", "custom_header_value"); 249 | /// 250 | /// // It is necessary to annotate the type of response here 251 | /// // That way it knows what type to deserialize the JSON into 252 | /// let response: CallbackResponse = customized_request_builder.send().await?.json().await?; 253 | /// # 254 | /// # Ok(()) 255 | /// # } 256 | /// ``` 257 | pub fn make_prerecorded_callback_request_builder( 258 | &self, 259 | source: AudioSource, 260 | options: &Options, 261 | callback: &str, 262 | ) -> RequestBuilder { 263 | self.make_prerecorded_request_builder(source, options) 264 | .query(&[("callback", callback)]) 265 | } 266 | 267 | fn listen_url(&self) -> Url { 268 | self.0.base_url.join(DEEPGRAM_API_URL_LISTEN).unwrap() 269 | } 270 | } 271 | 272 | #[cfg(test)] 273 | mod tests { 274 | use crate::Deepgram; 275 | 276 | #[test] 277 | fn listen_url() { 278 | let dg = Deepgram::new("token").unwrap(); 279 | assert_eq!( 280 | &dg.transcription().listen_url().to_string(), 281 | "https://api.deepgram.com/v1/listen" 282 | ); 283 | } 284 | 285 | #[test] 286 | fn listen_url_custom_host() { 287 | let dg = Deepgram::with_base_url("http://localhost:8888/abc/").unwrap(); 288 | assert_eq!( 289 | &dg.transcription().listen_url().to_string(), 290 | "http://localhost:8888/abc/v1/listen" 291 | ); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /src/manage/billing.rs: -------------------------------------------------------------------------------- 1 | //! Get the outstanding balances for a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#billing 6 | 7 | use crate::{ 8 | manage::billing::response::{Balance, Balances}, 9 | send_and_translate_response, Deepgram, 10 | }; 11 | 12 | pub mod response; 13 | 14 | /// Get the outstanding balances for a Deepgram Project. 15 | /// 16 | /// Constructed using [`Deepgram::billing`]. 17 | /// 18 | /// See the [Deepgram API Reference][api] for more info. 19 | /// 20 | /// [api]: https://developers.deepgram.com/api-reference/#billing 21 | #[derive(Debug, Clone)] 22 | pub struct Billing<'a>(&'a Deepgram); 23 | 24 | impl Deepgram { 25 | /// Construct a new [`Billing`] from a [`Deepgram`]. 26 | pub fn billing(&self) -> Billing<'_> { 27 | self.into() 28 | } 29 | } 30 | 31 | impl<'a> From<&'a Deepgram> for Billing<'a> { 32 | /// Construct a new [`Billing`] from a [`Deepgram`]. 33 | fn from(deepgram: &'a Deepgram) -> Self { 34 | Self(deepgram) 35 | } 36 | } 37 | 38 | impl Billing<'_> { 39 | /// Get the outstanding balances for the specified project. 40 | /// 41 | /// See the [Deepgram API Reference][api] for more info. 42 | /// 43 | /// [api]: https://developers.deepgram.com/api-reference/#billing-all 44 | /// 45 | /// # Examples 46 | /// 47 | /// ```no_run 48 | /// # use deepgram::{Deepgram, DeepgramError}; 49 | /// # use std::env; 50 | /// # 51 | /// # #[tokio::main] 52 | /// # async fn main() -> Result<(), DeepgramError> { 53 | /// # let deepgram_api_key = 54 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 55 | /// # 56 | /// # let project_id = 57 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 58 | /// # 59 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 60 | /// 61 | /// let balances = dg_client 62 | /// .billing() 63 | /// .list_balance(&project_id) 64 | /// .await?; 65 | /// # 66 | /// # Ok(()) 67 | /// # } 68 | /// ``` 69 | pub async fn list_balance(&self, project_id: &str) -> crate::Result { 70 | let url = format!( 71 | "https://api.deepgram.com/v1/projects/{}/balances", 72 | project_id, 73 | ); 74 | 75 | send_and_translate_response(self.0.client.get(url)).await 76 | } 77 | 78 | /// Get the details of a specific balance. 79 | /// 80 | /// See the [Deepgram API Reference][api] for more info. 81 | /// 82 | /// [api]: https://developers.deepgram.com/api-reference/#billing-get 83 | /// 84 | /// # Examples 85 | /// 86 | /// ```no_run 87 | /// # use deepgram::{Deepgram, DeepgramError}; 88 | /// # use std::env; 89 | /// # 90 | /// # #[tokio::main] 91 | /// # async fn main() -> Result<(), DeepgramError> { 92 | /// # let deepgram_api_key = 93 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 94 | /// # 95 | /// # let project_id = 96 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 97 | /// # 98 | /// # let balance_id = 99 | /// # env::var("DEEPGRAM_BALANCE_ID").expect("DEEPGRAM_BALANCE_ID environmental variable"); 100 | /// # 101 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 102 | /// 103 | /// let balance = dg_client 104 | /// .billing() 105 | /// .get_balance(&project_id, &balance_id) 106 | /// .await?; 107 | /// 108 | /// assert_eq!(balance_id, balance.balance_id.to_string()); 109 | /// # 110 | /// # Ok(()) 111 | /// # } 112 | /// ``` 113 | pub async fn get_balance(&self, project_id: &str, balance_id: &str) -> crate::Result { 114 | let url = format!( 115 | "https://api.deepgram.com/v1/projects/{}/balances/{}", 116 | project_id, balance_id, 117 | ); 118 | 119 | send_and_translate_response(self.0.client.get(url)).await 120 | } 121 | } 122 | 123 | #[cfg(test)] 124 | mod tests { 125 | use crate::manage::billing::response::{Balance, BillingUnits}; 126 | 127 | #[test] 128 | fn test() { 129 | assert_eq!( 130 | serde_json::from_str::( 131 | "{\"balance_id\":\"a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8\",\"amount\":1,\"units\":\"usd\",\"purchase_order_id\":\"a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8\"}", 132 | ).unwrap().units, 133 | BillingUnits::Usd 134 | ); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/manage/billing/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram billing API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use uuid::Uuid; 5 | 6 | /// The balances for a Deepgram Project. 7 | /// 8 | /// See the [Deepgram API Reference][api] for more info. 9 | /// 10 | /// [api]: https://developers.deepgram.com/api-reference/#billing 11 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 12 | #[non_exhaustive] 13 | pub struct Balances { 14 | #[allow(missing_docs)] 15 | pub balances: Vec, 16 | } 17 | 18 | /// Information about a specific balance. 19 | /// 20 | /// See the [Deepgram API Reference][api] for more info. 21 | /// 22 | /// [api]: https://developers.deepgram.com/api-reference/#billing 23 | #[allow(missing_docs)] // Struct fields are documented in the API reference 24 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 25 | #[non_exhaustive] 26 | pub struct Balance { 27 | #[allow(missing_docs)] 28 | pub balance_id: Uuid, 29 | 30 | #[allow(missing_docs)] 31 | pub amount: f64, 32 | 33 | #[allow(missing_docs)] 34 | pub units: BillingUnits, 35 | 36 | #[allow(missing_docs)] 37 | pub purchase_order_id: Uuid, 38 | } 39 | 40 | /// Units for the [`Balance::amount`] field. 41 | /// 42 | /// See the [Deepgram API Reference][api] for more info. 43 | /// 44 | /// [api]: https://developers.deepgram.com/api-reference/#billing 45 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)] 46 | #[non_exhaustive] 47 | pub enum BillingUnits { 48 | #[allow(missing_docs)] 49 | #[serde(rename = "usd")] 50 | Usd, 51 | 52 | #[allow(missing_docs)] 53 | #[serde(rename = "hour")] 54 | Hour, 55 | } 56 | -------------------------------------------------------------------------------- /src/manage/invitations.rs: -------------------------------------------------------------------------------- 1 | //! Manage the invitations to a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#invitations 6 | 7 | use crate::{send_and_translate_response, Deepgram}; 8 | 9 | use response::Message; 10 | 11 | pub mod response; 12 | 13 | /// Manage the invitations to a Deepgram Project. 14 | /// 15 | /// Constructed using [`Deepgram::invitations`]. 16 | /// 17 | /// See the [Deepgram API Reference][api] for more info. 18 | /// 19 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 20 | #[derive(Debug, Clone)] 21 | pub struct Invitations<'a>(&'a Deepgram); 22 | 23 | impl Deepgram { 24 | /// Construct a new [`Invitations`] from a [`Deepgram`]. 25 | pub fn invitations(&self) -> Invitations<'_> { 26 | self.into() 27 | } 28 | } 29 | 30 | impl<'a> From<&'a Deepgram> for Invitations<'a> { 31 | /// Construct a new [`Invitations`] from a [`Deepgram`]. 32 | fn from(deepgram: &'a Deepgram) -> Self { 33 | Self(deepgram) 34 | } 35 | } 36 | 37 | impl Invitations<'_> { 38 | /// Remove the authenticated account from the specified project. 39 | /// 40 | /// See the [Deepgram API Reference][api] for more info. 41 | /// 42 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 43 | /// 44 | /// # Examples 45 | /// 46 | /// ```no_run 47 | /// # use std::env; 48 | /// # 49 | /// # use deepgram::{Deepgram, DeepgramError}; 50 | /// # 51 | /// # #[tokio::main] 52 | /// # async fn main() -> Result<(), DeepgramError> { 53 | /// # let deepgram_api_key = 54 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 55 | /// # 56 | /// # let project_id = 57 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 58 | /// # 59 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 60 | /// 61 | /// dg_client 62 | /// .invitations() 63 | /// .leave_project(&project_id) 64 | /// .await?; 65 | /// # 66 | /// # Ok(()) 67 | /// # } 68 | /// ``` 69 | pub async fn leave_project(&self, project_id: &str) -> crate::Result { 70 | let url = format!("https://api.deepgram.com/v1/projects/{}/leave", project_id,); 71 | 72 | send_and_translate_response(self.0.client.delete(url)).await 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/manage/invitations/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram invitations API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// Success message. 6 | /// 7 | /// See the [Deepgram API Reference][api] for more info. 8 | /// 9 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 10 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 11 | #[non_exhaustive] 12 | pub struct Message { 13 | #[allow(missing_docs)] 14 | pub message: String, 15 | } 16 | -------------------------------------------------------------------------------- /src/manage/keys.rs: -------------------------------------------------------------------------------- 1 | //! Manage the keys for a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#keys 6 | 7 | use crate::{ 8 | manage::keys::{ 9 | options::{Options, SerializableOptions}, 10 | response::{MemberAndApiKey, MembersAndApiKeys, NewApiKey}, 11 | }, 12 | send_and_translate_response, Deepgram, 13 | }; 14 | 15 | use response::Message; 16 | 17 | pub mod options; 18 | pub mod response; 19 | 20 | /// Manage the keys for a Deepgram Project. 21 | /// 22 | /// Constructed using [`Deepgram::keys`]. 23 | /// 24 | /// See the [Deepgram API Reference][api] for more info. 25 | /// 26 | /// [api]: https://developers.deepgram.com/api-reference/#keys 27 | #[derive(Debug, Clone)] 28 | pub struct Keys<'a>(&'a Deepgram); 29 | 30 | impl Deepgram { 31 | /// Construct a new [`Keys`] from a [`Deepgram`]. 32 | pub fn keys(&self) -> Keys<'_> { 33 | self.into() 34 | } 35 | } 36 | 37 | impl<'a> From<&'a Deepgram> for Keys<'a> { 38 | /// Construct a new [`Keys`] from a [`Deepgram`]. 39 | fn from(deepgram: &'a Deepgram) -> Self { 40 | Self(deepgram) 41 | } 42 | } 43 | 44 | impl Keys<'_> { 45 | /// Get keys for the specified project. 46 | /// 47 | /// See the [Deepgram API Reference][api] for more info. 48 | /// 49 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-keys 50 | /// 51 | /// # Examples 52 | /// 53 | /// ```no_run 54 | /// # use std::env; 55 | /// # 56 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 57 | /// # 58 | /// # #[tokio::main] 59 | /// # async fn main() -> Result<(), DeepgramError> { 60 | /// # let deepgram_api_key = 61 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 62 | /// # 63 | /// # let project_id = 64 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 65 | /// # 66 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 67 | /// 68 | /// let keys = dg_client 69 | /// .keys() 70 | /// .list(&project_id) 71 | /// .await?; 72 | /// # 73 | /// # Ok(()) 74 | /// # } 75 | /// ``` 76 | pub async fn list(&self, project_id: &str) -> crate::Result { 77 | let url = format!("https://api.deepgram.com/v1/projects/{}/keys", project_id); 78 | 79 | send_and_translate_response(self.0.client.get(url)).await 80 | } 81 | 82 | /// Get details of the specified key. 83 | /// 84 | /// See the [Deepgram API Reference][api] for more info. 85 | /// 86 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-key 87 | /// 88 | /// # Examples 89 | /// 90 | /// ```no_run 91 | /// # use std::env; 92 | /// # 93 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 94 | /// # 95 | /// # #[tokio::main] 96 | /// # async fn main() -> Result<(), DeepgramError> { 97 | /// # let deepgram_api_key = 98 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 99 | /// # 100 | /// # let project_id = 101 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 102 | /// # 103 | /// # let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 104 | /// # 105 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 106 | /// 107 | /// let key = dg_client 108 | /// .keys() 109 | /// .get(&project_id, &key_id) 110 | /// .await?; 111 | /// # 112 | /// # Ok(()) 113 | /// # } 114 | /// ``` 115 | pub async fn get(&self, project_id: &str, key_id: &str) -> crate::Result { 116 | let url = format!( 117 | "https://api.deepgram.com/v1/projects/{}/keys/{}", 118 | project_id, key_id, 119 | ); 120 | 121 | send_and_translate_response(self.0.client.get(url)).await 122 | } 123 | 124 | /// Create a new key in the specified project. 125 | /// 126 | /// See the [Deepgram API Reference][api] for more info. 127 | /// 128 | /// [api]: https://developers.deepgram.com/api-reference/#keys-create 129 | /// 130 | /// # Examples 131 | /// 132 | /// ```no_run 133 | /// # use std::env; 134 | /// # 135 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 136 | /// # 137 | /// # #[tokio::main] 138 | /// # async fn main() -> Result<(), DeepgramError> { 139 | /// # let deepgram_api_key = 140 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 141 | /// # 142 | /// # let project_id = 143 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 144 | /// # 145 | /// # let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 146 | /// # 147 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 148 | /// 149 | /// let options = Options::builder("New Key", ["member"]).build(); 150 | /// let new_key = dg_client 151 | /// .keys() 152 | /// .create(&project_id, &options) 153 | /// .await?; 154 | /// # 155 | /// # Ok(()) 156 | /// # } 157 | /// ``` 158 | pub async fn create(&self, project_id: &str, options: &Options) -> crate::Result { 159 | let url = format!("https://api.deepgram.com/v1/projects/{}/keys", project_id); 160 | let request = self 161 | .0 162 | .client 163 | .post(url) 164 | .json(&SerializableOptions::from(options)); 165 | 166 | send_and_translate_response(request).await 167 | } 168 | 169 | /// Delete the specified key in the specified project. 170 | /// 171 | /// See the [Deepgram API Reference][api] for more info. 172 | /// 173 | /// [api]: https://developers.deepgram.com/api-reference/#keys-delete 174 | /// 175 | /// # Examples 176 | /// 177 | /// ```no_run 178 | /// # use std::env; 179 | /// # 180 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 181 | /// # 182 | /// # #[tokio::main] 183 | /// # async fn main() -> Result<(), DeepgramError> { 184 | /// # let deepgram_api_key = 185 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 186 | /// # 187 | /// # let project_id = 188 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 189 | /// # 190 | /// # let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 191 | /// # 192 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 193 | /// 194 | /// dg_client 195 | /// .keys() 196 | /// .delete(&project_id, &key_id) 197 | /// .await?; 198 | /// # 199 | /// # Ok(()) 200 | /// # } 201 | /// ``` 202 | pub async fn delete(&self, project_id: &str, key_id: &str) -> crate::Result { 203 | let url = format!( 204 | "https://api.deepgram.com/v1/projects/{}/keys/{}", 205 | project_id, key_id, 206 | ); 207 | 208 | send_and_translate_response(self.0.client.delete(url)).await 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/manage/keys/options.rs: -------------------------------------------------------------------------------- 1 | //! Set options for [`Keys::create`](super::Keys::create). 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#keys-create 6 | 7 | use serde::Serialize; 8 | 9 | /// Used as a parameter for [`Keys::create`](super::Keys::create). 10 | /// 11 | /// See the [Deepgram API Reference][api] for more info. 12 | /// 13 | /// [api]: https://developers.deepgram.com/api-reference/#keys-create 14 | #[derive(Debug, PartialEq, Clone)] 15 | pub struct Options { 16 | comment: String, 17 | tags: Vec, 18 | scopes: Vec, 19 | expiration: Option, 20 | } 21 | 22 | #[derive(Debug, PartialEq, Clone)] 23 | enum Expiration { 24 | ExpirationDate(String), 25 | TimeToLiveInSeconds(usize), 26 | } 27 | 28 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 29 | /// 30 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 31 | #[derive(Debug, PartialEq, Clone)] 32 | pub struct OptionsBuilder(Options); 33 | 34 | #[derive(Serialize)] 35 | pub(crate) struct SerializableOptions<'a> { 36 | comment: &'a String, 37 | 38 | #[serde(skip_serializing_if = "Vec::is_empty")] 39 | tags: &'a Vec, 40 | 41 | scopes: &'a Vec, 42 | 43 | #[serde(skip_serializing_if = "Option::is_none")] 44 | expiration_date: Option<&'a String>, 45 | 46 | #[serde(skip_serializing_if = "Option::is_none")] 47 | time_to_live_in_seconds: Option, 48 | } 49 | 50 | impl Options { 51 | /// Construct a new [`OptionsBuilder`]. 52 | pub fn builder<'a>( 53 | comment: impl Into, 54 | scopes: impl IntoIterator, 55 | ) -> OptionsBuilder { 56 | OptionsBuilder::new(comment, scopes) 57 | } 58 | 59 | /// Return the Options in json format. If serialization would 60 | /// fail, this will also return an error. 61 | /// 62 | /// This is intended primarily to help with debugging API requests. 63 | /// 64 | /// ``` 65 | /// use deepgram::manage::keys::options::Options; 66 | /// let options = Options::builder("API Key", ["member"]) 67 | /// .tag(["my-tag", "another-tag"]) 68 | /// .build(); 69 | /// assert_eq!( 70 | /// &options.json().unwrap(), 71 | /// r#"{"comment":"API Key","tags":["my-tag","another-tag"],"scopes":["member"]}"#) 72 | /// ``` 73 | /// 74 | pub fn json(&self) -> Result { 75 | serde_json::to_string(&SerializableOptions::from(self)) 76 | } 77 | } 78 | 79 | impl OptionsBuilder { 80 | /// Construct a new [`OptionsBuilder`]. 81 | pub fn new<'a>(comment: impl Into, scopes: impl IntoIterator) -> Self { 82 | Self(Options { 83 | comment: comment.into(), 84 | tags: Vec::new(), 85 | scopes: scopes.into_iter().map(String::from).collect(), 86 | expiration: None, 87 | }) 88 | } 89 | 90 | /// Set the comment. 91 | /// 92 | /// This will overwrite any previously set comment, 93 | /// including the one set in [`OptionsBuilder::new`] for [`Options::builder`]. 94 | /// 95 | /// # Examples 96 | /// 97 | /// ``` 98 | /// # use deepgram::manage::keys::options::Options; 99 | /// # 100 | /// let options1 = Options::builder("Old comment", ["member"]) 101 | /// .comment("New comment") 102 | /// .build(); 103 | /// 104 | /// let options2 = Options::builder("New comment", ["member"]).build(); 105 | /// 106 | /// assert_eq!(options1, options2); 107 | /// ``` 108 | pub fn comment(mut self, comment: impl Into) -> Self { 109 | self.0.comment = comment.into(); 110 | self 111 | } 112 | 113 | /// Set the tags. 114 | /// 115 | /// Calling this when already set will append to the existing tags, not overwrite them. 116 | /// 117 | /// # Examples 118 | /// 119 | /// ``` 120 | /// # use deepgram::manage::keys::options::Options; 121 | /// # 122 | /// let options = Options::builder("New Key", ["member"]) 123 | /// .tag(["Tag 1", "Tag 2"]) 124 | /// .build(); 125 | /// ``` 126 | /// 127 | /// ``` 128 | /// # use deepgram::manage::keys::options::Options; 129 | /// # 130 | /// let options1 = Options::builder("New Key", ["member"]) 131 | /// .tag(["Tag 1"]) 132 | /// .tag(vec!["Tag 2"]) 133 | /// .build(); 134 | /// 135 | /// let options2 = Options::builder("New Key", ["member"]) 136 | /// .tag(["Tag 1", "Tag 2"]) 137 | /// .build(); 138 | /// 139 | /// assert_eq!(options1, options2); 140 | /// ``` 141 | pub fn tag<'a>(mut self, tags: impl IntoIterator) -> Self { 142 | self.0.tags.extend(tags.into_iter().map(String::from)); 143 | self 144 | } 145 | 146 | /// Set additional scopes. 147 | /// 148 | /// Calling this when already set will append to the existing scopes, not overwrite them. 149 | /// 150 | /// # Examples 151 | /// 152 | /// ``` 153 | /// # use deepgram::manage::keys::options::Options; 154 | /// # 155 | /// let options = Options::builder("New Key", ["member"]) 156 | /// .scopes(["admin"]) 157 | /// .build(); 158 | /// ``` 159 | /// 160 | /// ``` 161 | /// # use deepgram::manage::keys::options::Options; 162 | /// # 163 | /// let options1 = Options::builder("New Key", ["member"]) 164 | /// .scopes(["admin"]) 165 | /// .build(); 166 | /// 167 | /// let options2 = Options::builder("New Key", ["member", "admin"]).build(); 168 | /// 169 | /// assert_eq!(options1, options2); 170 | /// ``` 171 | pub fn scopes<'a>(mut self, scopes: impl IntoIterator) -> Self { 172 | self.0.scopes.extend(scopes.into_iter().map(String::from)); 173 | self 174 | } 175 | 176 | /// Set the expiration date. 177 | /// 178 | /// This will unset the time to live in seconds. 179 | /// 180 | /// # Examples 181 | /// 182 | /// ``` 183 | /// # use deepgram::manage::keys::options::Options; 184 | /// # 185 | /// let options = Options::builder("New Key", ["member"]) 186 | /// .expiration_date("2038-01-19") 187 | /// .build(); 188 | /// ``` 189 | /// 190 | /// ``` 191 | /// # use deepgram::manage::keys::options::Options; 192 | /// # 193 | /// let options1 = Options::builder("New Key", ["member"]) 194 | /// .time_to_live_in_seconds(7776000) 195 | /// .expiration_date("2038-01-19") 196 | /// .build(); 197 | /// 198 | /// let options2 = Options::builder("New Key", ["member"]) 199 | /// .expiration_date("2038-01-19") 200 | /// .build(); 201 | /// 202 | /// assert_eq!(options1, options2); 203 | /// ``` 204 | pub fn expiration_date(mut self, expiration_date: impl Into) -> Self { 205 | self.0.expiration = Some(Expiration::ExpirationDate(expiration_date.into())); 206 | self 207 | } 208 | 209 | /// Set the time to live in seconds. 210 | /// 211 | /// This will unset the expiration date. 212 | /// 213 | /// # Examples 214 | /// 215 | /// ``` 216 | /// # use deepgram::manage::keys::options::Options; 217 | /// # 218 | /// let options = Options::builder("New Key", ["member"]) 219 | /// .time_to_live_in_seconds(7776000) 220 | /// .build(); 221 | /// ``` 222 | /// 223 | /// ``` 224 | /// # use deepgram::manage::keys::options::Options; 225 | /// # 226 | /// let options1 = Options::builder("New Key", ["member"]) 227 | /// .expiration_date("2038-01-19") 228 | /// .time_to_live_in_seconds(7776000) 229 | /// .build(); 230 | /// 231 | /// let options2 = Options::builder("New Key", ["member"]) 232 | /// .time_to_live_in_seconds(7776000) 233 | /// .build(); 234 | /// 235 | /// assert_eq!(options1, options2); 236 | /// ``` 237 | pub fn time_to_live_in_seconds(mut self, time_to_live_in_seconds: usize) -> Self { 238 | self.0.expiration = Some(Expiration::TimeToLiveInSeconds(time_to_live_in_seconds)); 239 | self 240 | } 241 | 242 | /// Finish building the [`Options`] object. 243 | pub fn build(self) -> Options { 244 | self.0 245 | } 246 | } 247 | 248 | impl<'a> From<&'a Options> for SerializableOptions<'a> { 249 | fn from(options: &'a Options) -> Self { 250 | // Destructuring it makes sure that we don't forget to use any of it 251 | let Options { 252 | comment, 253 | tags, 254 | scopes, 255 | expiration, 256 | } = options; 257 | 258 | let mut serializable_options = Self { 259 | comment, 260 | tags, 261 | scopes, 262 | expiration_date: None, 263 | time_to_live_in_seconds: None, 264 | }; 265 | 266 | match expiration { 267 | Some(Expiration::ExpirationDate(expiration_date)) => { 268 | serializable_options.expiration_date = Some(expiration_date); 269 | } 270 | Some(Expiration::TimeToLiveInSeconds(time_to_live_in_seconds)) => { 271 | serializable_options.time_to_live_in_seconds = Some(*time_to_live_in_seconds); 272 | } 273 | None => {} 274 | }; 275 | 276 | serializable_options 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /src/manage/keys/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram keys API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use uuid::Uuid; 5 | 6 | /// Success message. 7 | /// 8 | /// See the [Deepgram API Reference][api] for more info. 9 | /// 10 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 11 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 12 | #[non_exhaustive] 13 | pub struct Message { 14 | #[allow(missing_docs)] 15 | pub message: String, 16 | } 17 | 18 | /// Returned by [`Keys::list`](super::Keys::list). 19 | /// 20 | /// See the [Deepgram API Reference][api] for more info. 21 | /// 22 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-keys 23 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 24 | #[non_exhaustive] 25 | pub struct MembersAndApiKeys { 26 | #[allow(missing_docs)] 27 | pub api_keys: Vec, 28 | } 29 | 30 | /// Returned by [`Keys::get`](super::Keys::get). 31 | /// 32 | /// See the [Deepgram API Reference][api] for more info. 33 | /// 34 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-key 35 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 36 | #[non_exhaustive] 37 | pub struct MemberAndApiKey { 38 | #[allow(missing_docs)] 39 | pub member: Member, 40 | 41 | #[allow(missing_docs)] 42 | pub api_key: ApiKey, 43 | } 44 | 45 | /// Details of a single member. 46 | /// 47 | /// See the [Deepgram API Reference][api] for more info. 48 | /// 49 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-key 50 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 51 | #[non_exhaustive] 52 | pub struct Member { 53 | #[allow(missing_docs)] 54 | pub member_id: Uuid, 55 | 56 | #[allow(missing_docs)] 57 | pub first_name: Option, 58 | 59 | #[allow(missing_docs)] 60 | pub last_name: Option, 61 | 62 | #[allow(missing_docs)] 63 | pub email: String, 64 | } 65 | 66 | /// Details of a single API key. 67 | /// 68 | /// See the [Deepgram API Reference][api] for more info. 69 | /// 70 | /// [api]: https://developers.deepgram.com/api-reference/#keys-get-key 71 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 72 | #[non_exhaustive] 73 | pub struct ApiKey { 74 | #[allow(missing_docs)] 75 | pub api_key_id: Uuid, 76 | 77 | #[allow(missing_docs)] 78 | pub comment: String, 79 | 80 | #[allow(missing_docs)] 81 | pub scopes: Vec, 82 | 83 | #[allow(missing_docs)] 84 | pub tags: Option>, 85 | 86 | #[allow(missing_docs)] 87 | pub created: String, 88 | 89 | #[allow(missing_docs)] 90 | pub expiration_date: Option, 91 | } 92 | 93 | /// Returned by [`Keys::create`](super::Keys::create). 94 | /// 95 | /// See the [Deepgram API Reference][api] for more info. 96 | /// 97 | /// [api]: https://developers.deepgram.com/api-reference/#keys-create 98 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 99 | #[non_exhaustive] 100 | pub struct NewApiKey { 101 | #[allow(missing_docs)] 102 | pub api_key_id: Uuid, 103 | 104 | #[allow(missing_docs)] 105 | pub key: String, 106 | 107 | #[allow(missing_docs)] 108 | pub comment: String, 109 | 110 | #[allow(missing_docs)] 111 | pub scopes: Vec, 112 | 113 | #[allow(missing_docs)] 114 | pub tags: Option>, 115 | 116 | #[allow(missing_docs)] 117 | pub created: String, 118 | 119 | #[allow(missing_docs)] 120 | pub expiration_date: Option, 121 | } 122 | -------------------------------------------------------------------------------- /src/manage/members.rs: -------------------------------------------------------------------------------- 1 | //! Manage the members of a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#members 6 | 7 | use crate::{send_and_translate_response, Deepgram}; 8 | 9 | use response::Message; 10 | 11 | pub mod response; 12 | 13 | /// Manage the members of a Deepgram Project. 14 | /// 15 | /// Constructed using [`Deepgram::members`]. 16 | /// 17 | /// See the [Deepgram API Reference][api] for more info. 18 | /// 19 | /// [api]: https://developers.deepgram.com/api-reference/#members 20 | #[derive(Debug, Clone)] 21 | pub struct Members<'a>(&'a Deepgram); 22 | 23 | impl Deepgram { 24 | /// Construct a new [`Members`] from a [`Deepgram`]. 25 | pub fn members(&self) -> Members<'_> { 26 | self.into() 27 | } 28 | } 29 | 30 | impl<'a> From<&'a Deepgram> for Members<'a> { 31 | /// Construct a new [`Members`] from a [`Deepgram`]. 32 | fn from(deepgram: &'a Deepgram) -> Self { 33 | Self(deepgram) 34 | } 35 | } 36 | 37 | impl Members<'_> { 38 | /// Get all members of the specified project. 39 | /// 40 | /// See the [Deepgram API Reference][api] for more info. 41 | /// 42 | /// [api]: https://developers.deepgram.com/api-reference/#members-get-members 43 | /// 44 | /// # Examples 45 | /// 46 | /// ```no_run 47 | /// # use std::env; 48 | /// # 49 | /// # use deepgram::{Deepgram, DeepgramError}; 50 | /// # 51 | /// # #[tokio::main] 52 | /// # async fn main() -> Result<(), DeepgramError> { 53 | /// # let deepgram_api_key = 54 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 55 | /// # 56 | /// # let project_id = 57 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 58 | /// # 59 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 60 | /// 61 | /// let members = dg_client 62 | /// .members() 63 | /// .list_members(&project_id) 64 | /// .await?; 65 | /// # 66 | /// # Ok(()) 67 | /// # } 68 | /// ``` 69 | pub async fn list_members(&self, project_id: &str) -> crate::Result { 70 | let url = format!( 71 | "https://api.deepgram.com/v1/projects/{}/members", 72 | project_id, 73 | ); 74 | 75 | send_and_translate_response(self.0.client.get(url)).await 76 | } 77 | 78 | /// Remove the specified member from the specified project. 79 | /// 80 | /// See the [Deepgram API Reference][api] for more info. 81 | /// 82 | /// [api]: https://developers.deepgram.com/api-reference/#members-delete 83 | /// 84 | /// # Examples 85 | /// 86 | /// ```no_run 87 | /// # use std::env; 88 | /// # 89 | /// # use deepgram::{Deepgram, DeepgramError}; 90 | /// # 91 | /// # #[tokio::main] 92 | /// # async fn main() -> Result<(), DeepgramError> { 93 | /// # let deepgram_api_key = 94 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 95 | /// # 96 | /// # let project_id = 97 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 98 | /// # 99 | /// # let member_id = 100 | /// # env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 101 | /// # 102 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 103 | /// 104 | /// dg_client 105 | /// .members() 106 | /// .remove_member(&project_id, &member_id) 107 | /// .await?; 108 | /// # 109 | /// # Ok(()) 110 | /// # } 111 | /// ``` 112 | pub async fn remove_member(&self, project_id: &str, member_id: &str) -> crate::Result { 113 | let url = format!( 114 | "https://api.deepgram.com/v1/projects/{}/members/{}", 115 | project_id, member_id, 116 | ); 117 | 118 | send_and_translate_response(self.0.client.delete(url)).await 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/manage/members/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram members API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use uuid::Uuid; 5 | 6 | /// Success message. 7 | /// 8 | /// See the [Deepgram API Reference][api] for more info. 9 | /// 10 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 11 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 12 | #[non_exhaustive] 13 | pub struct Message { 14 | #[allow(missing_docs)] 15 | pub message: String, 16 | } 17 | 18 | /// Returned by [`Members::list_members`](super::Members::list_members). 19 | /// 20 | /// See the [Deepgram API Reference][api] for more info. 21 | /// 22 | /// [api]: https://developers.deepgram.com/api-reference/#members-get-members 23 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 24 | #[non_exhaustive] 25 | pub struct Members { 26 | #[allow(missing_docs)] 27 | pub members: Vec, 28 | } 29 | 30 | /// Returned by [`Members::list_members`](super::Members::list_members). 31 | /// 32 | /// See the [Deepgram API Reference][api] for more info. 33 | /// 34 | /// [api]: https://developers.deepgram.com/api-reference/#members-get-members 35 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 36 | #[non_exhaustive] 37 | pub struct Member { 38 | #[allow(missing_docs)] 39 | pub member_id: Uuid, 40 | 41 | #[allow(missing_docs)] 42 | pub first_name: Option, 43 | 44 | #[allow(missing_docs)] 45 | pub last_name: Option, 46 | 47 | #[allow(missing_docs)] 48 | pub scopes: Vec, 49 | 50 | #[allow(missing_docs)] 51 | pub email: String, 52 | } 53 | -------------------------------------------------------------------------------- /src/manage/mod.rs: -------------------------------------------------------------------------------- 1 | //! Manage module 2 | 3 | pub mod billing; 4 | pub mod invitations; 5 | pub mod keys; 6 | pub mod members; 7 | pub mod projects; 8 | pub mod scopes; 9 | pub mod usage; 10 | -------------------------------------------------------------------------------- /src/manage/projects.rs: -------------------------------------------------------------------------------- 1 | //! Manage Deepgram Projects. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#projects 6 | 7 | use crate::{send_and_translate_response, Deepgram}; 8 | 9 | use options::{Options, SerializableOptions}; 10 | 11 | use response::{Message, Project}; 12 | 13 | pub mod options; 14 | pub mod response; 15 | 16 | /// Manage Deepgram Projects. 17 | /// 18 | /// Constructed using [`Deepgram::projects`]. 19 | /// 20 | /// You can create new Deepgram Projects on the [Deepgram Console][console]. 21 | /// 22 | /// See the [Deepgram API Reference][api] for more info. 23 | /// 24 | /// [console]: https://console.deepgram.com/ 25 | /// [api]: https://developers.deepgram.com/api-reference/#projects 26 | #[derive(Debug, Clone)] 27 | pub struct Projects<'a>(&'a Deepgram); 28 | 29 | impl Deepgram { 30 | /// Construct a new [`Projects`] from a [`Deepgram`]. 31 | pub fn projects(&self) -> Projects<'_> { 32 | self.into() 33 | } 34 | } 35 | 36 | impl<'a> From<&'a Deepgram> for Projects<'a> { 37 | /// Construct a new [`Projects`] from a [`Deepgram`]. 38 | fn from(deepgram: &'a Deepgram) -> Self { 39 | Self(deepgram) 40 | } 41 | } 42 | 43 | impl Projects<'_> { 44 | /// Get all projects. 45 | /// 46 | /// See the [Deepgram API Reference][api] for more info. 47 | /// 48 | /// [api]: https://developers.deepgram.com/api-reference/#projects-get-projects 49 | /// 50 | /// # Examples 51 | /// 52 | /// ```no_run 53 | /// # use std::env; 54 | /// # 55 | /// # use deepgram::{Deepgram, DeepgramError}; 56 | /// # 57 | /// # #[tokio::main] 58 | /// # async fn main() -> Result<(), DeepgramError> { 59 | /// # let deepgram_api_key = 60 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 61 | /// # 62 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 63 | /// 64 | /// let projects = dg_client 65 | /// .projects() 66 | /// .list() 67 | /// .await?; 68 | /// # 69 | /// # Ok(()) 70 | /// # } 71 | /// ``` 72 | pub async fn list(&self) -> crate::Result { 73 | let request = self.0.client.get("https://api.deepgram.com/v1/projects"); 74 | 75 | send_and_translate_response(request).await 76 | } 77 | 78 | /// Get a specific project. 79 | /// 80 | /// See the [Deepgram API Reference][api] for more info. 81 | /// 82 | /// [api]: https://developers.deepgram.com/api-reference/#projects-get-project 83 | /// 84 | /// # Examples 85 | /// 86 | /// ```no_run 87 | /// # use std::env; 88 | /// # 89 | /// # use deepgram::{Deepgram, DeepgramError}; 90 | /// # 91 | /// # #[tokio::main] 92 | /// # async fn main() -> Result<(), DeepgramError> { 93 | /// # let deepgram_api_key = 94 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 95 | /// # 96 | /// # let project_id = 97 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 98 | /// # 99 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 100 | /// 101 | /// let project = dg_client 102 | /// .projects() 103 | /// .get(&project_id) 104 | /// .await?; 105 | /// # 106 | /// # Ok(()) 107 | /// # } 108 | /// ``` 109 | pub async fn get(&self, project_id: &str) -> crate::Result { 110 | let url = format!("https://api.deepgram.com/v1/projects/{}", project_id); 111 | 112 | send_and_translate_response(self.0.client.get(url)).await 113 | } 114 | 115 | /// Update the specified project. 116 | /// 117 | /// See the [Deepgram API Reference][api] for more info. 118 | /// 119 | /// [api]: https://developers.deepgram.com/api-reference/#projects-update 120 | /// 121 | /// # Examples 122 | /// 123 | /// ```no_run 124 | /// # use std::env; 125 | /// # 126 | /// # use deepgram::{manage::projects::options::Options, Deepgram, DeepgramError}; 127 | /// # 128 | /// # #[tokio::main] 129 | /// # async fn main() -> Result<(), DeepgramError> { 130 | /// # let deepgram_api_key = 131 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 132 | /// # 133 | /// # let project_id = 134 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 135 | /// # 136 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 137 | /// 138 | /// let options = Options::builder() 139 | /// .name("The Transcribinator") 140 | /// .company("Doofenshmirtz Evil Incorporated") 141 | /// .build(); 142 | /// 143 | /// dg_client 144 | /// .projects() 145 | /// .update(&project_id, &options) 146 | /// .await?; 147 | /// # 148 | /// # Ok(()) 149 | /// # } 150 | /// ``` 151 | pub async fn update(&self, project_id: &str, options: &Options) -> crate::Result { 152 | let url = format!("https://api.deepgram.com/v1/projects/{}", project_id); 153 | let request = self 154 | .0 155 | .client 156 | .patch(url) 157 | .json(&SerializableOptions::from(options)); 158 | 159 | send_and_translate_response(request).await 160 | } 161 | 162 | /// Delete the specified project. 163 | /// 164 | /// See the [Deepgram API Reference][api] for more info. 165 | /// 166 | /// [api]: https://developers.deepgram.com/api-reference/#projects-get-delete 167 | /// 168 | /// # Examples 169 | /// 170 | /// ```no_run 171 | /// # use std::env; 172 | /// # 173 | /// # use deepgram::{Deepgram, DeepgramError}; 174 | /// # 175 | /// # #[tokio::main] 176 | /// # async fn main() -> Result<(), DeepgramError> { 177 | /// # let deepgram_api_key = 178 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 179 | /// # 180 | /// # let project_id = 181 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 182 | /// # 183 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 184 | /// 185 | /// dg_client 186 | /// .projects() 187 | /// .delete(&project_id) 188 | /// .await?; 189 | /// # 190 | /// # Ok(()) 191 | /// # } 192 | /// ``` 193 | pub async fn delete(&self, project_id: &str) -> crate::Result { 194 | let url = format!("https://api.deepgram.com/v1/projects/{}", project_id); 195 | let request = self.0.client.delete(url); 196 | 197 | send_and_translate_response(request).await 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/manage/projects/options.rs: -------------------------------------------------------------------------------- 1 | //! Set options for [`Projects::update`](super::Projects::update). 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#projects-update 6 | 7 | use serde::Serialize; 8 | 9 | /// Used as a parameter for [`Projects::update`](super::Projects::update). 10 | /// 11 | /// See the [Deepgram API Reference][api] for more info. 12 | /// 13 | /// [api]: https://developers.deepgram.com/api-reference/#projects-update 14 | #[derive(Debug, PartialEq, Eq, Clone, Hash)] 15 | pub struct Options { 16 | name: Option, 17 | company: Option, 18 | } 19 | 20 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 21 | /// 22 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 23 | #[derive(Debug, PartialEq, Clone)] 24 | pub struct OptionsBuilder(Options); 25 | 26 | #[derive(Serialize)] 27 | pub(crate) struct SerializableOptions<'a> { 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | pub(super) name: &'a Option, 30 | 31 | #[serde(skip_serializing_if = "Option::is_none")] 32 | pub(super) company: &'a Option, 33 | } 34 | 35 | impl Options { 36 | /// Construct a new [`OptionsBuilder`]. 37 | pub fn builder() -> OptionsBuilder { 38 | OptionsBuilder::new() 39 | } 40 | 41 | /// Return the Options in json format. If serialization would 42 | /// fail, this will also return an error. 43 | /// 44 | /// This is intended primarily to help with debugging API requests. 45 | /// 46 | /// ``` 47 | /// use deepgram::manage::projects::options::Options; 48 | /// let options = Options::builder() 49 | /// .company("Deepgram") 50 | /// .name("DG Project") 51 | /// .build(); 52 | /// assert_eq!( 53 | /// &options.json().unwrap(), 54 | /// r#"{"name":"DG Project","company":"Deepgram"}"#) 55 | /// ``` 56 | /// 57 | pub fn json(&self) -> Result { 58 | serde_json::to_string(&SerializableOptions::from(self)) 59 | } 60 | } 61 | 62 | impl OptionsBuilder { 63 | /// Construct a new [`OptionsBuilder`]. 64 | pub fn new() -> Self { 65 | Self(Options { 66 | name: None, 67 | company: None, 68 | }) 69 | } 70 | 71 | /// Set the project name. 72 | /// 73 | /// # Examples 74 | /// 75 | /// ``` 76 | /// # use deepgram::manage::projects::options::Options; 77 | /// # 78 | /// let options = Options::builder() 79 | /// .name("The Transcribinator") 80 | /// .build(); 81 | /// ``` 82 | pub fn name(mut self, name: impl Into) -> Self { 83 | self.0.name = Some(name.into()); 84 | self 85 | } 86 | 87 | /// Set the project company. 88 | /// 89 | /// # Examples 90 | /// 91 | /// ``` 92 | /// # use deepgram::manage::projects::options::Options; 93 | /// # 94 | /// let options = Options::builder() 95 | /// .company("Doofenshmirtz Evil Incorporated") 96 | /// .build(); 97 | /// ``` 98 | pub fn company(mut self, company: impl Into) -> Self { 99 | self.0.company = Some(company.into()); 100 | self 101 | } 102 | 103 | /// Finish building the [`Options`] object. 104 | pub fn build(self) -> Options { 105 | self.0 106 | } 107 | } 108 | 109 | impl Default for OptionsBuilder { 110 | fn default() -> Self { 111 | Self::new() 112 | } 113 | } 114 | 115 | impl<'a> From<&'a Options> for SerializableOptions<'a> { 116 | fn from(options: &'a Options) -> Self { 117 | // Destructuring it makes sure that we don't forget to use any of it 118 | let Options { name, company } = options; 119 | 120 | Self { name, company } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/manage/projects/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram projects API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use uuid::Uuid; 5 | 6 | /// Success message. 7 | /// 8 | /// See the [Deepgram API Reference][api] for more info. 9 | /// 10 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 11 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 12 | #[non_exhaustive] 13 | pub struct Message { 14 | #[allow(missing_docs)] 15 | pub message: String, 16 | } 17 | 18 | /// Returned by [`Projects::list`](super::Projects::list). 19 | /// 20 | /// See the [Deepgram API Reference][api] for more info. 21 | /// 22 | /// [api]: https://developers.deepgram.com/api-reference/#projects-get-projects 23 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 24 | #[non_exhaustive] 25 | pub struct Projects { 26 | #[allow(missing_docs)] 27 | pub projects: Vec, 28 | } 29 | 30 | /// Returned by [`Projects::get`](super::Projects::get). 31 | /// 32 | /// See the [Deepgram API Reference][api] for more info. 33 | /// 34 | /// [api]: https://developers.deepgram.com/api-reference/#projects-get-project 35 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 36 | #[non_exhaustive] 37 | pub struct Project { 38 | #[allow(missing_docs)] 39 | pub project_id: Uuid, 40 | 41 | #[allow(missing_docs)] 42 | pub name: String, 43 | 44 | #[allow(missing_docs)] 45 | pub company: Option, 46 | } 47 | -------------------------------------------------------------------------------- /src/manage/scopes.rs: -------------------------------------------------------------------------------- 1 | //! Manage the permissions of a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#scopes 6 | 7 | use serde::Serialize; 8 | 9 | use crate::{send_and_translate_response, Deepgram}; 10 | 11 | use response::Message; 12 | 13 | pub mod response; 14 | 15 | /// Manage the permissions of a Deepgram Project. 16 | /// 17 | /// Constructed using [`Deepgram::scopes`]. 18 | /// 19 | /// See the [Deepgram API Reference][api] for more info. 20 | /// 21 | /// [api]: https://developers.deepgram.com/api-reference/#scopes 22 | #[derive(Debug, Clone)] 23 | pub struct Scopes<'a>(&'a Deepgram); 24 | 25 | impl Deepgram { 26 | /// Construct a new [`Scopes`] from a [`Deepgram`]. 27 | pub fn scopes(&self) -> Scopes<'_> { 28 | self.into() 29 | } 30 | } 31 | 32 | impl<'a> From<&'a Deepgram> for Scopes<'a> { 33 | /// Construct a new [`Scopes`] from a [`Deepgram`]. 34 | fn from(deepgram: &'a Deepgram) -> Self { 35 | Self(deepgram) 36 | } 37 | } 38 | 39 | impl Scopes<'_> { 40 | /// Get the specified project scopes assigned to the specified member. 41 | /// 42 | /// See the [Deepgram API Reference][api] for more info. 43 | /// 44 | /// [api]: https://developers.deepgram.com/api-reference/#scopes-get 45 | /// 46 | /// # Examples 47 | /// 48 | /// ```no_run 49 | /// # use std::env; 50 | /// # 51 | /// # use deepgram::{Deepgram, DeepgramError}; 52 | /// # 53 | /// # #[tokio::main] 54 | /// # async fn main() -> Result<(), DeepgramError> { 55 | /// # let deepgram_api_key = 56 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 57 | /// # 58 | /// # let project_id = 59 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 60 | /// # 61 | /// # let member_id = 62 | /// # env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 63 | /// # 64 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 65 | /// 66 | /// let scopes = dg_client 67 | /// .scopes() 68 | /// .get_scope(&project_id, &member_id) 69 | /// .await?; 70 | /// # 71 | /// # Ok(()) 72 | /// # } 73 | /// ``` 74 | pub async fn get_scope( 75 | &self, 76 | project_id: &str, 77 | member_id: &str, 78 | ) -> crate::Result { 79 | let url = format!( 80 | "https://api.deepgram.com/v1/projects/{}/members/{}/scopes ", 81 | project_id, member_id 82 | ); 83 | 84 | send_and_translate_response(self.0.client.get(url)).await 85 | } 86 | 87 | /// Update the specified project scopes assigned to the specified member. 88 | /// 89 | /// See the [Deepgram API Reference][api] for more info. 90 | /// 91 | /// [api]: https://developers.deepgram.com/api-reference/#scopes-update 92 | /// 93 | /// # Examples 94 | /// 95 | /// ```no_run 96 | /// # use std::env; 97 | /// # 98 | /// # use deepgram::{Deepgram, DeepgramError}; 99 | /// # 100 | /// # #[tokio::main] 101 | /// # async fn main() -> Result<(), DeepgramError> { 102 | /// # let deepgram_api_key = 103 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 104 | /// # 105 | /// # let project_id = 106 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 107 | /// # 108 | /// # let member_id = 109 | /// # env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 110 | /// # 111 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 112 | /// 113 | /// dg_client 114 | /// .scopes() 115 | /// .update_scope(&project_id, &member_id, "member") 116 | /// .await?; 117 | /// # 118 | /// # Ok(()) 119 | /// # } 120 | /// ``` 121 | pub async fn update_scope( 122 | &self, 123 | project_id: &str, 124 | member_id: &str, 125 | scope: &str, 126 | ) -> crate::Result { 127 | #[derive(Serialize)] 128 | struct Scope<'a> { 129 | scope: &'a str, 130 | } 131 | 132 | let url = format!( 133 | "https://api.deepgram.com/v1/projects/{}/members/{}/scopes", 134 | project_id, member_id 135 | ); 136 | let request = self.0.client.put(url).json(&Scope { scope }); 137 | 138 | send_and_translate_response(request).await 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/manage/scopes/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram TODO API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// Success message. 6 | /// 7 | /// See the [Deepgram API Reference][api] for more info. 8 | /// 9 | /// [api]: https://developers.deepgram.com/api-reference/#invitations 10 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 11 | #[non_exhaustive] 12 | pub struct Message { 13 | #[allow(missing_docs)] 14 | pub message: String, 15 | } 16 | 17 | /// Scopes associated with the member. 18 | /// 19 | /// See the [Deepgram API Reference][api] for more info. 20 | /// 21 | /// [api]: https://developers.deepgram.com/api-reference/#scopes-get 22 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 23 | #[non_exhaustive] 24 | pub struct Scopes { 25 | #[allow(missing_docs)] 26 | pub scopes: Vec, 27 | } 28 | -------------------------------------------------------------------------------- /src/manage/usage.rs: -------------------------------------------------------------------------------- 1 | //! Get the usage data of a Deepgram Project. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#usage 6 | 7 | use response::{Fields, Request, Requests, UsageSummary}; 8 | 9 | use crate::{send_and_translate_response, Deepgram}; 10 | 11 | pub mod get_fields_options; 12 | pub mod get_usage_options; 13 | pub mod list_requests_options; 14 | pub mod response; 15 | 16 | /// Get the usage data of a Deepgram Project. 17 | /// 18 | /// Constructed using [`Deepgram::usage`]. 19 | /// 20 | /// See the [Deepgram API Reference][api] for more info. 21 | /// 22 | /// [api]: https://developers.deepgram.com/api-reference/#usage 23 | #[derive(Debug, Clone)] 24 | pub struct Usage<'a>(&'a Deepgram); 25 | 26 | impl Deepgram { 27 | /// Construct a new [`Usage`] from a [`Deepgram`]. 28 | pub fn usage(&self) -> Usage<'_> { 29 | self.into() 30 | } 31 | } 32 | 33 | impl<'a> From<&'a Deepgram> for Usage<'a> { 34 | /// Construct a new [`Usage`] from a [`Deepgram`]. 35 | fn from(deepgram: &'a Deepgram) -> Self { 36 | Self(deepgram) 37 | } 38 | } 39 | 40 | impl Usage<'_> { 41 | /// Get all requests sent to the Deepgram API for the specified project. 42 | /// 43 | /// See the [Deepgram API Reference][api] for more info. 44 | /// 45 | /// [api]: https://developers.deepgram.com/api-reference/#usage-all 46 | /// 47 | /// # Examples 48 | /// 49 | /// ```no_run 50 | /// # use std::env; 51 | /// # 52 | /// # use deepgram::{ 53 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 54 | /// # Deepgram, DeepgramError, 55 | /// # }; 56 | /// # 57 | /// # #[tokio::main] 58 | /// # async fn main() -> Result<(), DeepgramError> { 59 | /// # let deepgram_api_key = 60 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 61 | /// # 62 | /// # let project_id = 63 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 64 | /// # 65 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 66 | /// 67 | /// let options = list_requests_options::Options::builder().build(); 68 | /// let requests = dg_client 69 | /// .usage() 70 | /// .list_requests(&project_id, &options) 71 | /// .await?; 72 | /// # 73 | /// # Ok(()) 74 | /// # } 75 | /// ``` 76 | pub async fn list_requests( 77 | &self, 78 | project_id: &str, 79 | options: &list_requests_options::Options, 80 | ) -> crate::Result { 81 | let url = format!( 82 | "https://api.deepgram.com/v1/projects/{}/requests", 83 | project_id, 84 | ); 85 | let request = self 86 | .0 87 | .client 88 | .get(url) 89 | .query(&list_requests_options::SerializableOptions::from(options)); 90 | 91 | send_and_translate_response(request).await 92 | } 93 | 94 | /// Get the details of the specified request sent to the Deepgram API for the specified project. 95 | /// 96 | /// See the [Deepgram API Reference][api] for more info. 97 | /// 98 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 99 | /// 100 | /// # Examples 101 | /// 102 | /// ```no_run 103 | /// # use std::env; 104 | /// # 105 | /// # use deepgram::{ 106 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 107 | /// # Deepgram, DeepgramError, 108 | /// # }; 109 | /// # 110 | /// # #[tokio::main] 111 | /// # async fn main() -> Result<(), DeepgramError> { 112 | /// # let deepgram_api_key = 113 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 114 | /// # 115 | /// # let project_id = 116 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 117 | /// # 118 | /// # let request_id = 119 | /// # env::var("DEEPGRAM_REQUEST_ID").expect("DEEPGRAM_REQUEST_ID environmental variable"); 120 | /// # 121 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 122 | /// 123 | /// let request = dg_client 124 | /// .usage() 125 | /// .get_request(&project_id, &request_id) 126 | /// .await?; 127 | /// # 128 | /// # Ok(()) 129 | /// # } 130 | /// ``` 131 | pub async fn get_request(&self, project_id: &str, request_id: &str) -> crate::Result { 132 | let url = format!( 133 | "https://api.deepgram.com/v1/projects/{}/requests/{}", 134 | project_id, request_id, 135 | ); 136 | 137 | send_and_translate_response(self.0.client.get(url)).await 138 | } 139 | 140 | /// Get a summary of usage statistics. 141 | /// 142 | /// See the [Deepgram API Reference][api] for more info. 143 | /// 144 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 145 | /// 146 | /// # Examples 147 | /// 148 | /// ```no_run 149 | /// # use std::env; 150 | /// # 151 | /// # use deepgram::{ 152 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 153 | /// # Deepgram, DeepgramError, 154 | /// # }; 155 | /// # 156 | /// # #[tokio::main] 157 | /// # async fn main() -> Result<(), DeepgramError> { 158 | /// # let deepgram_api_key = 159 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 160 | /// # 161 | /// # let project_id = 162 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 163 | /// # 164 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 165 | /// 166 | /// let options = get_usage_options::Options::builder().build(); 167 | /// let summary = dg_client 168 | /// .usage() 169 | /// .get_usage(&project_id, &options) 170 | /// .await?; 171 | /// # 172 | /// # Ok(()) 173 | /// # } 174 | /// ``` 175 | pub async fn get_usage( 176 | &self, 177 | project_id: &str, 178 | options: &get_usage_options::Options, 179 | ) -> crate::Result { 180 | let url = format!("https://api.deepgram.com/v1/projects/{}/usage", project_id); 181 | let request = self 182 | .0 183 | .client 184 | .get(url) 185 | .query(&get_usage_options::SerializableOptions::from(options)); 186 | 187 | send_and_translate_response(request).await 188 | } 189 | 190 | /// Get the features, models, tags, languages, and processing method used for requests in the specified project. 191 | /// 192 | /// See the [Deepgram API Reference][api] for more info. 193 | /// 194 | /// [api]: https://developers.deepgram.com/api-reference/#usage-fields 195 | /// 196 | /// # Examples 197 | /// 198 | /// ```no_run 199 | /// # use std::env; 200 | /// # 201 | /// # use deepgram::{ 202 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 203 | /// # Deepgram, DeepgramError, 204 | /// # }; 205 | /// # 206 | /// # #[tokio::main] 207 | /// # async fn main() -> Result<(), DeepgramError> { 208 | /// # let deepgram_api_key = 209 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 210 | /// # 211 | /// # let project_id = 212 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 213 | /// # 214 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 215 | /// 216 | /// let options = get_fields_options::Options::builder().build(); 217 | /// let summary = dg_client 218 | /// .usage() 219 | /// .get_fields(&project_id, &options) 220 | /// .await?; 221 | /// # 222 | /// # Ok(()) 223 | /// # } 224 | /// ``` 225 | pub async fn get_fields( 226 | &self, 227 | project_id: &str, 228 | options: &get_fields_options::Options, 229 | ) -> crate::Result { 230 | let url = format!( 231 | "https://api.deepgram.com/v1/projects/{}/usage/fields", 232 | project_id, 233 | ); 234 | let request = self 235 | .0 236 | .client 237 | .get(url) 238 | .query(&get_fields_options::SerializableOptions::from(options)); 239 | 240 | send_and_translate_response(request).await 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/manage/usage/get_fields_options.rs: -------------------------------------------------------------------------------- 1 | //! Set options for [`Usage::get_fields`](super::Usage::get_fields). 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#usage-fields 6 | 7 | use serde::Serialize; 8 | 9 | /// Used as a parameter for [`Usage::get_fields`](super::Usage::get_fields). 10 | /// 11 | /// See the [Deepgram API Reference][api] for more info. 12 | /// 13 | /// [api]: https://developers.deepgram.com/api-reference/#usage-fields 14 | #[derive(Debug, PartialEq, Clone)] 15 | pub struct Options { 16 | start: Option, 17 | end: Option, 18 | } 19 | 20 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 21 | /// 22 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 23 | #[derive(Debug, PartialEq, Clone)] 24 | pub struct OptionsBuilder(Options); 25 | 26 | #[derive(Serialize)] 27 | pub(crate) struct SerializableOptions<'a> { 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | start: &'a Option, 30 | 31 | #[serde(skip_serializing_if = "Option::is_none")] 32 | end: &'a Option, 33 | } 34 | 35 | impl Options { 36 | /// Construct a new [`OptionsBuilder`]. 37 | pub fn builder() -> OptionsBuilder { 38 | OptionsBuilder::new() 39 | } 40 | 41 | /// Return the Options in urlencoded format. If serialization would 42 | /// fail, this will also return an error. 43 | /// 44 | /// This is intended primarily to help with debugging API requests. 45 | /// 46 | /// ``` 47 | /// use deepgram::manage::usage::get_fields_options::Options; 48 | /// let options = Options::builder() 49 | /// .start("2024-04-10T00:00:00Z") 50 | /// .end("2024-10-10") 51 | /// .build(); 52 | /// assert_eq!(&options.urlencoded().unwrap(), "start=2024-04-10T00%3A00%3A00Z&end=2024-10-10") 53 | /// ``` 54 | /// 55 | pub fn urlencoded(&self) -> Result { 56 | serde_urlencoded::to_string(SerializableOptions::from(self)) 57 | } 58 | } 59 | 60 | impl OptionsBuilder { 61 | /// Construct a new [`OptionsBuilder`]. 62 | pub fn new() -> Self { 63 | Self(Options { 64 | start: None, 65 | end: None, 66 | }) 67 | } 68 | 69 | /// Set the time range start date. 70 | /// 71 | /// # Examples 72 | /// 73 | /// ``` 74 | /// # use deepgram::manage::usage::list_requests_options::Options; 75 | /// # 76 | /// let options1 = Options::builder() 77 | /// .start("1970-01-01") 78 | /// .build(); 79 | /// ``` 80 | pub fn start(mut self, start: impl Into) -> Self { 81 | self.0.start = Some(start.into()); 82 | self 83 | } 84 | 85 | /// Set the time range end date. 86 | /// 87 | /// # Examples 88 | /// 89 | /// ``` 90 | /// # use deepgram::manage::usage::list_requests_options::Options; 91 | /// # 92 | /// let options1 = Options::builder() 93 | /// .end("2038-01-19") 94 | /// .build(); 95 | /// ``` 96 | pub fn end(mut self, end: impl Into) -> Self { 97 | self.0.end = Some(end.into()); 98 | self 99 | } 100 | 101 | /// Finish building the [`Options`] object. 102 | pub fn build(self) -> Options { 103 | self.0 104 | } 105 | } 106 | 107 | impl Default for OptionsBuilder { 108 | fn default() -> Self { 109 | Self::new() 110 | } 111 | } 112 | 113 | impl<'a> From<&'a Options> for SerializableOptions<'a> { 114 | fn from(options: &'a Options) -> Self { 115 | // Destructuring it makes sure that we don't forget to use any of it 116 | let Options { start, end } = options; 117 | 118 | Self { start, end } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/manage/usage/get_usage_options.rs: -------------------------------------------------------------------------------- 1 | //! Set options for [`Usage::get_usage`](super::Usage::get_usage). 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#usage-summary 6 | 7 | use serde::{ser::SerializeSeq, Serialize}; 8 | 9 | /// Used as a parameter for [`Usage::get_usage`](super::Usage::get_usage). 10 | /// 11 | /// See the [Deepgram API Reference][api] for more info. 12 | /// 13 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 14 | #[derive(Debug, PartialEq, Clone)] 15 | pub struct Options { 16 | start: Option, 17 | end: Option, 18 | accessor: Option, 19 | tags: Vec, 20 | methods: Vec, 21 | models: Vec, 22 | multichannel: Option, 23 | interim_results: Option, 24 | punctuate: Option, 25 | ner: Option, 26 | utterances: Option, 27 | replace: Option, 28 | profanity_filter: Option, 29 | keywords: Option, 30 | diarize: Option, 31 | search: Option, 32 | redact: Option, 33 | alternatives: Option, 34 | numerals: Option, 35 | } 36 | 37 | /// Used as a parameter for [`OptionsBuilder::method`]. 38 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 39 | #[non_exhaustive] 40 | pub enum Method { 41 | #[allow(missing_docs)] 42 | Sync, 43 | 44 | #[allow(missing_docs)] 45 | Async, 46 | 47 | #[allow(missing_docs)] 48 | Streaming, 49 | } 50 | 51 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 52 | /// 53 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 54 | #[derive(Debug, PartialEq, Clone)] 55 | pub struct OptionsBuilder(Options); 56 | 57 | pub(crate) struct SerializableOptions<'a>(&'a Options); 58 | 59 | impl Options { 60 | /// Construct a new [`OptionsBuilder`]. 61 | pub fn builder() -> OptionsBuilder { 62 | OptionsBuilder::new() 63 | } 64 | 65 | /// Return the Options in urlencoded format. If serialization would 66 | /// fail, this will also return an error. 67 | /// 68 | /// This is intended primarily to help with debugging API requests. 69 | /// 70 | /// ``` 71 | /// use deepgram::manage::usage::get_usage_options::{Options, Method}; 72 | /// let options = Options::builder() 73 | /// .method([Method::Sync, Method::Async]) 74 | /// .ner(true) 75 | /// .build(); 76 | /// assert_eq!(&options.urlencoded().unwrap(), "method=sync&method=async&ner=true") 77 | /// ``` 78 | /// 79 | pub fn urlencoded(&self) -> Result { 80 | serde_urlencoded::to_string(SerializableOptions::from(self)) 81 | } 82 | } 83 | 84 | impl OptionsBuilder { 85 | /// Construct a new [`OptionsBuilder`]. 86 | pub fn new() -> Self { 87 | Self(Options { 88 | start: None, 89 | end: None, 90 | accessor: None, 91 | tags: Vec::new(), 92 | methods: Vec::new(), 93 | models: Vec::new(), 94 | multichannel: None, 95 | interim_results: None, 96 | punctuate: None, 97 | ner: None, 98 | utterances: None, 99 | replace: None, 100 | profanity_filter: None, 101 | keywords: None, 102 | diarize: None, 103 | search: None, 104 | redact: None, 105 | alternatives: None, 106 | numerals: None, 107 | }) 108 | } 109 | 110 | /// Set the time range start date. 111 | /// 112 | /// # Examples 113 | /// 114 | /// ``` 115 | /// # use deepgram::manage::usage::get_usage_options::Options; 116 | /// # 117 | /// let options = Options::builder() 118 | /// .start("1970-01-01") 119 | /// .build(); 120 | /// ``` 121 | pub fn start(mut self, start: impl Into) -> Self { 122 | self.0.start = Some(start.into()); 123 | self 124 | } 125 | 126 | /// Set the time range end date. 127 | /// 128 | /// # Examples 129 | /// 130 | /// ``` 131 | /// # use deepgram::manage::usage::get_usage_options::Options; 132 | /// # 133 | /// let options = Options::builder() 134 | /// .end("2038-01-19") 135 | /// .build(); 136 | /// ``` 137 | pub fn end(mut self, end: impl Into) -> Self { 138 | self.0.end = Some(end.into()); 139 | self 140 | } 141 | 142 | /// Limits results to requests made using the API key corresponding to the given accessor. 143 | /// 144 | /// # Examples 145 | /// 146 | /// ``` 147 | /// # use deepgram::manage::usage::get_usage_options::Options; 148 | /// # 149 | /// let options = Options::builder() 150 | /// .accessor("12345678-1234-1234-1234-1234567890ab") 151 | /// .build(); 152 | /// ``` 153 | pub fn accessor(mut self, accessor: impl Into) -> Self { 154 | self.0.accessor = Some(accessor.into()); 155 | self 156 | } 157 | 158 | /// Limits results to requests associated with the specified tag. 159 | /// 160 | /// Calling this when already set will append to the existing tags, not overwrite them. 161 | /// 162 | /// # Examples 163 | /// 164 | /// ``` 165 | /// # use deepgram::manage::usage::get_usage_options::Options; 166 | /// # 167 | /// let options = Options::builder() 168 | /// .tag(["Tag 1", "Tag 2"]) 169 | /// .build(); 170 | /// ``` 171 | /// 172 | /// ``` 173 | /// # use deepgram::manage::usage::get_usage_options::Options; 174 | /// # 175 | /// let options1 = Options::builder() 176 | /// .tag(["Tag 1"]) 177 | /// .tag(["Tag 2"]) 178 | /// .build(); 179 | /// 180 | /// let options2 = Options::builder() 181 | /// .tag(["Tag 1", "Tag 2"]) 182 | /// .build(); 183 | /// 184 | /// assert_eq!(options1, options2); 185 | /// ``` 186 | pub fn tag<'a>(mut self, tag: impl IntoIterator) -> Self { 187 | self.0.tags.extend(tag.into_iter().map(String::from)); 188 | self 189 | } 190 | 191 | /// Limits results to requests processed using the specified method. 192 | /// 193 | /// Calling this when already set will append to the existing methods, not overwrite them. 194 | /// 195 | /// # Examples 196 | /// 197 | /// ``` 198 | /// # use deepgram::manage::usage::get_usage_options::{Method, Options}; 199 | /// # 200 | /// let options = Options::builder() 201 | /// .method([Method::Sync, Method::Streaming]) 202 | /// .build(); 203 | /// ``` 204 | /// 205 | /// ``` 206 | /// # use deepgram::manage::usage::get_usage_options::{Method, Options}; 207 | /// # 208 | /// let options1 = Options::builder() 209 | /// .method([Method::Sync]) 210 | /// .method([Method::Streaming]) 211 | /// .build(); 212 | /// 213 | /// let options2 = Options::builder() 214 | /// .method([Method::Sync, Method::Streaming]) 215 | /// .build(); 216 | /// 217 | /// assert_eq!(options1, options2); 218 | /// ``` 219 | pub fn method(mut self, method: impl IntoIterator) -> Self { 220 | self.0.methods.extend(method); 221 | self 222 | } 223 | 224 | /// Limits results to requests run with the specified model UUID applied. 225 | /// 226 | /// Calling this when already set will append to the models, not overwrite them. 227 | /// 228 | /// # Examples 229 | /// 230 | /// ``` 231 | /// # use deepgram::manage::usage::get_usage_options::Options; 232 | /// # 233 | /// let options = Options::builder() 234 | /// .model([ 235 | /// "4899aa60-f723-4517-9815-2042acc12a82", 236 | /// "125125fb-e391-458e-a227-a60d6426f5d6", 237 | /// ]) 238 | /// .build(); 239 | /// ``` 240 | /// 241 | /// ``` 242 | /// # use deepgram::manage::usage::get_usage_options::Options; 243 | /// # 244 | /// let options1 = Options::builder() 245 | /// .model(["4899aa60-f723-4517-9815-2042acc12a82"]) 246 | /// .model(["125125fb-e391-458e-a227-a60d6426f5d6"]) 247 | /// .build(); 248 | /// 249 | /// let options2 = Options::builder() 250 | /// .model([ 251 | /// "4899aa60-f723-4517-9815-2042acc12a82", 252 | /// "125125fb-e391-458e-a227-a60d6426f5d6", 253 | /// ]) 254 | /// .build(); 255 | /// 256 | /// assert_eq!(options1, options2); 257 | /// ``` 258 | pub fn model<'a>(mut self, model: impl IntoIterator) -> Self { 259 | self.0.models.extend(model.into_iter().map(String::from)); 260 | self 261 | } 262 | 263 | /// Limits results to requests that include the Multichannel feature. 264 | /// 265 | /// # Examples 266 | /// 267 | /// ``` 268 | /// # use deepgram::manage::usage::get_usage_options::Options; 269 | /// # 270 | /// let options = Options::builder() 271 | /// .multichannel(true) 272 | /// .build(); 273 | /// ``` 274 | pub fn multichannel(mut self, multichannel: bool) -> Self { 275 | self.0.multichannel = Some(multichannel); 276 | self 277 | } 278 | 279 | /// Limits results to requests that include the Interim Results feature. 280 | /// 281 | /// # Examples 282 | /// 283 | /// ``` 284 | /// # use deepgram::manage::usage::get_usage_options::Options; 285 | /// # 286 | /// let options = Options::builder() 287 | /// .interim_results(true) 288 | /// .build(); 289 | /// ``` 290 | pub fn interim_results(mut self, interim_results: bool) -> Self { 291 | self.0.interim_results = Some(interim_results); 292 | self 293 | } 294 | 295 | /// Limits results to requests that include the Punctuation feature. 296 | /// 297 | /// # Examples 298 | /// 299 | /// ``` 300 | /// # use deepgram::manage::usage::get_usage_options::Options; 301 | /// # 302 | /// let options = Options::builder() 303 | /// .punctuate(true) 304 | /// .build(); 305 | /// ``` 306 | pub fn punctuate(mut self, punctuate: bool) -> Self { 307 | self.0.punctuate = Some(punctuate); 308 | self 309 | } 310 | 311 | /// Limits results to requests that include the Named-Entity Recognition feature. 312 | /// 313 | /// # Examples 314 | /// 315 | /// ``` 316 | /// # use deepgram::manage::usage::get_usage_options::Options; 317 | /// # 318 | /// let options = Options::builder() 319 | /// .ner(true) 320 | /// .build(); 321 | /// ``` 322 | pub fn ner(mut self, ner: bool) -> Self { 323 | self.0.ner = Some(ner); 324 | self 325 | } 326 | 327 | /// Limits results to requests that include the Utterances feature. 328 | /// 329 | /// # Examples 330 | /// 331 | /// ``` 332 | /// # use deepgram::manage::usage::get_usage_options::Options; 333 | /// # 334 | /// let options = Options::builder() 335 | /// .utterances(true) 336 | /// .build(); 337 | /// ``` 338 | pub fn utterances(mut self, utterances: bool) -> Self { 339 | self.0.utterances = Some(utterances); 340 | self 341 | } 342 | 343 | /// Limits results to requests that include the Replace feature. 344 | /// 345 | /// # Examples 346 | /// 347 | /// ``` 348 | /// # use deepgram::manage::usage::get_usage_options::Options; 349 | /// # 350 | /// let options = Options::builder() 351 | /// .replace(true) 352 | /// .build(); 353 | /// ``` 354 | pub fn replace(mut self, replace: bool) -> Self { 355 | self.0.replace = Some(replace); 356 | self 357 | } 358 | 359 | /// Limits results to requests that include the Profanity Filter feature. 360 | /// 361 | /// # Examples 362 | /// 363 | /// ``` 364 | /// # use deepgram::manage::usage::get_usage_options::Options; 365 | /// # 366 | /// let options = Options::builder() 367 | /// .profanity_filter(true) 368 | /// .build(); 369 | /// ``` 370 | pub fn profanity_filter(mut self, profanity_filter: bool) -> Self { 371 | self.0.profanity_filter = Some(profanity_filter); 372 | self 373 | } 374 | 375 | /// Limits results to requests that include the Keywords feature. 376 | /// 377 | /// # Examples 378 | /// 379 | /// ``` 380 | /// # use deepgram::manage::usage::get_usage_options::Options; 381 | /// # 382 | /// let options = Options::builder() 383 | /// .keywords(true) 384 | /// .build(); 385 | /// ``` 386 | pub fn keywords(mut self, keywords: bool) -> Self { 387 | self.0.keywords = Some(keywords); 388 | self 389 | } 390 | 391 | /// Limits results to requests that include the Diarization feature. 392 | /// 393 | /// # Examples 394 | /// 395 | /// ``` 396 | /// # use deepgram::manage::usage::get_usage_options::Options; 397 | /// # 398 | /// let options = Options::builder() 399 | /// .diarize(true) 400 | /// .build(); 401 | /// ``` 402 | pub fn diarize(mut self, diarize: bool) -> Self { 403 | self.0.diarize = Some(diarize); 404 | self 405 | } 406 | 407 | /// Limits results to requests that include the Search feature. 408 | /// 409 | /// # Examples 410 | /// 411 | /// ``` 412 | /// # use deepgram::manage::usage::get_usage_options::Options; 413 | /// # 414 | /// let options = Options::builder() 415 | /// .search(true) 416 | /// .build(); 417 | /// ``` 418 | pub fn search(mut self, search: bool) -> Self { 419 | self.0.search = Some(search); 420 | self 421 | } 422 | 423 | /// Limits results to requests that include the Redaction feature. 424 | /// 425 | /// # Examples 426 | /// 427 | /// ``` 428 | /// # use deepgram::manage::usage::get_usage_options::Options; 429 | /// # 430 | /// let options = Options::builder() 431 | /// .redact(true) 432 | /// .build(); 433 | /// ``` 434 | pub fn redact(mut self, redact: bool) -> Self { 435 | self.0.redact = Some(redact); 436 | self 437 | } 438 | 439 | /// Limits results to requests that include the Alternatives feature. 440 | /// 441 | /// # Examples 442 | /// 443 | /// ``` 444 | /// # use deepgram::manage::usage::get_usage_options::Options; 445 | /// # 446 | /// let options = Options::builder() 447 | /// .alternatives(true) 448 | /// .build(); 449 | /// ``` 450 | pub fn alternatives(mut self, alternatives: bool) -> Self { 451 | self.0.alternatives = Some(alternatives); 452 | self 453 | } 454 | 455 | /// Limits results to requests that include the Numerals feature. 456 | /// 457 | /// # Examples 458 | /// 459 | /// ``` 460 | /// # use deepgram::manage::usage::get_usage_options::Options; 461 | /// # 462 | /// let options = Options::builder() 463 | /// .numerals(true) 464 | /// .build(); 465 | /// ``` 466 | pub fn numerals(mut self, numerals: bool) -> Self { 467 | self.0.numerals = Some(numerals); 468 | self 469 | } 470 | 471 | /// Finish building the [`Options`] object. 472 | pub fn build(self) -> Options { 473 | self.0 474 | } 475 | } 476 | 477 | impl Default for OptionsBuilder { 478 | fn default() -> Self { 479 | Self::new() 480 | } 481 | } 482 | 483 | impl<'a> From<&'a Options> for SerializableOptions<'a> { 484 | fn from(options: &'a Options) -> Self { 485 | Self(options) 486 | } 487 | } 488 | 489 | impl Serialize for SerializableOptions<'_> { 490 | fn serialize(&self, serializer: S) -> Result 491 | where 492 | S: serde::Serializer, 493 | { 494 | let mut seq = serializer.serialize_seq(None)?; 495 | 496 | // Destructuring it makes sure that we don't forget to use any of it 497 | let Options { 498 | start, 499 | end, 500 | accessor, 501 | tags, 502 | methods, 503 | models, 504 | multichannel, 505 | interim_results, 506 | punctuate, 507 | ner, 508 | utterances, 509 | replace, 510 | profanity_filter, 511 | keywords, 512 | diarize, 513 | search, 514 | redact, 515 | alternatives, 516 | numerals, 517 | } = self.0; 518 | 519 | if let Some(start) = start { 520 | seq.serialize_element(&("start", start))?; 521 | } 522 | 523 | if let Some(end) = end { 524 | seq.serialize_element(&("end", end))?; 525 | } 526 | 527 | if let Some(accessor) = accessor { 528 | seq.serialize_element(&("accessor", accessor))?; 529 | } 530 | 531 | for element in tags { 532 | seq.serialize_element(&("tag", element))?; 533 | } 534 | 535 | for element in methods { 536 | seq.serialize_element(&("method", AsRef::::as_ref(element)))?; 537 | } 538 | 539 | for element in models { 540 | seq.serialize_element(&("model", element))?; 541 | } 542 | 543 | if let Some(multichannel) = multichannel { 544 | seq.serialize_element(&("multichannel", multichannel))?; 545 | } 546 | 547 | if let Some(interim_results) = interim_results { 548 | seq.serialize_element(&("interim_results", interim_results))?; 549 | } 550 | 551 | if let Some(punctuate) = punctuate { 552 | seq.serialize_element(&("punctuate", punctuate))?; 553 | } 554 | 555 | if let Some(ner) = ner { 556 | seq.serialize_element(&("ner", ner))?; 557 | } 558 | 559 | if let Some(utterances) = utterances { 560 | seq.serialize_element(&("utterances", utterances))?; 561 | } 562 | 563 | if let Some(replace) = replace { 564 | seq.serialize_element(&("replace", replace))?; 565 | } 566 | 567 | if let Some(replace) = replace { 568 | seq.serialize_element(&("replace", replace))?; 569 | } 570 | 571 | if let Some(profanity_filter) = profanity_filter { 572 | seq.serialize_element(&("profanity_filter", profanity_filter))?; 573 | } 574 | 575 | if let Some(keywords) = keywords { 576 | seq.serialize_element(&("keywords", keywords))?; 577 | } 578 | 579 | if let Some(diarize) = diarize { 580 | seq.serialize_element(&("diarize", diarize))?; 581 | } 582 | 583 | if let Some(search) = search { 584 | seq.serialize_element(&("search", search))?; 585 | } 586 | 587 | if let Some(redact) = redact { 588 | seq.serialize_element(&("redact", redact))?; 589 | } 590 | 591 | if let Some(alternatives) = alternatives { 592 | seq.serialize_element(&("alternatives", alternatives))?; 593 | } 594 | 595 | if let Some(numerals) = numerals { 596 | seq.serialize_element(&("numerals", numerals))?; 597 | } 598 | 599 | seq.end() 600 | } 601 | } 602 | 603 | impl AsRef for Method { 604 | fn as_ref(&self) -> &str { 605 | use Method::*; 606 | 607 | match self { 608 | Sync => "sync", 609 | Async => "async", 610 | Streaming => "streaming", 611 | } 612 | } 613 | } 614 | 615 | mod serialize_options_tests { 616 | // TODO 617 | } 618 | -------------------------------------------------------------------------------- /src/manage/usage/list_requests_options.rs: -------------------------------------------------------------------------------- 1 | //! Set options for [`Usage::list_requests`](super::Usage::list_requests). 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/api-reference/#usage-all 6 | 7 | use serde::Serialize; 8 | 9 | /// Used as a parameter for [`Usage::list_requests`](super::Usage::list_requests). 10 | /// 11 | /// See the [Deepgram API Reference][api] for more info. 12 | /// 13 | /// [api]: https://developers.deepgram.com/api-reference/#usage-all 14 | #[derive(Debug, PartialEq, Clone)] 15 | pub struct Options { 16 | start: Option, 17 | end: Option, 18 | limit: Option, 19 | status: Option, 20 | } 21 | 22 | /// Used as a parameter for [`OptionsBuilder::status`]. 23 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 24 | #[non_exhaustive] 25 | pub enum Status { 26 | #[allow(missing_docs)] 27 | Succeeded, 28 | 29 | #[allow(missing_docs)] 30 | Failed, 31 | } 32 | 33 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 34 | /// 35 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 36 | #[derive(Debug, PartialEq, Clone)] 37 | pub struct OptionsBuilder(Options); 38 | 39 | #[derive(Serialize)] 40 | pub(crate) struct SerializableOptions<'a> { 41 | #[serde(skip_serializing_if = "Option::is_none")] 42 | start: &'a Option, 43 | 44 | #[serde(skip_serializing_if = "Option::is_none")] 45 | end: &'a Option, 46 | 47 | #[serde(skip_serializing_if = "Option::is_none")] 48 | limit: Option, 49 | 50 | #[serde(skip_serializing_if = "Option::is_none")] 51 | status: Option<&'static str>, 52 | } 53 | 54 | impl Options { 55 | /// Construct a new [`OptionsBuilder`]. 56 | pub fn builder() -> OptionsBuilder { 57 | OptionsBuilder::new() 58 | } 59 | 60 | /// Return the Options in urlencoded format. If serialization would 61 | /// fail, this will also return an error. 62 | /// 63 | /// This is intended primarily to help with debugging API requests. 64 | /// 65 | /// ``` 66 | /// use deepgram::manage::usage::list_requests_options::Options; 67 | /// let options = Options::builder() 68 | /// .start("2024-04-10T00:00:00Z") 69 | /// .end("2024-10-10") 70 | /// .limit(100) 71 | /// .build(); 72 | /// assert_eq!(&options.urlencoded().unwrap(), "start=2024-04-10T00%3A00%3A00Z&end=2024-10-10&limit=100") 73 | /// ``` 74 | /// 75 | pub fn urlencoded(&self) -> Result { 76 | serde_urlencoded::to_string(SerializableOptions::from(self)) 77 | } 78 | } 79 | 80 | impl OptionsBuilder { 81 | /// Construct a new [`OptionsBuilder`]. 82 | pub fn new() -> Self { 83 | Self(Options { 84 | start: None, 85 | end: None, 86 | limit: None, 87 | status: None, 88 | }) 89 | } 90 | 91 | /// Set the time range start date. 92 | /// 93 | /// # Examples 94 | /// 95 | /// ``` 96 | /// # use deepgram::manage::usage::list_requests_options::Options; 97 | /// # 98 | /// let options1 = Options::builder() 99 | /// .start("1970-01-01") 100 | /// .build(); 101 | /// ``` 102 | pub fn start(mut self, start: impl Into) -> Self { 103 | self.0.start = Some(start.into()); 104 | self 105 | } 106 | 107 | /// Set the time range end date. 108 | /// 109 | /// # Examples 110 | /// 111 | /// ``` 112 | /// # use deepgram::manage::usage::list_requests_options::Options; 113 | /// # 114 | /// let options1 = Options::builder() 115 | /// .end("2038-01-19") 116 | /// .build(); 117 | /// ``` 118 | pub fn end(mut self, end: impl Into) -> Self { 119 | self.0.end = Some(end.into()); 120 | self 121 | } 122 | 123 | /// Set the maximum number of results to return per page. 124 | /// 125 | /// # Examples 126 | /// 127 | /// ``` 128 | /// # use deepgram::manage::usage::list_requests_options::Options; 129 | /// # 130 | /// let options1 = Options::builder() 131 | /// .limit(42) 132 | /// .build(); 133 | /// ``` 134 | pub fn limit(mut self, limit: usize) -> Self { 135 | self.0.limit = Some(limit); 136 | self 137 | } 138 | 139 | /// Limits results to requests to requests that either succeeded or failed. 140 | /// 141 | /// # Examples 142 | /// 143 | /// ``` 144 | /// # use deepgram::manage::usage::list_requests_options::{Options, Status}; 145 | /// # 146 | /// let options1 = Options::builder() 147 | /// .status(Status::Succeeded) 148 | /// .build(); 149 | /// ``` 150 | pub fn status(mut self, status: Status) -> Self { 151 | self.0.status = Some(status); 152 | self 153 | } 154 | 155 | /// Finish building the [`Options`] object. 156 | pub fn build(self) -> Options { 157 | self.0 158 | } 159 | } 160 | 161 | impl Default for OptionsBuilder { 162 | fn default() -> Self { 163 | Self::new() 164 | } 165 | } 166 | 167 | impl<'a> From<&'a Options> for SerializableOptions<'a> { 168 | fn from(options: &'a Options) -> Self { 169 | // Destructuring it makes sure that we don't forget to use any of it 170 | let Options { 171 | start, 172 | end, 173 | limit, 174 | status, 175 | } = options; 176 | 177 | Self { 178 | start, 179 | end, 180 | limit: *limit, 181 | status: match status { 182 | Some(Status::Succeeded) => Some("succeeded"), 183 | Some(Status::Failed) => Some("failed"), 184 | None => None, 185 | }, 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/manage/usage/response.rs: -------------------------------------------------------------------------------- 1 | //! Deepgram usage API response types. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use uuid::Uuid; 5 | 6 | /// Returned by [`Usage::list_requests`](super::Usage::list_requests). 7 | /// 8 | /// See the [Deepgram API Reference][api] for more info. 9 | /// 10 | /// [api]: https://developers.deepgram.com/api-reference/#usage-all 11 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 12 | #[non_exhaustive] 13 | pub struct Requests { 14 | #[allow(missing_docs)] 15 | pub page: usize, 16 | 17 | #[allow(missing_docs)] 18 | pub limit: usize, 19 | 20 | #[allow(missing_docs)] 21 | pub requests: Vec, 22 | } 23 | 24 | /// Returned by [`Usage::get_request`](super::Usage::get_request). 25 | /// 26 | /// See the [Deepgram API Reference][api] for more info. 27 | /// 28 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 29 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 30 | #[non_exhaustive] 31 | pub struct Request { 32 | #[allow(missing_docs)] 33 | pub request_id: Uuid, 34 | 35 | #[allow(missing_docs)] 36 | pub created: String, 37 | 38 | #[allow(missing_docs)] 39 | pub path: String, 40 | 41 | #[allow(missing_docs)] 42 | pub api_key_id: Uuid, 43 | 44 | #[allow(missing_docs)] 45 | pub response: Option, 46 | 47 | #[allow(missing_docs)] 48 | pub callback: Option, 49 | } 50 | 51 | /// The response generated by the request. 52 | /// 53 | /// See the [Deepgram API Reference][api] for more info. 54 | /// 55 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 56 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 57 | #[non_exhaustive] 58 | pub struct Response { 59 | #[allow(missing_docs)] 60 | pub details: Option
, 61 | 62 | #[allow(missing_docs)] 63 | pub message: Option, 64 | 65 | #[allow(missing_docs)] 66 | pub code: i16, 67 | 68 | #[allow(missing_docs)] 69 | pub completed: String, 70 | } 71 | 72 | /// Details about the request. 73 | /// 74 | /// See the [Deepgram API Reference][api] for more info. 75 | /// 76 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 77 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 78 | #[non_exhaustive] 79 | pub struct Details { 80 | #[allow(missing_docs)] 81 | pub usd: Option, 82 | 83 | #[allow(missing_docs)] 84 | pub duration: f64, 85 | 86 | #[allow(missing_docs)] 87 | pub total_audio: f64, 88 | 89 | #[allow(missing_docs)] 90 | pub channels: usize, 91 | 92 | #[allow(missing_docs)] 93 | pub streams: usize, 94 | 95 | #[allow(missing_docs)] 96 | pub models: Vec, 97 | 98 | #[allow(missing_docs)] 99 | pub method: String, 100 | 101 | #[allow(missing_docs)] 102 | pub tags: Vec, 103 | 104 | #[allow(missing_docs)] 105 | pub features: Vec, 106 | 107 | #[allow(missing_docs)] 108 | pub config: Config, 109 | } 110 | 111 | /// Configuration used when running the request. 112 | /// 113 | /// See the [Deepgram API Reference][api] for more info. 114 | /// 115 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 116 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 117 | #[non_exhaustive] 118 | pub struct Config { 119 | #[allow(missing_docs)] 120 | pub alternatives: Option, 121 | 122 | #[allow(missing_docs)] 123 | pub diarize: Option, 124 | 125 | #[allow(missing_docs)] 126 | pub keywords: Option>, 127 | 128 | #[allow(missing_docs)] 129 | pub language: Option, 130 | 131 | #[allow(missing_docs)] 132 | pub model: Option, 133 | 134 | #[allow(missing_docs)] 135 | pub tier: Option, 136 | 137 | #[allow(missing_docs)] 138 | pub multichannel: Option, 139 | 140 | #[allow(missing_docs)] 141 | pub ner: Option, 142 | 143 | #[allow(missing_docs)] 144 | pub numerals: Option, 145 | 146 | #[allow(missing_docs)] 147 | pub profanity_filter: Option, 148 | 149 | #[allow(missing_docs)] 150 | pub punctuate: Option, 151 | 152 | #[allow(missing_docs)] 153 | pub redact: Option>, 154 | 155 | #[allow(missing_docs)] 156 | pub search: Option>, 157 | 158 | #[allow(missing_docs)] 159 | pub utterances: Option, 160 | } 161 | 162 | /// Details about a callback request. 163 | /// 164 | /// See the [Deepgram API Reference][api] for more info. 165 | /// 166 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 167 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 168 | #[non_exhaustive] 169 | pub struct Callback { 170 | #[allow(missing_docs)] 171 | pub attempts: usize, 172 | 173 | #[allow(missing_docs)] 174 | pub code: Option, 175 | 176 | #[allow(missing_docs)] 177 | pub completed: Option, 178 | } 179 | 180 | /// Returned by [`Usage::get_usage`](super::Usage::get_usage). 181 | /// 182 | /// See the [Deepgram API Reference][api] for more info. 183 | /// 184 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 185 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 186 | #[non_exhaustive] 187 | pub struct UsageSummary { 188 | #[allow(missing_docs)] 189 | pub start: String, 190 | 191 | #[allow(missing_docs)] 192 | pub end: String, 193 | 194 | #[allow(missing_docs)] 195 | pub resolution: Resolution, 196 | 197 | #[allow(missing_docs)] 198 | pub results: Vec, 199 | } 200 | 201 | /// The amount of time covered by each [`Result`]. 202 | /// 203 | /// See the [Deepgram API Reference][api] for more info. 204 | /// 205 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 206 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 207 | #[non_exhaustive] 208 | pub struct Resolution { 209 | #[allow(missing_docs)] 210 | pub units: String, 211 | 212 | #[allow(missing_docs)] 213 | pub amount: usize, 214 | } 215 | 216 | /// A summary of the usage over a period of time. 217 | /// 218 | /// The resolution of each result is defined in [`UsageSummary::resolution`]. 219 | /// 220 | /// See the [Deepgram API Reference][api] for more info. 221 | /// 222 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 223 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 224 | #[non_exhaustive] 225 | pub struct Result { 226 | #[allow(missing_docs)] 227 | pub start: String, 228 | 229 | #[allow(missing_docs)] 230 | pub end: String, 231 | 232 | #[allow(missing_docs)] 233 | pub hours: f64, 234 | 235 | #[allow(missing_docs)] 236 | pub total_hours: f64, 237 | 238 | #[allow(missing_docs)] 239 | pub requests: usize, 240 | } 241 | 242 | /// Returned by [`Usage::get_fields`](super::Usage::get_fields). 243 | /// 244 | /// See the [Deepgram API Reference][api] for more info. 245 | /// 246 | /// [api]: https://developers.deepgram.com/api-reference/#usage-fields 247 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 248 | #[non_exhaustive] 249 | pub struct Fields { 250 | #[allow(missing_docs)] 251 | pub tags: Vec, 252 | 253 | #[allow(missing_docs)] 254 | pub models: Vec, 255 | 256 | #[allow(missing_docs)] 257 | pub processing_methods: Vec, 258 | 259 | #[allow(missing_docs)] 260 | pub features: Vec, 261 | } 262 | 263 | /// Details about the model used. 264 | /// 265 | /// See the [Deepgram API Reference][api] for more info. 266 | /// 267 | /// [api]: https://developers.deepgram.com/api-reference/#usage-fields 268 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 269 | #[non_exhaustive] 270 | pub struct ModelDetail { 271 | #[allow(missing_docs)] 272 | pub name: String, 273 | 274 | #[allow(missing_docs)] 275 | pub language: String, 276 | 277 | #[allow(missing_docs)] 278 | pub version: String, 279 | 280 | #[allow(missing_docs)] 281 | pub model_id: Uuid, 282 | } 283 | -------------------------------------------------------------------------------- /src/speak/mod.rs: -------------------------------------------------------------------------------- 1 | //! Speak module 2 | 3 | pub mod options; 4 | pub mod rest; 5 | -------------------------------------------------------------------------------- /src/speak/options.rs: -------------------------------------------------------------------------------- 1 | //! Set various Deepgram features to control how the speech is generated. 2 | //! 3 | //! See the [Deepgram API Reference][api] for more info. 4 | //! 5 | //! [api]: https://developers.deepgram.com/docs/tts-feature-overview 6 | 7 | use serde::{ser::SerializeSeq, Deserialize, Serialize}; 8 | 9 | /// Used as a parameter for [`OptionsBuilder::model`]. 10 | /// 11 | /// See the [Deepgram Model feature docs][docs] for more info. 12 | /// 13 | /// [docs]: https://developers.deepgram.com/docs/tts-models 14 | #[derive(Debug, PartialEq, Eq, Clone, Hash)] 15 | #[non_exhaustive] 16 | pub enum Model { 17 | #[allow(missing_docs)] 18 | AuraAsteriaEn, 19 | 20 | #[allow(missing_docs)] 21 | AuraLunaEn, 22 | 23 | #[allow(missing_docs)] 24 | AuraStellaEn, 25 | 26 | #[allow(missing_docs)] 27 | AuraAthenaEn, 28 | 29 | #[allow(missing_docs)] 30 | AuraHeraEn, 31 | 32 | #[allow(missing_docs)] 33 | AuraOrionEn, 34 | 35 | #[allow(missing_docs)] 36 | AuraArcasEn, 37 | 38 | #[allow(missing_docs)] 39 | AuraPerseusEn, 40 | 41 | #[allow(missing_docs)] 42 | AuraAngusEn, 43 | 44 | #[allow(missing_docs)] 45 | AuraOrpheusEn, 46 | 47 | #[allow(missing_docs)] 48 | AuraHeliosEn, 49 | 50 | #[allow(missing_docs)] 51 | AuraZeusEn, 52 | 53 | #[allow(missing_docs)] 54 | CustomId(String), 55 | } 56 | 57 | impl AsRef for Model { 58 | fn as_ref(&self) -> &str { 59 | match self { 60 | Self::AuraAsteriaEn => "aura-asteria-en", 61 | Self::AuraLunaEn => "aura-luna-en", 62 | Self::AuraStellaEn => "aura-stella-en", 63 | Self::AuraAthenaEn => "aura-athena-en", 64 | Self::AuraHeraEn => "aura-hera-en", 65 | Self::AuraOrionEn => "aura-orion-en", 66 | Self::AuraArcasEn => "aura-arcas-en", 67 | Self::AuraPerseusEn => "aura-perseus-en", 68 | Self::AuraAngusEn => "aura-angus-en", 69 | Self::AuraOrpheusEn => "aura-orpheus-en", 70 | Self::AuraHeliosEn => "aura-helios-en", 71 | Self::AuraZeusEn => "aura-zeus-en", 72 | Self::CustomId(id) => id, 73 | } 74 | } 75 | } 76 | 77 | /// Encoding value 78 | /// 79 | /// See the [Deepgram Encoding feature docs][docs] for more info. 80 | /// 81 | /// [docs]: https://developers.deepgram.com/docs/tts-encoding 82 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 83 | #[serde(rename_all = "lowercase")] 84 | #[non_exhaustive] 85 | pub enum Encoding { 86 | /// 16-bit, little endian, signed PCM WAV data 87 | Linear16, 88 | /// Mu-law encoded WAV data 89 | Mulaw, 90 | /// Alaw 91 | Alaw, 92 | /// Mp3 93 | Mp3, 94 | /// Ogg Opus 95 | Opus, 96 | /// Free Lossless Audio Codec (FLAC) encoded data 97 | Flac, 98 | /// Aac 99 | Aac, 100 | 101 | #[allow(missing_docs)] 102 | CustomEncoding(String), 103 | } 104 | 105 | /// TTSEncoding Impl 106 | impl Encoding { 107 | pub(crate) fn as_str(&self) -> &str { 108 | match self { 109 | Encoding::Linear16 => "linear16", 110 | Encoding::Mulaw => "mulaw", 111 | Encoding::Alaw => "alaw", 112 | Encoding::Mp3 => "mp3", 113 | Encoding::Opus => "opus", 114 | Encoding::Flac => "flac", 115 | Encoding::Aac => "aac", 116 | Encoding::CustomEncoding(encoding) => encoding, 117 | } 118 | } 119 | } 120 | 121 | /// Container value 122 | /// 123 | /// See the [Deepgram Container feature docs][docs] for more info. 124 | /// 125 | /// [docs]: https://developers.deepgram.com/docs/tts-container 126 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 127 | #[serde(rename_all = "lowercase")] 128 | #[non_exhaustive] 129 | pub enum Container { 130 | #[allow(missing_docs)] 131 | Wav, 132 | #[allow(missing_docs)] 133 | Ogg, 134 | #[allow(missing_docs)] 135 | None, 136 | 137 | #[allow(missing_docs)] 138 | CustomContainer(String), 139 | } 140 | 141 | /// Encoding Impl 142 | impl Container { 143 | pub(crate) fn as_str(&self) -> &str { 144 | match self { 145 | Container::Wav => "wav", 146 | Container::Ogg => "ogg", 147 | Container::None => "nonne", 148 | Container::CustomContainer(container) => container, 149 | } 150 | } 151 | } 152 | 153 | /// Used as a parameter for [`Speak::speak_to_file`](crate::Speak::speak_to_file) and similar functions. 154 | #[derive(Debug, PartialEq, Clone)] 155 | pub struct Options { 156 | model: Option, 157 | encoding: Option, 158 | sample_rate: Option, 159 | container: Option, 160 | bit_rate: Option, 161 | } 162 | 163 | /// Builds an [`Options`] object using [the Builder pattern][builder]. 164 | /// 165 | /// Use it to set any of Deepgram's features except the Callback feature. 166 | /// The Callback feature can be set when making the request by calling [`Transcription::prerecorded_callback`](crate::Speak::speak_to_file). 167 | /// 168 | /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html 169 | #[derive(Debug, PartialEq, Clone)] 170 | pub struct OptionsBuilder(Options); 171 | 172 | #[derive(Debug, PartialEq, Clone)] 173 | pub(super) struct SerializableOptions<'a>(pub(super) &'a Options); 174 | 175 | impl Options { 176 | /// Construct a new [`OptionsBuilder`]. 177 | pub fn builder() -> OptionsBuilder { 178 | OptionsBuilder::new() 179 | } 180 | 181 | /// Return the Options in urlencoded format. If serialization would 182 | /// fail, this will also return an error. 183 | /// 184 | /// This is intended primarily to help with debugging API requests. 185 | /// 186 | /// ``` 187 | /// use deepgram::speak::options::{Encoding, Model, Options}; 188 | /// let options = Options::builder() 189 | /// .model(Model::AuraArcasEn) 190 | /// .encoding(Encoding::Flac) 191 | /// .build(); 192 | /// assert_eq!(&options.urlencoded().unwrap(), "model=aura-arcas-en&encoding=flac") 193 | /// ``` 194 | /// 195 | pub fn urlencoded(&self) -> Result { 196 | serde_urlencoded::to_string(SerializableOptions(self)) 197 | } 198 | } 199 | 200 | impl OptionsBuilder { 201 | /// Construct a new [`OptionsBuilder`]. 202 | pub fn new() -> Self { 203 | Self(Options { 204 | model: None, 205 | encoding: None, 206 | sample_rate: None, 207 | container: None, 208 | bit_rate: None, 209 | }) 210 | } 211 | 212 | /// Set the Model feature. 213 | /// 214 | /// See the [Deepgram Model feature docs][docs] for more info. 215 | /// 216 | /// [docs]: https://developers.deepgram.com/docs/tts-models 217 | pub fn model(mut self, model: Model) -> Self { 218 | self.0.model = Some(model); 219 | self 220 | } 221 | 222 | /// Set the Encoding feature. 223 | /// 224 | /// See the [Deepgram Encoding feature docs][docs] for more info. 225 | /// 226 | /// [docs]: https://developers.deepgram.com/docs/tts-encoding 227 | pub fn encoding(mut self, encoding: Encoding) -> Self { 228 | self.0.encoding = Some(encoding); 229 | self 230 | } 231 | 232 | /// Set the Sample Rate feature. 233 | /// 234 | /// See the [Deepgram Sample Rate feature docs][docs] for more info. 235 | /// 236 | /// [docs]: https://developers.deepgram.com/docs/tts-sample-rate 237 | pub fn sample_rate(mut self, sample_rate: u32) -> Self { 238 | self.0.sample_rate = Some(sample_rate); 239 | self 240 | } 241 | 242 | /// Set the Container feature. 243 | /// 244 | /// See the [Deepgram Container docs][docs] for more info. 245 | /// 246 | /// [docs]: https://developers.deepgram.com/docs/tts-container 247 | pub fn container(mut self, container: Container) -> Self { 248 | self.0.container = Some(container); 249 | self 250 | } 251 | 252 | /// Set the Bit Rate feature. 253 | /// 254 | /// See the [Deepgram Bit Rate feature docs][docs] for more info. 255 | /// 256 | /// [docs]: https://developers.deepgram.com/docs/tts-bit-rate 257 | pub fn bit_rate(mut self, bit_rate: u32) -> Self { 258 | self.0.bit_rate = Some(bit_rate); 259 | self 260 | } 261 | 262 | /// Finish building the [`Options`] object. 263 | pub fn build(self) -> Options { 264 | self.0 265 | } 266 | } 267 | 268 | impl Default for OptionsBuilder { 269 | fn default() -> Self { 270 | Self::new() 271 | } 272 | } 273 | 274 | impl Serialize for SerializableOptions<'_> { 275 | fn serialize(&self, serializer: S) -> Result 276 | where 277 | S: serde::Serializer, 278 | { 279 | let mut seq = serializer.serialize_seq(None)?; 280 | 281 | // Destructuring it makes sure that we don't forget to use any of it 282 | let Options { 283 | model, 284 | encoding, 285 | sample_rate, 286 | container, 287 | bit_rate, 288 | } = self.0; 289 | 290 | if let Some(model) = model { 291 | seq.serialize_element(&("model", model.as_ref()))?; 292 | } 293 | 294 | if let Some(encoding) = encoding { 295 | seq.serialize_element(&("encoding", encoding.as_str()))?; 296 | } 297 | 298 | if let Some(sample_rate) = sample_rate { 299 | seq.serialize_element(&("sample_rate", sample_rate))?; 300 | } 301 | 302 | if let Some(container) = container { 303 | seq.serialize_element(&("container", container.as_str()))?; 304 | } 305 | 306 | if let Some(bit_rate) = bit_rate { 307 | seq.serialize_element(&("bit_rate", bit_rate))?; 308 | } 309 | 310 | seq.end() 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /src/speak/rest.rs: -------------------------------------------------------------------------------- 1 | //! Rest TTS module 2 | 3 | use bytes::Bytes; 4 | use futures::stream::{Stream, StreamExt}; 5 | use reqwest::RequestBuilder; 6 | use serde_json::Value; 7 | use tokio::sync::mpsc; 8 | use tokio_stream::wrappers::ReceiverStream; 9 | use url::Url; 10 | 11 | use crate::{DeepgramError, Speak}; 12 | 13 | use super::options::{Options, SerializableOptions}; 14 | 15 | static DEEPGRAM_API_URL_SPEAK: &str = "v1/speak"; 16 | 17 | impl Speak<'_> { 18 | /// Sends a request to Deepgram to transcribe pre-recorded audio. 19 | pub async fn speak_to_file( 20 | &self, 21 | text: &str, 22 | options: &Options, 23 | output_file: &std::path::Path, 24 | ) -> Result<(), DeepgramError> { 25 | let payload = Value::Object( 26 | [("text".to_string(), Value::String(text.to_string()))] 27 | .iter() 28 | .cloned() 29 | .collect(), 30 | ); 31 | 32 | let request_builder = self 33 | .0 34 | .client 35 | .post(self.speak_url()) 36 | .query(&SerializableOptions(options)) 37 | .json(&payload); 38 | 39 | self.send_and_save_response(request_builder, output_file) 40 | .await 41 | } 42 | 43 | async fn send_and_save_response( 44 | &self, 45 | request_builder: RequestBuilder, 46 | output_file: &std::path::Path, 47 | ) -> Result<(), DeepgramError> { 48 | let mut response = request_builder.send().await?; 49 | 50 | if let Err(err) = response.error_for_status_ref() { 51 | let status = response.status(); 52 | let error_text = response.text().await?; 53 | eprintln!("Failed to generate speech: {}", status); 54 | eprintln!("Error details: {}", error_text); 55 | return Err(DeepgramError::DeepgramApiError { 56 | body: error_text, 57 | err, 58 | }); 59 | } 60 | 61 | // Create the output file 62 | let mut file = std::fs::File::create(output_file)?; 63 | 64 | // Stream the response body to the file 65 | while let Some(chunk) = response.chunk().await? { 66 | std::io::copy(&mut chunk.as_ref(), &mut file)?; 67 | } 68 | 69 | println!("Audio saved to {:?}", output_file); 70 | 71 | Ok(()) 72 | } 73 | 74 | /// Sends a request to Deepgram to transcribe pre-recorded audio. 75 | pub async fn speak_to_stream( 76 | &self, 77 | text: &str, 78 | options: &Options, 79 | ) -> Result, DeepgramError> { 80 | let payload = Value::Object( 81 | [("text".to_string(), Value::String(text.to_string()))] 82 | .iter() 83 | .cloned() 84 | .collect(), 85 | ); 86 | 87 | let request_builder = self 88 | .0 89 | .client 90 | .post(self.speak_url()) 91 | .query(&SerializableOptions(options)) 92 | .json(&payload); 93 | 94 | self.send_and_stream_response(request_builder).await 95 | } 96 | 97 | async fn send_and_stream_response( 98 | &self, 99 | request_builder: RequestBuilder, 100 | ) -> Result, DeepgramError> { 101 | let response = request_builder.send().await?; 102 | 103 | if let Err(err) = response.error_for_status_ref() { 104 | let status = response.status(); 105 | let error_text = response.text().await?; 106 | eprintln!("Failed to generate speech: {}", status); 107 | eprintln!("Error details: {}", error_text); 108 | return Err(DeepgramError::DeepgramApiError { 109 | body: error_text, 110 | err, 111 | }); 112 | } 113 | 114 | let (tx, rx) = mpsc::channel(1024); 115 | let rx_stream = ReceiverStream::new(rx); 116 | 117 | tokio::spawn(async move { 118 | let mut stream = response.bytes_stream(); 119 | 120 | while let Some(chunk) = stream.next().await { 121 | match chunk { 122 | Ok(data) => { 123 | if tx.send(data).await.is_err() { 124 | break; 125 | } 126 | } 127 | Err(e) => { 128 | eprintln!("Error streaming response: {}", e); 129 | break; 130 | } 131 | } 132 | } 133 | }); 134 | 135 | Ok(rx_stream) 136 | } 137 | 138 | fn speak_url(&self) -> Url { 139 | self.0.base_url.join(DEEPGRAM_API_URL_SPEAK).unwrap() 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | use crate::Deepgram; 146 | 147 | #[test] 148 | fn listen_url() { 149 | let dg = Deepgram::new("token").unwrap(); 150 | assert_eq!( 151 | &dg.text_to_speech().speak_url().to_string(), 152 | "https://api.deepgram.com/v1/speak" 153 | ); 154 | } 155 | } 156 | --------------------------------------------------------------------------------