├── .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 4 | .DS_Store -------------------------------------------------------------------------------- /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.7.0" 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 | bytes = "1" 23 | futures = "^0.3" 24 | http = "1.3" 25 | pin-project = "1" 26 | reqwest = { version = "^0.12", default-features = false, features = [ 27 | "json", 28 | "rustls-tls", 29 | "stream", 30 | ] } 31 | serde = { version = "^1.0.219", features = ["derive"] } 32 | serde_json = "1" 33 | serde_urlencoded = "0.7" 34 | thiserror = "2" 35 | tokio = { version = "^1.45.1", features = ["full"] } 36 | tokio-stream = "^0.1.17" 37 | tokio-tungstenite = { version = "^0.27.0", features = [ 38 | "rustls-tls-webpki-roots", 39 | ], optional = true } 40 | tokio-util = { version = "^0.7", features = ["codec", "io"] } 41 | tungstenite = { version = "^0.27", optional = true } 42 | url = "2" 43 | uuid = { version = "1", features = ["serde"] } 44 | # Dependencies below are specified only to satisfy minimal-versions. 45 | sha256 = "^1.6.0" 46 | anyhow = "^1.0.98" 47 | tracing = ">=0.1.41" 48 | 49 | [dev-dependencies] 50 | cpal = "^0.16" 51 | crossbeam = "0.8" 52 | audio = "0.2.0" 53 | rodio = { version = "0.20" } 54 | pkg-config = { version = "0.3.30" } 55 | 56 | [features] 57 | default = ["manage", "listen", "speak"] 58 | manage = [] 59 | listen = ["dep:tungstenite", "dep:tokio-tungstenite"] 60 | speak = [] 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 | ## Quick Start 19 | 20 | Check out the [examples folder](./examples/) for practical code examples showing how to use the SDK. 21 | 22 | ## Authentication 23 | 24 | 🔑 To access the Deepgram API you will need a [free Deepgram API Key](https://console.deepgram.com/signup?jump=keys). 25 | 26 | There are two ways to authenticate with the Deepgram API: 27 | 28 | 1. **API Key**: This is the simplest method. You can get a free API key from the 29 | [Deepgram Console](https://console.deepgram.com/signup?jump=keys). 30 | 31 | ```rust 32 | use deepgram::Deepgram; 33 | 34 | let dg = Deepgram::new("YOUR_DEEPGRAM_API_KEY"); 35 | ``` 36 | 37 | 2. **Temporary Tokens**: If you are building an application where you need to 38 | grant temporary access to the Deepgram API, you can use temporary tokens. 39 | This is useful for client-side applications where you don't want to expose 40 | your API key. 41 | 42 | You can create temporary tokens using the Deepgram API. Learn more about 43 | [token-based authentication](https://developers.deepgram.com/guides/fundamentals/token-based-authentication). 44 | 45 | ```rust 46 | use deepgram::Deepgram; 47 | 48 | let dg = Deepgram::with_temp_token("YOUR_TEMPORARY_TOKEN"); 49 | ``` 50 | 51 | ## Current Status 52 | 53 | This SDK is currently Community owned but is moving to a stable `1.0` version soon. 54 | 55 | ## Install 56 | 57 | From within your Cargo project directory, run the following command: 58 | 59 | ```sh 60 | cargo add deepgram 61 | ``` 62 | 63 | You will also probably need to install [`tokio`](https://crates.io/crates/tokio): 64 | 65 | ```sh 66 | cargo add tokio --features full 67 | ``` 68 | 69 | ## Development and Contributing 70 | 71 | Interested in contributing? We ❤️ pull requests! 72 | 73 | To make sure our community is safe for all, be sure to review and agree to our 74 | [Code of Conduct](./CODE_OF_CONDUCT.md) and review our 75 | [Contributing Guidelines](./CONTRIBUTING.md). 76 | 77 | ### Build the SDK 78 | 79 | ```sh 80 | cargo build 81 | ``` 82 | 83 | ## Getting Help 84 | 85 | We love to hear from you so if you have questions, comments or find a bug in the 86 | project, let us know! You can either: 87 | 88 | - [Open an issue in this repository](https://github.com/deepgram/deepgram-rust-sdk/issues/new) 89 | - [Join the Deepgram Github Discussions Community](https://github.com/orgs/deepgram/discussions) 90 | - [Join the Deepgram Discord Community](https://discord.gg/xWRaCDBtW4) 91 | 92 | [license]: LICENSE.txt 93 | -------------------------------------------------------------------------------- /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/d2f2723e64375d771086859d56c2b4434757a2da/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: {elapsed_time:.2?}"); 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: {elapsed_time:.2?}"); 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, SampleFormat}; 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 | macro_rules! create_stream { 16 | ($device:ident, $config:expr, $sync_tx:ident, $sample_type:ty) => { 17 | $device 18 | .build_input_stream( 19 | &$config.into(), 20 | move |data: &[$sample_type], _: &_| { 21 | let mut bytes = BytesMut::with_capacity(data.len() * 2); 22 | for sample in data { 23 | bytes.put_i16_le(sample.to_sample()); 24 | } 25 | $sync_tx.send(bytes.freeze()).unwrap(); 26 | }, 27 | |_| panic!(), 28 | None, 29 | ) 30 | .unwrap() 31 | }; 32 | } 33 | 34 | fn microphone_as_stream() -> FuturesReceiver> { 35 | let (sync_tx, sync_rx) = crossbeam::channel::unbounded(); 36 | let (mut async_tx, async_rx) = mpsc::channel(1); 37 | 38 | thread::spawn(move || { 39 | let host = cpal::default_host(); 40 | let device = host.default_input_device().unwrap(); 41 | 42 | // let config = device.supported_input_configs().unwrap(); 43 | // for config in config { 44 | // dbg!(&config); 45 | // } 46 | 47 | let config = device.default_input_config().unwrap(); 48 | 49 | // dbg!(&config); 50 | 51 | let stream = match config.sample_format() { 52 | SampleFormat::F32 => create_stream!(device, config, sync_tx, f32), 53 | SampleFormat::I16 => create_stream!(device, config, sync_tx, i16), 54 | SampleFormat::U16 => create_stream!(device, config, sync_tx, u16), 55 | sample_format => { 56 | panic!("Unsupported sample format: {sample_format:?}"); 57 | } 58 | }; 59 | 60 | stream.play().unwrap(); 61 | 62 | loop { 63 | thread::park(); 64 | } 65 | }); 66 | 67 | tokio::spawn(async move { 68 | loop { 69 | let data = sync_rx.recv(); 70 | async_tx.send(data).await.unwrap(); 71 | } 72 | }); 73 | 74 | async_rx 75 | } 76 | 77 | #[tokio::main] 78 | async fn main() -> Result<(), DeepgramError> { 79 | let deepgram_api_key = 80 | env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 81 | 82 | let dg_client = Deepgram::new(&deepgram_api_key)?; 83 | 84 | let mut results = dg_client 85 | .transcription() 86 | .stream_request() 87 | .keep_alive() 88 | .encoding(Encoding::Linear16) 89 | // TODO Specific to my machine, not general enough example. 90 | .sample_rate(44100) 91 | // TODO Specific to my machine, not general enough example. 92 | .channels(2) 93 | .stream(microphone_as_stream()) 94 | .await?; 95 | 96 | println!("Deepgram Request ID: {}", results.request_id()); 97 | while let Some(result) = results.next().await { 98 | println!("got: {result:?}"); 99 | } 100 | 101 | Ok(()) 102 | } 103 | -------------------------------------------------------------------------------- /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 | #[allow(missing_docs)] 64 | pub language: Option, 65 | } 66 | 67 | /// Transcription results. 68 | /// 69 | /// See the [Deepgram API Reference][api] for more info. 70 | /// 71 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 72 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 73 | #[non_exhaustive] 74 | pub struct ListenResults { 75 | #[allow(missing_docs)] 76 | pub channels: Vec, 77 | 78 | /// [`None`] unless the [Utterances feature][docs] is set. 79 | /// 80 | /// [docs]: https://developers.deepgram.com/documentation/features/utterances/ 81 | pub utterances: Option>, 82 | 83 | #[allow(missing_docs)] 84 | pub intents: Option, 85 | 86 | #[allow(missing_docs)] 87 | pub sentiments: Option, 88 | 89 | #[allow(missing_docs)] 90 | pub topics: Option, 91 | 92 | #[allow(missing_docs)] 93 | pub summary: Option, 94 | } 95 | 96 | /// Transcription results for a single audio channel. 97 | /// 98 | /// See the [Deepgram API Reference][api] 99 | /// and the [Deepgram Multichannel feature docs][docs] for more info. 100 | /// 101 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 102 | /// [docs]: https://developers.deepgram.com/documentation/features/multichannel/ 103 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 104 | #[non_exhaustive] 105 | pub struct ChannelResult { 106 | /// [`None`] unless the [Search feature][docs] is set. 107 | /// 108 | /// [docs]: https://developers.deepgram.com/docs/search/ 109 | pub search: Option>, 110 | 111 | #[allow(missing_docs)] 112 | pub alternatives: Vec, 113 | 114 | /// [BCP-47][bcp47] language tag for the dominant language identified in the channel. 115 | /// 116 | /// [`None`] unless the [Language Detection feature][docs] is set. 117 | /// 118 | /// [bcp47]: https://tools.ietf.org/html/bcp47 119 | /// [docs]: https://developers.deepgram.com/docs/language-detection/ 120 | pub detected_language: Option, 121 | } 122 | 123 | /// Transcription results for a single utterance. 124 | /// 125 | /// See the [Deepgram Utterance feature docs][docs] for more info. 126 | /// 127 | /// [docs]: https://developers.deepgram.com/documentation/features/utterances/ 128 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 129 | #[non_exhaustive] 130 | pub struct Utterance { 131 | #[allow(missing_docs)] 132 | pub start: f64, 133 | 134 | #[allow(missing_docs)] 135 | pub end: f64, 136 | 137 | #[allow(missing_docs)] 138 | pub confidence: f64, 139 | 140 | #[allow(missing_docs)] 141 | pub channel: usize, 142 | 143 | #[allow(missing_docs)] 144 | pub transcript: String, 145 | 146 | #[allow(missing_docs)] 147 | pub words: Vec, 148 | 149 | /// [`None`] unless the [Diarization feature][docs] is set. 150 | /// 151 | /// [docs]: https://developers.deepgram.com/docs/diarization 152 | pub speaker: Option, 153 | 154 | #[allow(missing_docs)] 155 | pub id: Uuid, 156 | } 157 | 158 | /// Search results. 159 | /// 160 | /// See the [Deepgram API Reference][api] 161 | /// and the [Deepgram Search feature docs][docs] for more info. 162 | /// 163 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 164 | /// [docs]: https://developers.deepgram.com/documentation/features/search/ 165 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 166 | #[non_exhaustive] 167 | pub struct SearchResults { 168 | #[allow(missing_docs)] 169 | pub query: String, 170 | 171 | #[allow(missing_docs)] 172 | pub hits: Vec, 173 | } 174 | 175 | /// Sentence 176 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 177 | pub struct Sentence { 178 | text: String, 179 | start: f64, 180 | end: f64, 181 | } 182 | 183 | /// Paragraph 184 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 185 | pub struct Paragraph { 186 | sentences: Vec, 187 | num_words: usize, 188 | start: f64, 189 | end: f64, 190 | } 191 | 192 | /// Paragraph results. 193 | /// 194 | /// See the [Deepgram API Reference][api] 195 | /// and the [Deepgram Search feature docs][docs] for more info. 196 | /// 197 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 198 | /// [docs]: https://developers.deepgram.com/docs/paragraphs 199 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 200 | pub struct Paragraphs { 201 | transcript: String, 202 | paragraphs: Vec, 203 | } 204 | 205 | /// Entity Detection results. 206 | /// 207 | /// See the [Deepgram API Reference][api] 208 | /// and the [Deepgram Search feature docs][docs] for more info. 209 | /// 210 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 211 | /// [docs]: https://developers.deepgram.com/docs/detect-entities 212 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 213 | pub struct Entity { 214 | label: String, 215 | value: String, 216 | confidence: f64, 217 | start_word: usize, 218 | end_word: usize, 219 | } 220 | 221 | /// Intent 222 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 223 | pub struct Intent { 224 | intent: String, 225 | confidence_score: f64, 226 | } 227 | 228 | /// Segment 229 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 230 | pub struct Segment { 231 | text: String, 232 | start_word: usize, 233 | end_word: usize, 234 | intents: Vec, 235 | } 236 | 237 | /// Intent Recognition results. 238 | /// 239 | /// See the [Deepgram API Reference][api] 240 | /// and the [Deepgram Search feature docs][docs] for more info. 241 | /// 242 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 243 | /// [docs]: https://developers.deepgram.com/docs/intent-recognition 244 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 245 | pub struct Intents { 246 | segments: Vec, 247 | } 248 | 249 | /// SentimentSegment 250 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 251 | pub struct SentimentSegment { 252 | text: String, 253 | start_word: usize, 254 | end_word: usize, 255 | sentiment: String, 256 | sentiment_score: f64, 257 | } 258 | 259 | /// SentimentAverage 260 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 261 | pub struct SentimentAverage { 262 | sentiment: String, 263 | sentiment_score: f64, 264 | } 265 | 266 | /// Sentiment Analysis results. 267 | /// 268 | /// See the [Deepgram API Reference][api] 269 | /// and the [Deepgram Search feature docs][docs] for more info. 270 | /// 271 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 272 | /// [docs]: https://developers.deepgram.com/docs/sentiment-analysis 273 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 274 | pub struct Sentiments { 275 | segments: Vec, 276 | average: SentimentAverage, 277 | } 278 | 279 | /// TopicDetail 280 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 281 | pub struct TopicDetail { 282 | topic: String, 283 | confidence_score: f64, 284 | } 285 | 286 | /// TopicSegment 287 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 288 | pub struct TopicSegment { 289 | text: String, 290 | start_word: usize, 291 | end_word: usize, 292 | topics: Vec, 293 | } 294 | 295 | /// Topics Detection results. 296 | /// 297 | /// See the [Deepgram API Reference][api] 298 | /// and the [Deepgram Search feature docs][docs] for more info. 299 | /// 300 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 301 | /// [docs]: https://developers.deepgram.com/docs/topic-detection 302 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 303 | pub struct Topics { 304 | segments: Vec, 305 | } 306 | 307 | /// Summary results. 308 | /// 309 | /// See the [Deepgram API Reference][api] 310 | /// and the [Deepgram Search feature docs][docs] for more info. 311 | /// 312 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 313 | /// [docs]: https://developers.deepgram.com/docs/summarization 314 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] 315 | pub struct Summary { 316 | result: String, 317 | short: String, 318 | } 319 | 320 | /// Transcript alternatives. 321 | /// 322 | /// See the [Deepgram API Reference][api] for more info. 323 | /// 324 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 325 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 326 | #[non_exhaustive] 327 | pub struct ResultAlternative { 328 | #[allow(missing_docs)] 329 | pub transcript: String, 330 | 331 | #[allow(missing_docs)] 332 | pub confidence: f64, 333 | 334 | #[allow(missing_docs)] 335 | pub words: Vec, 336 | 337 | #[allow(missing_docs)] 338 | pub paragraphs: Option, 339 | 340 | #[allow(missing_docs)] 341 | pub entities: Option>, 342 | 343 | #[allow(missing_docs)] 344 | #[serde(default)] 345 | pub languages: Vec, 346 | } 347 | 348 | /// A single transcribed word. 349 | /// 350 | /// See the [Deepgram API Reference][api] for more info. 351 | /// 352 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 353 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 354 | #[non_exhaustive] 355 | pub struct Word { 356 | #[allow(missing_docs)] 357 | pub word: String, 358 | 359 | #[allow(missing_docs)] 360 | pub start: f64, 361 | 362 | #[allow(missing_docs)] 363 | pub end: f64, 364 | 365 | #[allow(missing_docs)] 366 | pub confidence: f64, 367 | 368 | /// [`None`] unless the [Diarization feature][docs] is set. 369 | /// 370 | /// [docs]: https://developers.deepgram.com/documentation/features/diarize/ 371 | pub speaker: Option, 372 | 373 | /// [`None`] unless the [Punctuation feature][docs] is set. 374 | /// 375 | /// [docs]: https://developers.deepgram.com/documentation/features/punctuate/ 376 | pub punctuated_word: Option, 377 | } 378 | 379 | /// Search result. 380 | /// 381 | /// See the [Deepgram API Reference][api] 382 | /// and the [Deepgram Search feature docs][docs] for more info. 383 | /// 384 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 385 | /// [docs]: https://developers.deepgram.com/documentation/features/search/ 386 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 387 | #[non_exhaustive] 388 | pub struct Hit { 389 | #[allow(missing_docs)] 390 | pub confidence: f64, 391 | 392 | #[allow(missing_docs)] 393 | pub start: f64, 394 | 395 | #[allow(missing_docs)] 396 | pub end: f64, 397 | 398 | #[allow(missing_docs)] 399 | pub snippet: String, 400 | } 401 | -------------------------------------------------------------------------------- /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 | #[allow(missing_docs)] 31 | pub language: Option, 32 | } 33 | 34 | /// Transcript alternatives. 35 | /// 36 | /// See the [Deepgram API Reference][api] for more info. 37 | /// 38 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 39 | #[derive(Debug, Serialize, Deserialize)] 40 | pub struct Alternatives { 41 | #[allow(missing_docs)] 42 | pub transcript: String, 43 | 44 | #[allow(missing_docs)] 45 | pub words: Vec, 46 | 47 | #[allow(missing_docs)] 48 | pub confidence: f64, 49 | 50 | #[allow(missing_docs)] 51 | #[serde(default)] 52 | pub languages: Vec, 53 | } 54 | 55 | /// Transcription results for a single audio channel. 56 | /// 57 | /// See the [Deepgram API Reference][api] 58 | /// and the [Deepgram Multichannel feature docs][docs] for more info. 59 | /// 60 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 61 | /// [docs]: https://developers.deepgram.com/documentation/features/multichannel/ 62 | #[derive(Debug, Serialize, Deserialize)] 63 | pub struct Channel { 64 | #[allow(missing_docs)] 65 | pub alternatives: Vec, 66 | } 67 | 68 | /// Modle info 69 | #[derive(Debug, Serialize, Deserialize)] 70 | pub struct ModelInfo { 71 | #[allow(missing_docs)] 72 | pub name: String, 73 | 74 | #[allow(missing_docs)] 75 | pub version: String, 76 | 77 | #[allow(missing_docs)] 78 | pub arch: String, 79 | } 80 | 81 | /// Metadata about the transcription. 82 | /// 83 | /// See the [Deepgram API Reference][api] for more info. 84 | /// 85 | /// [api]: https://developers.deepgram.com/api-reference/#transcription-prerecorded 86 | #[derive(Debug, Serialize, Deserialize)] 87 | pub struct Metadata { 88 | #[allow(missing_docs)] 89 | pub request_id: String, 90 | 91 | #[allow(missing_docs)] 92 | pub model_info: ModelInfo, 93 | 94 | #[allow(missing_docs)] 95 | pub model_uuid: String, 96 | } 97 | 98 | /// Possible websocket message types 99 | #[derive(Debug, Serialize, Deserialize)] 100 | #[serde(untagged)] 101 | #[non_exhaustive] 102 | pub enum StreamResponse { 103 | #[allow(missing_docs)] 104 | TranscriptResponse { 105 | #[allow(missing_docs)] 106 | #[serde(rename = "type")] 107 | type_field: String, 108 | 109 | #[allow(missing_docs)] 110 | start: f64, 111 | 112 | #[allow(missing_docs)] 113 | duration: f64, 114 | 115 | #[allow(missing_docs)] 116 | is_final: bool, 117 | 118 | #[allow(missing_docs)] 119 | speech_final: bool, 120 | 121 | #[allow(missing_docs)] 122 | from_finalize: bool, 123 | 124 | #[allow(missing_docs)] 125 | channel: Channel, 126 | 127 | #[allow(missing_docs)] 128 | metadata: Metadata, 129 | 130 | #[allow(missing_docs)] 131 | channel_index: Vec, 132 | }, 133 | #[allow(missing_docs)] 134 | TerminalResponse { 135 | #[allow(missing_docs)] 136 | request_id: String, 137 | 138 | #[allow(missing_docs)] 139 | created: String, 140 | 141 | #[allow(missing_docs)] 142 | duration: f64, 143 | 144 | #[allow(missing_docs)] 145 | channels: u32, 146 | }, 147 | #[allow(missing_docs)] 148 | SpeechStartedResponse { 149 | #[allow(missing_docs)] 150 | #[serde(rename = "type")] 151 | type_field: String, 152 | 153 | #[allow(missing_docs)] 154 | channel: Vec, 155 | 156 | #[allow(missing_docs)] 157 | timestamp: f64, 158 | }, 159 | #[allow(missing_docs)] 160 | UtteranceEndResponse { 161 | #[allow(missing_docs)] 162 | #[serde(rename = "type")] 163 | type_field: String, 164 | 165 | #[allow(missing_docs)] 166 | channel: Vec, 167 | 168 | #[allow(missing_docs)] 169 | last_word_end: f64, 170 | }, 171 | } 172 | -------------------------------------------------------------------------------- /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 | pub use http::Error as HttpError; 11 | pub use reqwest::Error as ReqwestError; 12 | pub use serde_json::Error as SerdeJsonError; 13 | pub use serde_urlencoded::ser::Error as SerdeUrlencodedError; 14 | use std::io; 15 | use std::ops::Deref; 16 | #[cfg(feature = "listen")] 17 | pub use tungstenite::Error as TungsteniteError; 18 | 19 | use reqwest::{ 20 | header::{HeaderMap, HeaderValue}, 21 | RequestBuilder, 22 | }; 23 | use serde::de::DeserializeOwned; 24 | use thiserror::Error; 25 | use url::Url; 26 | 27 | #[cfg(feature = "listen")] 28 | pub mod common; 29 | #[cfg(feature = "listen")] 30 | pub mod listen; 31 | #[cfg(feature = "manage")] 32 | pub mod manage; 33 | #[cfg(feature = "speak")] 34 | pub mod speak; 35 | 36 | static DEEPGRAM_BASE_URL: &str = "https://api.deepgram.com"; 37 | 38 | /// Transcribe audio using Deepgram's automated speech recognition. 39 | /// 40 | /// Constructed using [`Deepgram::transcription`]. 41 | /// 42 | /// See the [Deepgram API Reference][api] for more info. 43 | /// 44 | /// [api]: https://developers.deepgram.com/api-reference/#transcription 45 | #[derive(Debug, Clone)] 46 | pub struct Transcription<'a>(#[allow(unused)] pub &'a Deepgram); 47 | 48 | /// Generate speech from text using Deepgram's text to speech api. 49 | /// 50 | /// Constructed using [`Deepgram::text_to_speech`]. 51 | /// 52 | /// See the [Deepgram API Reference][api] for more info. 53 | /// 54 | /// [api]: https://developers.deepgram.com/reference/text-to-speech-api 55 | #[derive(Debug, Clone)] 56 | pub struct Speak<'a>(#[allow(unused)] pub &'a Deepgram); 57 | 58 | impl Deepgram { 59 | /// Construct a new [`Transcription`] from a [`Deepgram`]. 60 | pub fn transcription(&self) -> Transcription<'_> { 61 | self.into() 62 | } 63 | 64 | /// Construct a new [`Speak`] from a [`Deepgram`]. 65 | pub fn text_to_speech(&self) -> Speak<'_> { 66 | self.into() 67 | } 68 | } 69 | 70 | impl<'a> From<&'a Deepgram> for Transcription<'a> { 71 | /// Construct a new [`Transcription`] from a [`Deepgram`]. 72 | fn from(deepgram: &'a Deepgram) -> Self { 73 | Self(deepgram) 74 | } 75 | } 76 | 77 | impl<'a> From<&'a Deepgram> for Speak<'a> { 78 | /// Construct a new [`Speak`] from a [`Deepgram`]. 79 | fn from(deepgram: &'a Deepgram) -> Self { 80 | Self(deepgram) 81 | } 82 | } 83 | 84 | impl Transcription<'_> { 85 | /// Expose a method to access the inner `Deepgram` reference if needed. 86 | pub fn deepgram(&self) -> &Deepgram { 87 | self.0 88 | } 89 | } 90 | 91 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] 92 | /// A string wrapper that redacts its contents when formatted with `Debug`. 93 | pub(crate) struct RedactedString(pub String); 94 | 95 | impl fmt::Debug for RedactedString { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | f.write_str("***") 98 | } 99 | } 100 | 101 | impl Deref for RedactedString { 102 | type Target = str; 103 | 104 | fn deref(&self) -> &Self::Target { 105 | &self.0 106 | } 107 | } 108 | 109 | /// Authentication method for Deepgram API requests. 110 | #[derive(Debug, Clone, PartialEq, Eq)] 111 | pub(crate) enum AuthMethod { 112 | /// Use an API key with "Token" prefix (e.g., "Token dg_xxx"). 113 | /// This is for permanent API keys created in the Deepgram console. 114 | ApiKey(RedactedString), 115 | 116 | /// Use a temporary token with "Bearer" prefix (e.g., "Bearer dg_xxx"). 117 | /// This is for temporary tokens obtained via token-based authentication. 118 | TempToken(RedactedString), 119 | } 120 | 121 | impl AuthMethod { 122 | /// Get the authorization header value for this authentication method. 123 | pub(crate) fn header_value(&self) -> String { 124 | match self { 125 | AuthMethod::ApiKey(key) => format!("Token {}", key.0), 126 | AuthMethod::TempToken(token) => format!("Bearer {}", token.0), 127 | } 128 | } 129 | } 130 | 131 | /// A client for the Deepgram API. 132 | /// 133 | /// Make transcriptions requests using [`Deepgram::transcription`]. 134 | #[derive(Debug, Clone)] 135 | pub struct Deepgram { 136 | #[cfg_attr(not(feature = "listen"), allow(unused))] 137 | auth: Option, 138 | #[cfg_attr(not(feature = "listen"), allow(unused))] 139 | base_url: Url, 140 | #[cfg_attr(not(feature = "listen"), allow(unused))] 141 | client: reqwest::Client, 142 | } 143 | 144 | /// Errors that may arise from the [`deepgram`](crate) crate. 145 | // TODO sub-errors for the different types? 146 | #[derive(Debug, Error)] 147 | #[non_exhaustive] 148 | pub enum DeepgramError { 149 | /// The Deepgram API returned an error. 150 | #[error("The Deepgram API returned an error.")] 151 | DeepgramApiError { 152 | /// Error message from the Deepgram API. 153 | body: String, 154 | 155 | /// Underlying [`reqwest::Error`] from the HTTP request. 156 | err: ReqwestError, 157 | }, 158 | 159 | /// Something went wrong when generating the http request. 160 | #[error("Something went wrong when generating the http request: {0}")] 161 | HttpError(#[from] HttpError), 162 | 163 | /// Something went wrong when making the HTTP request. 164 | #[error("Something went wrong when making the HTTP request: {0}")] 165 | ReqwestError(#[from] ReqwestError), 166 | 167 | /// Something went wrong during I/O. 168 | #[error("Something went wrong during I/O: {0}")] 169 | IoError(#[from] io::Error), 170 | 171 | #[cfg(feature = "listen")] 172 | /// Something went wrong with WS. 173 | #[error("Something went wrong with WS: {0}")] 174 | WsError(#[from] Box), 175 | 176 | /// Something went wrong during serialization/deserialization. 177 | #[error("Something went wrong during json serialization/deserialization: {0}")] 178 | JsonError(#[from] SerdeJsonError), 179 | 180 | /// Something went wrong during serialization/deserialization. 181 | #[error("Something went wrong during query serialization: {0}")] 182 | UrlencodedError(#[from] SerdeUrlencodedError), 183 | 184 | /// The data stream produced an error 185 | #[error("The data stream produced an error: {0}")] 186 | StreamError(#[from] Box), 187 | 188 | /// The provided base url is not valid 189 | #[error("The provided base url is not valid")] 190 | InvalidUrl, 191 | 192 | /// A websocket close from was received indicating an error 193 | #[error("websocket close frame received with error content: code: {code}, reason: {reason}")] 194 | WebsocketClose { 195 | /// The numerical code indicating the reason for the error 196 | code: u16, 197 | /// A textual description of the error reason 198 | reason: String, 199 | }, 200 | 201 | /// An unexpected error occurred in the client 202 | #[error("an unepected error occurred in the deepgram client: {0}")] 203 | InternalClientError(anyhow::Error), 204 | 205 | /// A Deepgram API server response was not in the expected format. 206 | #[error("The Deepgram API server response was not in the expected format: {0}")] 207 | UnexpectedServerResponse(anyhow::Error), 208 | } 209 | 210 | #[cfg(feature = "listen")] 211 | impl From for DeepgramError { 212 | fn from(err: TungsteniteError) -> Self { 213 | Self::from(Box::new(err)) 214 | } 215 | } 216 | 217 | #[cfg_attr(not(feature = "listen"), allow(unused))] 218 | type Result = std::result::Result; 219 | 220 | impl Deepgram { 221 | /// Construct a new Deepgram client. 222 | /// 223 | /// The client will be pointed at Deepgram's hosted API. 224 | /// 225 | /// Create your first API key on the [Deepgram Console][console]. 226 | /// 227 | /// [console]: https://console.deepgram.com/ 228 | /// 229 | /// # Errors 230 | /// 231 | /// Errors under the same conditions as [`reqwest::ClientBuilder::build`]. 232 | pub fn new>(api_key: K) -> Result { 233 | let auth = AuthMethod::ApiKey(RedactedString(api_key.as_ref().to_owned())); 234 | // This cannot panic because we are converting a static value 235 | // that is known-good. 236 | let base_url = DEEPGRAM_BASE_URL.try_into().unwrap(); 237 | Self::inner_constructor(base_url, Some(auth)) 238 | } 239 | 240 | /// Construct a new Deepgram client with a temporary token. 241 | /// 242 | /// This uses the "Bearer" prefix for authentication, suitable for temporary tokens. 243 | pub fn with_temp_token>(temp_token: T) -> Result { 244 | let auth = AuthMethod::TempToken(RedactedString(temp_token.as_ref().to_owned())); 245 | let base_url = DEEPGRAM_BASE_URL.try_into().unwrap(); 246 | Self::inner_constructor(base_url, Some(auth)) 247 | } 248 | 249 | /// Construct a new Deepgram client with the specified base URL. 250 | /// 251 | /// When using a self-hosted instance of deepgram, this will be the 252 | /// host portion of your own instance. For instance, if you would 253 | /// query your deepgram instance at `http://deepgram.internal/v1/listen`, 254 | /// the base_url will be `http://deepgram.internal`. 255 | /// 256 | /// Admin features, such as billing, usage, and key management will 257 | /// still go through the hosted site at `https://api.deepgram.com`. 258 | /// 259 | /// Self-hosted instances do not in general authenticate incoming 260 | /// requests, so unlike in [`Deepgram::new`], so no api key needs to be 261 | /// provided. The SDK will not include an `Authorization` header in its 262 | /// requests. If an API key is required, consider using 263 | /// [`Deepgram::with_base_url_and_api_key`]. 264 | /// 265 | /// [console]: https://console.deepgram.com/ 266 | /// 267 | /// # Example: 268 | /// 269 | /// ``` 270 | /// # use deepgram::Deepgram; 271 | /// let deepgram = Deepgram::with_base_url( 272 | /// "http://localhost:8080", 273 | /// ); 274 | /// ``` 275 | /// 276 | /// # Errors 277 | /// 278 | /// Errors under the same conditions as [`reqwest::Client::new`], or if `base_url` 279 | /// is not a valid URL. 280 | pub fn with_base_url(base_url: U) -> Result 281 | where 282 | U: TryInto, 283 | U::Error: std::fmt::Debug, 284 | { 285 | let base_url = base_url.try_into().map_err(|_| DeepgramError::InvalidUrl)?; 286 | Self::inner_constructor(base_url, None) 287 | } 288 | 289 | /// Construct a new Deepgram client with the specified base URL and 290 | /// API Key. 291 | /// 292 | /// When using a self-hosted instance of deepgram, this will be the 293 | /// host portion of your own instance. For instance, if you would 294 | /// query your deepgram instance at `http://deepgram.internal/v1/listen`, 295 | /// the base_url will be `http://deepgram.internal`. 296 | /// 297 | /// Admin features, such as billing, usage, and key management will 298 | /// still go through the hosted site at `https://api.deepgram.com`. 299 | /// 300 | /// [console]: https://console.deepgram.com/ 301 | /// 302 | /// # Example: 303 | /// 304 | /// ``` 305 | /// # use deepgram::Deepgram; 306 | /// let deepgram = Deepgram::with_base_url_and_api_key( 307 | /// "http://localhost:8080", 308 | /// "apikey12345", 309 | /// ).unwrap(); 310 | /// ``` 311 | /// 312 | /// # Errors 313 | /// 314 | /// Errors under the same conditions as [`reqwest::ClientBuilder::build`], or if `base_url` 315 | /// is not a valid URL. 316 | pub fn with_base_url_and_api_key(base_url: U, api_key: K) -> Result 317 | where 318 | U: TryInto, 319 | U::Error: std::fmt::Debug, 320 | K: AsRef, 321 | { 322 | let base_url = base_url.try_into().map_err(|_| DeepgramError::InvalidUrl)?; 323 | let auth = AuthMethod::ApiKey(RedactedString(api_key.as_ref().to_owned())); 324 | Self::inner_constructor(base_url, Some(auth)) 325 | } 326 | 327 | /// Construct a new Deepgram client with the specified base URL and temp token. 328 | pub fn with_base_url_and_temp_token(base_url: U, temp_token: T) -> Result 329 | where 330 | U: TryInto, 331 | U::Error: std::fmt::Debug, 332 | T: AsRef, 333 | { 334 | let base_url = base_url.try_into().map_err(|_| DeepgramError::InvalidUrl)?; 335 | let auth = AuthMethod::TempToken(RedactedString(temp_token.as_ref().to_owned())); 336 | Self::inner_constructor(base_url, Some(auth)) 337 | } 338 | 339 | fn inner_constructor(base_url: Url, auth: Option) -> Result { 340 | static USER_AGENT: &str = concat!( 341 | env!("CARGO_PKG_NAME"), 342 | "/", 343 | env!("CARGO_PKG_VERSION"), 344 | " rust", 345 | ); 346 | 347 | if base_url.cannot_be_a_base() { 348 | return Err(DeepgramError::InvalidUrl); 349 | } 350 | let authorization_header = { 351 | let mut header = HeaderMap::new(); 352 | if let Some(auth) = &auth { 353 | let header_value = auth.header_value(); 354 | if let Ok(value) = HeaderValue::from_str(&header_value) { 355 | header.insert("Authorization", value); 356 | } 357 | } 358 | header 359 | }; 360 | 361 | Ok(Deepgram { 362 | auth, 363 | base_url, 364 | client: reqwest::Client::builder() 365 | .user_agent(USER_AGENT) 366 | .default_headers(authorization_header) 367 | .build()?, 368 | }) 369 | } 370 | } 371 | 372 | /// Sends the request and checks the response for an error. 373 | /// 374 | /// If there is an error, it translates it into a [`DeepgramError::DeepgramApiError`]. 375 | /// Otherwise, it deserializes the JSON accordingly. 376 | #[cfg_attr(not(feature = "listen"), allow(unused))] 377 | async fn send_and_translate_response( 378 | request_builder: RequestBuilder, 379 | ) -> crate::Result { 380 | let response = request_builder.send().await?; 381 | 382 | match response.error_for_status_ref() { 383 | Ok(_) => Ok(response.json().await?), 384 | Err(err) => Err(DeepgramError::DeepgramApiError { 385 | body: response.text().await?, 386 | err, 387 | }), 388 | } 389 | } 390 | 391 | #[cfg(test)] 392 | mod tests { 393 | use super::*; 394 | 395 | #[test] 396 | fn test_auth_method_header_value() { 397 | let api_key = AuthMethod::ApiKey(RedactedString("test_api_key".to_string())); 398 | assert_eq!(api_key.header_value(), "Token test_api_key".to_string()); 399 | 400 | let temp_token = AuthMethod::TempToken(RedactedString("test_temp_token".to_string())); 401 | assert_eq!( 402 | temp_token.header_value(), 403 | "Bearer test_temp_token".to_string() 404 | ); 405 | } 406 | 407 | #[test] 408 | fn test_deepgram_new_with_temp_token() { 409 | let client = Deepgram::with_temp_token("test_temp_token").unwrap(); 410 | assert_eq!( 411 | client.auth, 412 | Some(AuthMethod::TempToken(RedactedString( 413 | "test_temp_token".to_string() 414 | ))) 415 | ); 416 | } 417 | 418 | #[test] 419 | fn test_deepgram_new_with_api_key() { 420 | let client = Deepgram::new("test_api_key").unwrap(); 421 | assert_eq!( 422 | client.auth, 423 | Some(AuthMethod::ApiKey(RedactedString( 424 | "test_api_key".to_string() 425 | ))) 426 | ); 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /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!("https://api.deepgram.com/v1/projects/{project_id}/balances",); 71 | 72 | send_and_translate_response(self.0.client.get(url)).await 73 | } 74 | 75 | /// Get the details of a specific balance. 76 | /// 77 | /// See the [Deepgram API Reference][api] for more info. 78 | /// 79 | /// [api]: https://developers.deepgram.com/api-reference/#billing-get 80 | /// 81 | /// # Examples 82 | /// 83 | /// ```no_run 84 | /// # use deepgram::{Deepgram, DeepgramError}; 85 | /// # use std::env; 86 | /// # 87 | /// # #[tokio::main] 88 | /// # async fn main() -> Result<(), DeepgramError> { 89 | /// # let deepgram_api_key = 90 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 91 | /// # 92 | /// # let project_id = 93 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 94 | /// # 95 | /// # let balance_id = 96 | /// # env::var("DEEPGRAM_BALANCE_ID").expect("DEEPGRAM_BALANCE_ID environmental variable"); 97 | /// # 98 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 99 | /// 100 | /// let balance = dg_client 101 | /// .billing() 102 | /// .get_balance(&project_id, &balance_id) 103 | /// .await?; 104 | /// 105 | /// assert_eq!(balance_id, balance.balance_id.to_string()); 106 | /// # 107 | /// # Ok(()) 108 | /// # } 109 | /// ``` 110 | pub async fn get_balance(&self, project_id: &str, balance_id: &str) -> crate::Result { 111 | let url = 112 | format!("https://api.deepgram.com/v1/projects/{project_id}/balances/{balance_id}",); 113 | 114 | send_and_translate_response(self.0.client.get(url)).await 115 | } 116 | } 117 | 118 | #[cfg(test)] 119 | mod tests { 120 | use crate::manage::billing::response::{Balance, BillingUnits}; 121 | 122 | #[test] 123 | fn test() { 124 | assert_eq!( 125 | serde_json::from_str::( 126 | "{\"balance_id\":\"a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8\",\"amount\":1,\"units\":\"usd\",\"purchase_order_id\":\"a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8\"}", 127 | ).unwrap().units, 128 | BillingUnits::Usd 129 | ); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /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/{project_id}/leave",); 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/{project_id}/keys"); 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!("https://api.deepgram.com/v1/projects/{project_id}/keys/{key_id}",); 117 | 118 | send_and_translate_response(self.0.client.get(url)).await 119 | } 120 | 121 | /// Create a new key in the specified project. 122 | /// 123 | /// See the [Deepgram API Reference][api] for more info. 124 | /// 125 | /// [api]: https://developers.deepgram.com/api-reference/#keys-create 126 | /// 127 | /// # Examples 128 | /// 129 | /// ```no_run 130 | /// # use std::env; 131 | /// # 132 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 133 | /// # 134 | /// # #[tokio::main] 135 | /// # async fn main() -> Result<(), DeepgramError> { 136 | /// # let deepgram_api_key = 137 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 138 | /// # 139 | /// # let project_id = 140 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 141 | /// # 142 | /// # let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 143 | /// # 144 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 145 | /// 146 | /// let options = Options::builder("New Key", ["member"]).build(); 147 | /// let new_key = dg_client 148 | /// .keys() 149 | /// .create(&project_id, &options) 150 | /// .await?; 151 | /// # 152 | /// # Ok(()) 153 | /// # } 154 | /// ``` 155 | pub async fn create(&self, project_id: &str, options: &Options) -> crate::Result { 156 | let url = format!("https://api.deepgram.com/v1/projects/{project_id}/keys"); 157 | let request = self 158 | .0 159 | .client 160 | .post(url) 161 | .json(&SerializableOptions::from(options)); 162 | 163 | send_and_translate_response(request).await 164 | } 165 | 166 | /// Delete the specified key in the specified project. 167 | /// 168 | /// See the [Deepgram API Reference][api] for more info. 169 | /// 170 | /// [api]: https://developers.deepgram.com/api-reference/#keys-delete 171 | /// 172 | /// # Examples 173 | /// 174 | /// ```no_run 175 | /// # use std::env; 176 | /// # 177 | /// # use deepgram::{manage::keys::options::Options, Deepgram, DeepgramError}; 178 | /// # 179 | /// # #[tokio::main] 180 | /// # async fn main() -> Result<(), DeepgramError> { 181 | /// # let deepgram_api_key = 182 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 183 | /// # 184 | /// # let project_id = 185 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 186 | /// # 187 | /// # let key_id = env::var("DEEPGRAM_KEY_ID").expect("DEEPGRAM_KEY_ID environmental variable"); 188 | /// # 189 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 190 | /// 191 | /// dg_client 192 | /// .keys() 193 | /// .delete(&project_id, &key_id) 194 | /// .await?; 195 | /// # 196 | /// # Ok(()) 197 | /// # } 198 | /// ``` 199 | pub async fn delete(&self, project_id: &str, key_id: &str) -> crate::Result { 200 | let url = format!("https://api.deepgram.com/v1/projects/{project_id}/keys/{key_id}",); 201 | 202 | send_and_translate_response(self.0.client.delete(url)).await 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /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!("https://api.deepgram.com/v1/projects/{project_id}/members",); 71 | 72 | send_and_translate_response(self.0.client.get(url)).await 73 | } 74 | 75 | /// Remove the specified member from the specified project. 76 | /// 77 | /// See the [Deepgram API Reference][api] for more info. 78 | /// 79 | /// [api]: https://developers.deepgram.com/api-reference/#members-delete 80 | /// 81 | /// # Examples 82 | /// 83 | /// ```no_run 84 | /// # use std::env; 85 | /// # 86 | /// # use deepgram::{Deepgram, DeepgramError}; 87 | /// # 88 | /// # #[tokio::main] 89 | /// # async fn main() -> Result<(), DeepgramError> { 90 | /// # let deepgram_api_key = 91 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 92 | /// # 93 | /// # let project_id = 94 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 95 | /// # 96 | /// # let member_id = 97 | /// # env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 98 | /// # 99 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 100 | /// 101 | /// dg_client 102 | /// .members() 103 | /// .remove_member(&project_id, &member_id) 104 | /// .await?; 105 | /// # 106 | /// # Ok(()) 107 | /// # } 108 | /// ``` 109 | pub async fn remove_member(&self, project_id: &str, member_id: &str) -> crate::Result { 110 | let url = format!("https://api.deepgram.com/v1/projects/{project_id}/members/{member_id}",); 111 | 112 | send_and_translate_response(self.0.client.delete(url)).await 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /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/{project_id}/members/{member_id}/scopes " 81 | ); 82 | 83 | send_and_translate_response(self.0.client.get(url)).await 84 | } 85 | 86 | /// Update the specified project scopes assigned to the specified member. 87 | /// 88 | /// See the [Deepgram API Reference][api] for more info. 89 | /// 90 | /// [api]: https://developers.deepgram.com/api-reference/#scopes-update 91 | /// 92 | /// # Examples 93 | /// 94 | /// ```no_run 95 | /// # use std::env; 96 | /// # 97 | /// # use deepgram::{Deepgram, DeepgramError}; 98 | /// # 99 | /// # #[tokio::main] 100 | /// # async fn main() -> Result<(), DeepgramError> { 101 | /// # let deepgram_api_key = 102 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 103 | /// # 104 | /// # let project_id = 105 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 106 | /// # 107 | /// # let member_id = 108 | /// # env::var("DEEPGRAM_MEMBER_ID").expect("DEEPGRAM_MEMBER_ID environmental variable"); 109 | /// # 110 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 111 | /// 112 | /// dg_client 113 | /// .scopes() 114 | /// .update_scope(&project_id, &member_id, "member") 115 | /// .await?; 116 | /// # 117 | /// # Ok(()) 118 | /// # } 119 | /// ``` 120 | pub async fn update_scope( 121 | &self, 122 | project_id: &str, 123 | member_id: &str, 124 | scope: &str, 125 | ) -> crate::Result { 126 | #[derive(Serialize)] 127 | struct Scope<'a> { 128 | scope: &'a str, 129 | } 130 | 131 | let url = 132 | format!("https://api.deepgram.com/v1/projects/{project_id}/members/{member_id}/scopes"); 133 | let request = self.0.client.put(url).json(&Scope { scope }); 134 | 135 | send_and_translate_response(request).await 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /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!("https://api.deepgram.com/v1/projects/{project_id}/requests",); 82 | let request = self 83 | .0 84 | .client 85 | .get(url) 86 | .query(&list_requests_options::SerializableOptions::from(options)); 87 | 88 | send_and_translate_response(request).await 89 | } 90 | 91 | /// Get the details of the specified request sent to the Deepgram API for the specified project. 92 | /// 93 | /// See the [Deepgram API Reference][api] for more info. 94 | /// 95 | /// [api]: https://developers.deepgram.com/api-reference/#usage-get 96 | /// 97 | /// # Examples 98 | /// 99 | /// ```no_run 100 | /// # use std::env; 101 | /// # 102 | /// # use deepgram::{ 103 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 104 | /// # Deepgram, DeepgramError, 105 | /// # }; 106 | /// # 107 | /// # #[tokio::main] 108 | /// # async fn main() -> Result<(), DeepgramError> { 109 | /// # let deepgram_api_key = 110 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 111 | /// # 112 | /// # let project_id = 113 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 114 | /// # 115 | /// # let request_id = 116 | /// # env::var("DEEPGRAM_REQUEST_ID").expect("DEEPGRAM_REQUEST_ID environmental variable"); 117 | /// # 118 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 119 | /// 120 | /// let request = dg_client 121 | /// .usage() 122 | /// .get_request(&project_id, &request_id) 123 | /// .await?; 124 | /// # 125 | /// # Ok(()) 126 | /// # } 127 | /// ``` 128 | pub async fn get_request(&self, project_id: &str, request_id: &str) -> crate::Result { 129 | let url = 130 | format!("https://api.deepgram.com/v1/projects/{project_id}/requests/{request_id}",); 131 | 132 | send_and_translate_response(self.0.client.get(url)).await 133 | } 134 | 135 | /// Get a summary of usage statistics. 136 | /// 137 | /// See the [Deepgram API Reference][api] for more info. 138 | /// 139 | /// [api]: https://developers.deepgram.com/api-reference/#usage-summary 140 | /// 141 | /// # Examples 142 | /// 143 | /// ```no_run 144 | /// # use std::env; 145 | /// # 146 | /// # use deepgram::{ 147 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 148 | /// # Deepgram, DeepgramError, 149 | /// # }; 150 | /// # 151 | /// # #[tokio::main] 152 | /// # async fn main() -> Result<(), DeepgramError> { 153 | /// # let deepgram_api_key = 154 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 155 | /// # 156 | /// # let project_id = 157 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 158 | /// # 159 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 160 | /// 161 | /// let options = get_usage_options::Options::builder().build(); 162 | /// let summary = dg_client 163 | /// .usage() 164 | /// .get_usage(&project_id, &options) 165 | /// .await?; 166 | /// # 167 | /// # Ok(()) 168 | /// # } 169 | /// ``` 170 | pub async fn get_usage( 171 | &self, 172 | project_id: &str, 173 | options: &get_usage_options::Options, 174 | ) -> crate::Result { 175 | let url = format!("https://api.deepgram.com/v1/projects/{project_id}/usage"); 176 | let request = self 177 | .0 178 | .client 179 | .get(url) 180 | .query(&get_usage_options::SerializableOptions::from(options)); 181 | 182 | send_and_translate_response(request).await 183 | } 184 | 185 | /// Get the features, models, tags, languages, and processing method used for requests in the specified project. 186 | /// 187 | /// See the [Deepgram API Reference][api] for more info. 188 | /// 189 | /// [api]: https://developers.deepgram.com/api-reference/#usage-fields 190 | /// 191 | /// # Examples 192 | /// 193 | /// ```no_run 194 | /// # use std::env; 195 | /// # 196 | /// # use deepgram::{ 197 | /// # manage::usage::{get_fields_options, get_usage_options, list_requests_options}, 198 | /// # Deepgram, DeepgramError, 199 | /// # }; 200 | /// # 201 | /// # #[tokio::main] 202 | /// # async fn main() -> Result<(), DeepgramError> { 203 | /// # let deepgram_api_key = 204 | /// # env::var("DEEPGRAM_API_KEY").expect("DEEPGRAM_API_KEY environmental variable"); 205 | /// # 206 | /// # let project_id = 207 | /// # env::var("DEEPGRAM_PROJECT_ID").expect("DEEPGRAM_PROJECT_ID environmental variable"); 208 | /// # 209 | /// let dg_client = Deepgram::new(&deepgram_api_key)?; 210 | /// 211 | /// let options = get_fields_options::Options::builder().build(); 212 | /// let summary = dg_client 213 | /// .usage() 214 | /// .get_fields(&project_id, &options) 215 | /// .await?; 216 | /// # 217 | /// # Ok(()) 218 | /// # } 219 | /// ``` 220 | pub async fn get_fields( 221 | &self, 222 | project_id: &str, 223 | options: &get_fields_options::Options, 224 | ) -> crate::Result { 225 | let url = format!("https://api.deepgram.com/v1/projects/{project_id}/usage/fields",); 226 | let request = self 227 | .0 228 | .client 229 | .get(url) 230 | .query(&get_fields_options::SerializableOptions::from(options)); 231 | 232 | send_and_translate_response(request).await 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------