Repository: 64bit/async-openai (Rust)

Issue:
Trouble with teloxide after upgrading to 0.14.0 from 0.12.0
I recently tried to upgrade my application to the latest version in order to make use of some of the new stuff announced at dev day. I have a telegram bot that uses teloxide, with a use of the image and transcription endpoints. However, I was running into this error with compiling:

```
the trait bound `fn(teloxide::Bot, teloxide::prelude::Message) -> impl futures_util::Future<Output = Result<(), RequestError>> {respond_to_voice}: Injectable<_, _, _>` is not satisfied
the following other types implement trait `Injectable<Input, Output, FnArgs>`:
  <Asyncify<Func> as Injectable<Input, Output, ()>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C, D)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C, D, E)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C, D, E, F)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C, D, E, F, G)>>
  <Asyncify<Func> as Injectable<Input, Output, (A, B, C, D, E, F, G, H)>>
and 2 others
```

Instead of trying to upgrade directly to the latest version from 0.12, I tried upgrading incrementally until discovering that the issue appeared with the upgrade to 0.14. It looks like it might be related to the changes around retrying for rate limiting, but I'm at a bit of a loss with how to fix it.

My implementation is pretty simple in terms of how I'm calling the library itself:

```rust
pub async fn get_ai_transcription(audio: &String) -> Result<String, CustomError> {
    let client = Client::new();

    let request = CreateTranscriptionRequestArgs::default()
        .file(audio)
        .model("whisper-1")
        .build()?;

    let response = client.audio().transcribe(request).await?;

    Ok(response.text)
}
```
but I was able to determine that it was occurring due to the `let response = client.audio().transcribe(request).await?;` line.

After trying a lot of debugging to even get the error message to change, I added this basic test 
```rust
fn test() {
    fn assert_send(_: impl Send) {}
    assert_send(get_ai_transcription(&"".to_string()));
}
```
and finally got a more readable error that disappears in 0.13 and reappears around 0.14.

```
    |
309 |     assert_send(get_ai_transcription(&"".to_string()));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `get_ai_transcription` is not `Send`
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn futures_util::Future<Output = Result<Form, OpenAIError>>`
note: required by a bound in `assert_send`
   --> src/ai.rs:308:28
    |
308 |     fn assert_send(_: impl Send) {}
    |                            ^^^^ required by this bound in `assert_send`
```

Unfortunately, now I'm a bit stuck. I'm pretty new to Rust, so debugging can still be a bit difficult. Do you have any suggestions or ideas for what I might be able to try? 


Discussion:
I think I'm experiencing the same problem with 
version
`async-openai = "0.16.3"`

<details><summary>Compiler error</summary>
<p>

```
error[E0277]: `dyn std::future::Future<Output = Result<reqwest::async_impl::multipart::Form, OpenAIError>>` cannot be sent between threads safely
   --> src/bot.rs:37:1
    |
