Skip to content

Commit 951334a

Browse files
64bitifsheldon
authored andcommitted
feat: responses & crate ergonomics + bug fixes (64bit#485)
* from traits impls * updated examples/responses to be simplified * updates * more from traits * updated images-and-vision example * further from traits * add responses-structured-outputs example * add streaming example * responses stream event ergonomics: event_type * updated responses function to include streaming example * handle StreamEnded gracefully * update example now that StreamEnded is handled gracefully * fix * fix: publish false * remove use of deprecated field types * remove examples using deprecated types/fields * responses refactor * fix coversation example * refactor impls * move warpper types impls in its own file * refactor * image impls * impls and forms for each type mods * create sdk.rs which add SDK like functionality on types * event types for realtime events * update example to use event_type() * Event type for assistant stream events (cherry picked from commit f6886c2)
1 parent f8a79ee commit 951334a

File tree

48 files changed

+3262
-1231
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3262
-1231
lines changed

async-openai/src/impls.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use crate::{
2+
admin_api_keys::AdminAPIKeys,
3+
assistants::Assistants,
4+
audio::Audio,
5+
audit_logs::AuditLogs,
6+
batches::Batches,
7+
certificates::Certificates,
8+
chat::Chat,
9+
chatkit::{Chatkit, ChatkitSessions, ChatkitThreads},
10+
completion::Completions,
11+
container_files::ContainerFiles,
12+
containers::Containers,
13+
conversation_items::ConversationItems,
14+
conversations::Conversations,
15+
embedding::Embeddings,
16+
eval_run_output_items::EvalRunOutputItems,
17+
eval_runs::EvalRuns,
18+
evals::Evals,
19+
file::Files,
20+
fine_tuning::FineTuning,
21+
group_roles::GroupRoles,
22+
group_users::GroupUsers,
23+
groups::Groups,
24+
image::Images,
25+
invites::Invites,
26+
messages::Messages,
27+
model::Models,
28+
moderation::Moderations,
29+
project_api_keys::ProjectAPIKeys,
30+
project_certificates::ProjectCertificates,
31+
project_group_roles::ProjectGroupRoles,
32+
project_groups::ProjectGroups,
33+
project_rate_limits::ProjectRateLimits,
34+
project_roles::ProjectRoles,
35+
project_service_accounts::ProjectServiceAccounts,
36+
project_user_roles::ProjectUserRoles,
37+
project_users::ProjectUsers,
38+
projects::Projects,
39+
responses::Responses,
40+
roles::Roles,
41+
runs::Runs,
42+
speech::Speech,
43+
steps::Steps,
44+
threads::Threads,
45+
transcriptions::Transcriptions,
46+
translations::Translations,
47+
uploads::Uploads,
48+
usage::Usage,
49+
user_roles::UserRoles,
50+
users::Users,
51+
vector_store_file_batches::VectorStoreFileBatches,
52+
vector_store_files::VectorStoreFiles,
53+
vector_stores::VectorStores,
54+
video::Videos,
55+
};
56+
57+
// request builder impls macro
58+
59+
/// Macro to implement `RequestOptionsBuilder` for wrapper types containing `RequestOptions`
60+
macro_rules! impl_request_options_builder {
61+
($type:ident) => {
62+
impl<'c, C: crate::config::Config> crate::traits::RequestOptionsBuilder for $type<'c, C> {
63+
fn options_mut(&mut self) -> &mut crate::RequestOptions {
64+
&mut self.request_options
65+
}
66+
67+
fn options(&self) -> &crate::RequestOptions {
68+
&self.request_options
69+
}
70+
}
71+
};
72+
}
73+
74+
#[cfg(feature = "realtime")]
75+
use crate::Realtime;
76+
77+
impl_request_options_builder!(AdminAPIKeys);
78+
impl_request_options_builder!(Assistants);
79+
impl_request_options_builder!(Audio);
80+
impl_request_options_builder!(AuditLogs);
81+
impl_request_options_builder!(Batches);
82+
impl_request_options_builder!(Certificates);
83+
impl_request_options_builder!(Chat);
84+
impl_request_options_builder!(Chatkit);
85+
impl_request_options_builder!(ChatkitSessions);
86+
impl_request_options_builder!(ChatkitThreads);
87+
impl_request_options_builder!(Completions);
88+
impl_request_options_builder!(ContainerFiles);
89+
impl_request_options_builder!(Containers);
90+
impl_request_options_builder!(ConversationItems);
91+
impl_request_options_builder!(Conversations);
92+
impl_request_options_builder!(Embeddings);
93+
impl_request_options_builder!(Evals);
94+
impl_request_options_builder!(EvalRunOutputItems);
95+
impl_request_options_builder!(EvalRuns);
96+
impl_request_options_builder!(Files);
97+
impl_request_options_builder!(FineTuning);
98+
impl_request_options_builder!(GroupRoles);
99+
impl_request_options_builder!(GroupUsers);
100+
impl_request_options_builder!(Groups);
101+
impl_request_options_builder!(Images);
102+
impl_request_options_builder!(Invites);
103+
impl_request_options_builder!(Messages);
104+
impl_request_options_builder!(Models);
105+
impl_request_options_builder!(Moderations);
106+
impl_request_options_builder!(Projects);
107+
impl_request_options_builder!(ProjectGroupRoles);
108+
impl_request_options_builder!(ProjectGroups);
109+
impl_request_options_builder!(ProjectRoles);
110+
impl_request_options_builder!(ProjectUserRoles);
111+
impl_request_options_builder!(ProjectUsers);
112+
impl_request_options_builder!(ProjectServiceAccounts);
113+
impl_request_options_builder!(ProjectAPIKeys);
114+
impl_request_options_builder!(ProjectRateLimits);
115+
impl_request_options_builder!(ProjectCertificates);
116+
impl_request_options_builder!(Roles);
117+
#[cfg(feature = "realtime")]
118+
impl_request_options_builder!(Realtime);
119+
impl_request_options_builder!(Responses);
120+
impl_request_options_builder!(Runs);
121+
impl_request_options_builder!(Speech);
122+
impl_request_options_builder!(Steps);
123+
impl_request_options_builder!(Threads);
124+
impl_request_options_builder!(Transcriptions);
125+
impl_request_options_builder!(Translations);
126+
impl_request_options_builder!(Uploads);
127+
impl_request_options_builder!(Usage);
128+
impl_request_options_builder!(UserRoles);
129+
impl_request_options_builder!(Users);
130+
impl_request_options_builder!(VectorStoreFileBatches);
131+
impl_request_options_builder!(VectorStoreFiles);
132+
impl_request_options_builder!(VectorStores);
133+
impl_request_options_builder!(Videos);

async-openai/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ mod group_roles;
168168
mod group_users;
169169
mod groups;
170170
mod image;
171+
mod impls;
171172
mod invites;
172173
mod messages;
173174
mod model;

async-openai/src/types/assistants/assistant_stream.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use serde::Deserialize;
22

33
use crate::client::OpenAIEventStream;
44
use crate::error::{ApiError, OpenAIError, StreamError, map_deserialization_error};
5-
5+
use crate::traits::EventType;
66
use crate::types::assistants::{
77
MessageDeltaObject, MessageObject, RunObject, RunStepDeltaObject, RunStepObject, ThreadObject,
88
};
@@ -209,3 +209,35 @@ impl TryFrom<eventsource_stream::Event> for AssistantStreamEvent {
209209
}
210210
}
211211
}
212+
213+
impl EventType for AssistantStreamEvent {
214+
fn event_type(&self) -> &'static str {
215+
match self {
216+
AssistantStreamEvent::ThreadCreated(_) => "thread.created",
217+
AssistantStreamEvent::ThreadRunCreated(_) => "thread.run.created",
218+
AssistantStreamEvent::ThreadRunQueued(_) => "thread.run.queued",
219+
AssistantStreamEvent::ThreadRunInProgress(_) => "thread.run.in_progress",
220+
AssistantStreamEvent::ThreadRunRequiresAction(_) => "thread.run.requires_action",
221+
AssistantStreamEvent::ThreadRunCompleted(_) => "thread.run.completed",
222+
AssistantStreamEvent::ThreadRunIncomplete(_) => "thread.run.incomplete",
223+
AssistantStreamEvent::ThreadRunFailed(_) => "thread.run.failed",
224+
AssistantStreamEvent::ThreadRunCancelling(_) => "thread.run.cancelling",
225+
AssistantStreamEvent::ThreadRunCancelled(_) => "thread.run.cancelled",
226+
AssistantStreamEvent::ThreadRunExpired(_) => "thread.run.expired",
227+
AssistantStreamEvent::ThreadRunStepCreated(_) => "thread.run.step.created",
228+
AssistantStreamEvent::ThreadRunStepInProgress(_) => "thread.run.step.in_progress",
229+
AssistantStreamEvent::ThreadRunStepDelta(_) => "thread.run.step.delta",
230+
AssistantStreamEvent::ThreadRunStepCompleted(_) => "thread.run.step.completed",
231+
AssistantStreamEvent::ThreadRunStepFailed(_) => "thread.run.step.failed",
232+
AssistantStreamEvent::ThreadRunStepCancelled(_) => "thread.run.step.cancelled",
233+
AssistantStreamEvent::ThreadRunStepExpired(_) => "thread.run.step.expired",
234+
AssistantStreamEvent::ThreadMessageCreated(_) => "thread.message.created",
235+
AssistantStreamEvent::ThreadMessageInProgress(_) => "thread.message.in_progress",
236+
AssistantStreamEvent::ThreadMessageDelta(_) => "thread.message.delta",
237+
AssistantStreamEvent::ThreadMessageCompleted(_) => "thread.message.completed",
238+
AssistantStreamEvent::ThreadMessageIncomplete(_) => "thread.message.incomplete",
239+
AssistantStreamEvent::ErrorEvent(_) => "error",
240+
AssistantStreamEvent::Done(_) => "done",
241+
}
242+
}
243+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use crate::types::assistants::CreateMessageRequestContent;
2+
3+
impl From<String> for CreateMessageRequestContent {
4+
fn from(value: String) -> Self {
5+
Self::Content(value)
6+
}
7+
}
8+
9+
impl From<&str> for CreateMessageRequestContent {
10+
fn from(value: &str) -> Self {
11+
Self::Content(value.to_string())
12+
}
13+
}
14+
15+
impl Default for CreateMessageRequestContent {
16+
fn default() -> Self {
17+
Self::Content("".into())
18+
}
19+
}