37  | #[command]
    | ^^^^^^^^^^ `dyn std::future::Future<Output = Result<reqwest::async_impl::multipart::Form, OpenAIError>>` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn std::future::Future<Output = Result<reqwest::async_impl::multipart::Form, OpenAIError>>`
    = note: required for `Unique<dyn std::future::Future<Output = Result<reqwest::async_impl::multipart::Form, OpenAIError>>>` to implement `std::marker::Send`
note: required because it appears within the type `Box<dyn Future<Output = Result<Form, OpenAIError>>>`
   --> /home/hannah/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:195:12
    |
195 | pub struct Box<
    |            ^^^
note: required because it appears within the type `Pin<Box<dyn Future<Output = Result<Form, OpenAIError>>>>`
   --> /home/hannah/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/pin.rs:410:12
    |
410 | pub struct Pin<P> {
    |            ^^^
    = note: required because it captures the following types: `reqwest::async_impl::request::RequestBuilder`, `Vec<(&str, &str)>`, `std::pin::Pin<Box<dyn std::future::Future<Output = Result<reqwest::async_impl::multipart::Form, OpenAIError>>>>`
note: required because it's used within this `async` block
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/client.rs:232:32
    |
232 |           let request_maker = || async {
    |  ________________________________^
233 | |             Ok(self
234 | |                 .http_client
235 | |                 .post(self.config.url(path))
...   |
239 | |                 .build()?)
240 | |         };
    | |_________^
    = note: required because it captures the following types: `{async block@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}::{closure#0}}`, `reqwest::async_impl::response::Response`, `impl std::future::Future<Output = Result<reqwest::async_impl::response::Response, reqwest::error::Error>>`, `StatusCode`, `impl std::future::Future<Output = Result<bytes::bytes::Bytes, reqwest::error::Error>>`
note: required because it's used within this `async` block
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/client.rs:257:57
    |
257 |           backoff::future::retry(self.backoff.clone(), || async {
    |  _________________________________________________________^
258 | |             let request = request_maker().await.map_err(backoff::Error::Permanent)?;
259 | |             let response = client
260 | |                 .execute(request)
...   |
296 | |             Ok(bytes)
297 | |         })
    | |_________^
note: required because it appears within the type `Retry<impl Sleeper, ExponentialBackoff<SystemClock>, NoopNotify, {closure@Client<OpenAIConfig>::execute_raw<{closure@Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}}, {async block@Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}::{closure#0}}>::{closure#0}::{closure#0}}, {async block@Client<OpenAIConfig>::execute_raw<{closure@Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}}, {async block@Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}::{closure#0}}>::{closure#0}::{closure#0}::{closure#0}}>`
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backoff-0.4.0/src/future.rs:110:16
    |
110 |     pub struct Retry<S: Sleeper, B, N, Fn, Fut> {
    |                ^^^^^
    = note: required because it captures the following types: `{closure@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}}`, `reqwest::async_impl::client::Client`, `backoff::future::Retry<impl backoff::future::Sleeper, backoff::exponential::ExponentialBackoff<backoff::clock::SystemClock>, backoff::retry::NoopNotify, {closure@async_openai::Client<OpenAIConfig>::execute_raw<{closure@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}}, {async block@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}::{closure#0}}>::{closure#0}::{closure#0}}, {async block@async_openai::Client<OpenAIConfig>::execute_raw<{closure@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}}, {async block@async_openai::Client<OpenAIConfig>::post_form<CreateTranscriptionResponse, CreateTranscriptionRequest>::{closure#0}::{closure#0}::{closure#0}}>::{closure#0}::{closure#0}::{closure#0}}>`
note: required because it's used within this `async` fn body
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/client.rs:254:5
    |
254 | /     {
255 | |         let client = self.http_client.clone();
256 | |
257 | |         backoff::future::retry(self.backoff.clone(), || async {
...   |
298 | |         .await
299 | |     }
    | |_____^
    = note: required because it captures the following types: `impl std::future::Future<Output = Result<bytes::bytes::Bytes, OpenAIError>>`
note: required because it's used within this `async` fn body
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/client.rs:311:5
    |
311 | /     {
312 | |         let bytes = self.execute_raw(request_maker).await?;
313 | |
314 | |         let response: O = serde_json::from_slice(bytes.as_ref())
...   |
317 | |         Ok(response)
318 | |     }
    | |_____^
    = note: required because it captures the following types: `CreateTranscriptionRequest`, `impl std::future::Future<Output = Result<CreateTranscriptionResponse, OpenAIError>>`
note: required because it's used within this `async` fn body
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/client.rs:231:5
    |
231 | /     {
232 | |         let request_maker = || async {
233 | |             Ok(self
234 | |                 .http_client
...   |
242 | |         self.execute(request_maker).await
243 | |     }
    | |_____^
    = note: required because it captures the following types: `impl std::future::Future<Output = Result<CreateTranscriptionResponse, OpenAIError>>`
note: required because it's used within this `async` fn body
   --> /home/hannah/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-openai-0.16.3/src/audio.rs:26:59
    |
26  |       ) -> Result<CreateTranscriptionResponse, OpenAIError> {
    |  ___________________________________________________________^
27  | |         self.client
28  | |             .post_form("/audio/transcriptions", request)
29  | |             .await
30  | |     }
    | |_____^
    = note: required because it captures the following types: `Audio<'_, OpenAIConfig>`, `impl std::future::Future<Output = Result<CreateTranscriptionResponse, OpenAIError>>`
note: required because it's used within this `async` fn body
   --> src/openai.rs:44:93
    |
44  |       pub async fn stt(&self, file: &str) -> Result<CreateTranscriptionResponse, OpenAIError> {
    |  _____________________________________________________________________________________________^
45  | |         let request = CreateTranscriptionRequestArgs::default()
46  | |             .file(file)
47  | |             .model("whisper-1")
...   |
51  | |         self.client.audio().transcribe(request).await
52  | |     }
    | |_____^
    = note: required because it captures the following types: `OpenAI`, `Typing`, `regex::Regex`, `Vec<std::string::String>`, `Option<&std::string::String>`, `impl std::future::Future<Output = Result<serenity::model::channel::Message, SerenityError>>`, `std::string::String`, `Output`, `impl std::future::Future<Output = Result<serenity::model::channel::Message, SerenityError>>`, `impl std::future::Future<Output = Result<CreateTranscriptionResponse, OpenAIError>>`
```

</p>
</details> 
I think this bug emerged from #100 
Hello there, 

To be honest I'm not sure whats going on, it might help to put full code on GitHub and share link, and get more eyes to debug. 



I think I have had the same problem.

This fix #157  is working well for me.
@katya4oyu I just tried the fix out and it seems to work for me as well!
Thank you for the fix, its released in v0.17.1
@katya4oyu @64bit thank you for your help and for the new release!



Patch:
diff --git a/async-openai/src/client.rs b/async-openai/src/client.rs
index 88e1ae95..b393eba5 100644
--- a/async-openai/src/client.rs
+++ b/async-openai/src/client.rs
@@ -235,7 +235,7 @@ impl<C: Config> Client<C> {
                 .post(self.config.url(path))
                 .query(&self.config.query())
                 .headers(self.config.headers())
-                .multipart(async_convert::TryInto::try_into(form.clone()).await?)
+                .multipart(async_convert::TryFrom::try_from(form.clone()).await?)
                 .build()?)
         };
 


Test patch:
diff --git a/async-openai/tests/whisper.rs b/async-openai/tests/whisper.rs
new file mode 100644
index 00000000..ee17a05f
--- /dev/null
+++ b/async-openai/tests/whisper.rs
@@ -0,0 +1,57 @@
+use async_openai::types::CreateTranslationRequestArgs;
+use async_openai::{types::CreateTranscriptionRequestArgs, Client};
+use tokio_test::assert_err;
+
+#[tokio::test]
+async fn transcribe_test() {
+    let client = Client::new();
+
+    let request = CreateTranscriptionRequestArgs::default().build().unwrap();
+
+    let response = client.audio().transcribe(request).await;
+
+    assert_err!(response); // FileReadError("cannot extract file name from ")
+}
+
+#[tokio::test]
+async fn transcribe_sendable_test() {
+    let client = Client::new();
+
+    // https://github.com/64bit/async-openai/issues/140
+    let transcribe = tokio::spawn(async move {
+        let request = CreateTranscriptionRequestArgs::default().build().unwrap();
+
+        client.audio().transcribe(request).await
+    });
+
+    let response = transcribe.await.unwrap();
+
+    assert_err!(response); // FileReadError("cannot extract file name from ")
+}
+
+#[tokio::test]
+async fn translate_test() {
+    let client = Client::new();
+
+    let request = CreateTranslationRequestArgs::default().build().unwrap();
+
+    let response = client.audio().translate(request).await;
+
+    assert_err!(response); // FileReadError("cannot extract file name from ")
+}
+
+#[tokio::test]
+async fn translate_sendable_test() {
+    let client = Client::new();
+
+    // https://github.com/64bit/async-openai/issues/140
+    let translate = tokio::spawn(async move {
+        let request = CreateTranslationRequestArgs::default().build().unwrap();
+
+        client.audio().translate(request).await
+    });
+
+    let response = translate.await.unwrap();
+
+    assert_err!(response); // FileReadError("cannot extract file name from ")
+}