async-openai/src/types/assistants/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod api;
22
mod assistant;
33
mod assistant_impls;
44
mod assistant_stream;
5+
mod impls;
56
mod message;
67
mod run;
78
mod step;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use crate::{
2+
error::OpenAIError,
3+
traits::AsyncTryFrom,
4+
types::audio::{
5+
CreateTranscriptionRequest, CreateTranslationRequest, TranscriptionChunkingStrategy,
6+
},
7+
util::create_file_part,
8+
};
9+
10+
impl AsyncTryFrom<CreateTranscriptionRequest> for reqwest::multipart::Form {
11+
type Error = OpenAIError;
12+
13+
async fn try_from(request: CreateTranscriptionRequest) -> Result<Self, Self::Error> {
14+
let audio_part = create_file_part(request.file.source).await?;
15+
16+
let mut form = reqwest::multipart::Form::new()
17+
.part("file", audio_part)
18+
.text("model", request.model);
19+
20+
if let Some(language) = request.language {
21+
form = form.text("language", language);
22+
}
23+
24+
if let Some(prompt) = request.prompt {
25+
form = form.text("prompt", prompt);
26+
}
27+
28+
if let Some(response_format) = request.response_format {
29+
form = form.text("response_format", response_format.to_string())
30+
}
31+
32+
if let Some(temperature) = request.temperature {
33+
form = form.text("temperature", temperature.to_string())
34+
}
35+
36+
if let Some(include) = request.include {
37+
for inc in include {
38+
form = form.text("include[]", inc.to_string());
39+
}
40+
}
41+
42+
if let Some(timestamp_granularities) = request.timestamp_granularities {
43+
for tg in timestamp_granularities {
44+
form = form.text("timestamp_granularities[]", tg.to_string());
45+
}
46+
}
47+
48+
if let Some(stream) = request.stream {
49+
form = form.text("stream", stream.to_string());
50+
}
51+
52+
if let Some(chunking_strategy) = request.chunking_strategy {
53+
match chunking_strategy {
54+
TranscriptionChunkingStrategy::Auto => {
55+
form = form.text("chunking_strategy", "auto");
56+
}
57+
TranscriptionChunkingStrategy::ServerVad(vad_config) => {
58+
form = form.text(
59+
"chunking_strategy",
60+
serde_json::to_string(&vad_config).unwrap().to_string(),
61+
);
62+
}
63+
}
64+
}
65+
66+
if let Some(known_speaker_names) = request.known_speaker_names {
67+
for kn in known_speaker_names {
68+
form = form.text("known_speaker_names[]", kn.to_string());
69+
}
70+
}
71+
72+
if let Some(known_speaker_references) = request.known_speaker_references {
73+
for kn in known_speaker_references {
74+
form = form.text("known_speaker_references[]", kn.to_string());
75+
}
76+
}
77+
78+
Ok(form)
79+
}
80+
}
81+
82+
impl AsyncTryFrom<CreateTranslationRequest> for reqwest::multipart::Form {
83+
type Error = OpenAIError;
84+
85+
async fn try_from(request: CreateTranslationRequest) -> Result<Self, Self::Error> {
86+
let audio_part = create_file_part(request.file.source).await?;
87+
88+
let mut form = reqwest::multipart::Form::new()
89+
.part("file", audio_part)
90+
.text("model", request.model);
91+
92+
if let Some(prompt) = request.prompt {
93+
form = form.text("prompt", prompt);
94+
}
95+
96+
if let Some(response_format) = request.response_format {
97+
form = form.text("response_format", response_format.to_string())
98+
}
99+
100+
if let Some(temperature) = request.temperature {
101+
form = form.text("temperature", temperature.to_string())
102+
}
103+
Ok(form)
104+
}
105+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use std::fmt::Display;
2+
3+
use crate::types::audio::{
4+
AudioResponseFormat, TimestampGranularity, TranscriptionInclude, TranslationResponseFormat,
5+
};
6+
7+
impl Display for AudioResponseFormat {
8+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9+
write!(
10+
f,
11+
"{}",
12+
match self {
13+
AudioResponseFormat::Json => "json",
14+
AudioResponseFormat::Srt => "srt",
15+
AudioResponseFormat::Text => "text",
16+
AudioResponseFormat::VerboseJson => "verbose_json",
17+
AudioResponseFormat::Vtt => "vtt",
18+
AudioResponseFormat::DiarizedJson => "diarized_json",
19+
}
20+
)
21+
}
22+
}
23+
24+
impl Display for TranslationResponseFormat {
25+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26+
write!(
27+
f,
28+
"{}",
29+
match self {
30+
TranslationResponseFormat::Json => "json",
31+
TranslationResponseFormat::Srt => "srt",
32+
TranslationResponseFormat::Text => "text",
33+
TranslationResponseFormat::VerboseJson => "verbose_json",
34+
TranslationResponseFormat::Vtt => "vtt",
35+
}
36+
)
37+
}
38+
}
39+
40+
impl Display for TimestampGranularity {
41+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42+
write!(
43+
f,
44+
"{}",
45+
match self {
46+
TimestampGranularity::Word => "word",
47+
TimestampGranularity::Segment => "segment",
48+
}
49+
)
50+
}
51+
}
52+
53+
impl Display for TranscriptionInclude {
54+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55+
write!(
56+
f,
57+
"{}",
58+
match self {
59+
TranscriptionInclude::Logprobs => "logprobs",
60+
}
61+
)
62+
}
63+
}

async-openai/src/types/audio/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
mod audio_types;
2+
mod form;
3+
mod impls;
4+
mod sdk;
25
mod stream;
36

47
pub use audio_types::*;

0 commit comments

Comments
 (0)