Skip to content

Commit

Permalink
com.openai.unity 8.4.0 (#303)
Browse files Browse the repository at this point in the history
- Add realtime support
- Added `o1`, `o1-mini`, `gpt-4o-mini`, and `gpt-4o-realtime`, `gpt-4o-audio` model convenience properties
- Fixed some bugs with function invocations
- Fixed `strict` for built in `FunctionAttribute` defined tools
- Fixed `FunctionAttribute` tool generated names so they aren't too long
- Refactored `Tools` and `ToolCalls`. There is more of a distinction now in `ChatResponses`
- Refactored `SpeechRequest`, and deprecated `SpeechVoice` enum in favor of new `Voice` class
- Refactored `OpenAI.Chat` to support new audio modalities and output audio
  • Loading branch information
StephenHodgson authored Nov 15, 2024
1 parent 27a2d3c commit d8afd72
Show file tree
Hide file tree
Showing 208 changed files with 11,699 additions and 1,065 deletions.
248 changes: 237 additions & 11 deletions Documentation~/README.md

Large diffs are not rendered by default.

214 changes: 57 additions & 157 deletions Runtime/Assistants/AssistantExtensions.cs

Large diffs are not rendered by default.

68 changes: 0 additions & 68 deletions Runtime/Assistants/AssistantFileResponse.cs

This file was deleted.

14 changes: 3 additions & 11 deletions Runtime/Assistants/AssistantResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,6 @@ internal AssistantResponse(
[JsonProperty("tool_resources")]
public ToolResources ToolResources { get; }

/// <summary>
/// A list of file IDs attached to this assistant.
/// There can be a maximum of 20 files attached to the assistant.
/// Files are ordered by their creation date in ascending order.
/// </summary>
[JsonIgnore]
[Obsolete("Files removed from Assistants. Files now belong to ToolResources.")]
public IReadOnlyList<string> FileIds => null;

/// <summary>
/// Set of 16 key-value pairs that can be attached to an object.
/// This can be useful for storing additional information about the object in a structured format.
Expand Down Expand Up @@ -161,7 +152,7 @@ internal AssistantResponse(

/// <summary>
/// Specifies the format that the model must output.
/// Setting to <see cref="ChatResponseFormat.Json"/> enables JSON mode,
/// Setting to <see cref="ChatResponseFormat.Json"/> or <see cref="ChatResponseFormat.JsonSchema"/> enables JSON mode,
/// which guarantees the message the model generates is valid JSON.
/// </summary>
/// <remarks>
Expand All @@ -172,10 +163,11 @@ internal AssistantResponse(
/// which indicates the generation exceeded max_tokens or the conversation exceeded the max context length.
/// </remarks>
[Preserve]
[JsonProperty("response_format")]
[JsonConverter(typeof(ResponseFormatConverter))]
[JsonProperty("response_format", DefaultValueHandling = DefaultValueHandling.Ignore)]
public ResponseFormatObject ResponseFormatObject { get; }

[Preserve]
[JsonIgnore]
public ChatResponseFormat ResponseFormat => ResponseFormatObject ?? ChatResponseFormat.Auto;

Expand Down
80 changes: 0 additions & 80 deletions Runtime/Assistants/AssistantsEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

using Newtonsoft.Json;
using OpenAI.Extensions;
using OpenAI.Files;
using System;
using System.Threading;
using System.Threading.Tasks;
using Utilities.WebRequestRest;
Expand Down Expand Up @@ -105,83 +103,5 @@ public async Task<bool> DeleteAssistantAsync(string assistantId, CancellationTok
response.Validate(EnableDebug);
return response.Deserialize<DeletedResponse>(client)?.Deleted ?? false;
}

#region Files (Obsolete)

/// <summary>
/// Returns a list of assistant files.
/// </summary>
/// <param name="assistantId">The ID of the assistant the file belongs to.</param>
/// <param name="query"><see cref="ListQuery"/>.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns><see cref="ListResponse{AssistantFile}"/>.</returns>
[Obsolete("Files removed from Assistants. Files now belong to ToolResources.")]
public async Task<ListResponse<AssistantFileResponse>> ListFilesAsync(string assistantId, ListQuery query = null, CancellationToken cancellationToken = default)
{
var response = await Rest.GetAsync(GetUrl($"/{assistantId}/files", query), new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response.Validate(EnableDebug);
return response.Deserialize<ListResponse<AssistantFileResponse>>(client);
}

/// <summary>
/// Attach a file to an assistant.
/// </summary>
/// <param name="assistantId"> The ID of the assistant for which to attach a file. </param>
/// <param name="file">
/// A <see cref="FileResponse"/> (with purpose="assistants") that the assistant should use.
/// Useful for tools like retrieval and code_interpreter that can access files.
/// </param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns><see cref="AssistantFileResponse"/>.</returns>
[Obsolete("Files removed from Assistants. Files now belong to ToolResources.")]
public async Task<AssistantFileResponse> AttachFileAsync(string assistantId, FileResponse file, CancellationToken cancellationToken = default)
{
if (file?.Purpose?.Equals(FilePurpose.Assistants) != true)
{
throw new InvalidOperationException($"{nameof(file)}.{nameof(file.Purpose)} must be 'assistants'!");
}

var payload = JsonConvert.SerializeObject(new { file_id = file.Id }, OpenAIClient.JsonSerializationOptions);
var response = await Rest.PostAsync(GetUrl($"/{assistantId}/files"), payload, new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response.Validate(EnableDebug);
return response.Deserialize<AssistantFileResponse>(client);
}

/// <summary>
/// Retrieves an AssistantFile.
/// </summary>
/// <param name="assistantId">The ID of the assistant who the file belongs to.</param>
/// <param name="fileId">The ID of the file we're getting.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns><see cref="AssistantFileResponse"/>.</returns>
[Obsolete("Files removed from Assistants. Files now belong to ToolResources.")]
public async Task<AssistantFileResponse> RetrieveFileAsync(string assistantId, string fileId, CancellationToken cancellationToken = default)
{
var response = await Rest.GetAsync(GetUrl($"/{assistantId}/files/{fileId}"), new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response.Validate(EnableDebug);
return response.Deserialize<AssistantFileResponse>(client);
}

/// <summary>
/// Remove an assistant file.
/// </summary>
/// <remarks>
/// Note that removing an AssistantFile does not delete the original File object,
/// it simply removes the association between that File and the Assistant.
/// To delete a File, use the File delete endpoint instead.
/// </remarks>
/// <param name="assistantId">The ID of the assistant that the file belongs to.</param>
/// <param name="fileId">The ID of the file to delete.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>True, if file was removed.</returns>
[Obsolete("Files removed from Assistants. Files now belong to ToolResources.")]
public async Task<bool> RemoveFileAsync(string assistantId, string fileId, CancellationToken cancellationToken = default)
{
var response = await Rest.DeleteAsync(GetUrl($"/{assistantId}/files/{fileId}"), new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response.Validate(EnableDebug);
return response.Deserialize<DeletedResponse>(client)?.Deleted ?? false;
}

#endregion Files (Obsolete)
}
}
19 changes: 3 additions & 16 deletions Runtime/Assistants/CreateAssistantRequest.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Newtonsoft.Json;
using Newtonsoft.Json.Schema;
using OpenAI.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Scripting;
Expand Down Expand Up @@ -102,19 +100,6 @@ public CreateAssistantRequest(
{
}

[Obsolete("use new .ctr")]
public CreateAssistantRequest(
AssistantResponse assistant,
string model,
string name,
string description,
string instructions,
IEnumerable<Tool> tools,
IEnumerable<string> files,
IReadOnlyDictionary<string, string> metadata)
{
}

/// <summary>
/// Constructor.
/// </summary>
Expand Down Expand Up @@ -279,7 +264,7 @@ public CreateAssistantRequest(

/// <summary>
/// Specifies the format that the model must output.
/// Setting to <see cref="ChatResponseFormat.Json"/> enables JSON mode,
/// Setting to <see cref="ChatResponseFormat.Json"/> or <see cref="ChatResponseFormat.JsonSchema"/> enables JSON mode,
/// which guarantees the message the model generates is valid JSON.
/// </summary>
/// <remarks>
Expand All @@ -294,6 +279,7 @@ public CreateAssistantRequest(
[JsonProperty("response_format", DefaultValueHandling = DefaultValueHandling.Ignore)]
public ResponseFormatObject ResponseFormatObject { get; internal set; }

[Preserve]
[JsonIgnore]
public ChatResponseFormat ResponseFormat => ResponseFormatObject ?? ChatResponseFormat.Auto;

Expand All @@ -302,6 +288,7 @@ public CreateAssistantRequest(
/// This can be useful for storing additional information about the object in a structured format.
/// Keys can be a maximum of 64 characters long and values can be a maximum of 512 characters long.
/// </summary>
[Preserve]
[JsonProperty("metadata")]
public IReadOnlyDictionary<string, string> Metadata { get; }
}
Expand Down
8 changes: 0 additions & 8 deletions Runtime/Audio/AudioEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,6 @@ void StreamCallback(Response partialResponse)
return new Tuple<string, AudioClip>(cachedPath, clip);
}

[Obsolete("Use CreateTranscriptionTextAsync or CreateTranscriptionJsonAsync instead.")]
public async Task<string> CreateTranscriptionAsync(AudioTranscriptionRequest request, CancellationToken cancellationToken = default)
=> await CreateTranscriptionTextAsync(request, cancellationToken);

/// <summary>
/// Transcribes audio into the input language.
/// </summary>
Expand Down Expand Up @@ -201,10 +197,6 @@ private async Task<string> Internal_CreateTranscriptionAsync(AudioTranscriptionR
return response.Body;
}

[Obsolete("Use CreateTranslationTextAsync or CreateTranslationJsonAsync instead.")]
public async Task<string> CreateTranslationAsync(AudioTranslationRequest request, CancellationToken cancellationToken = default)
=> await CreateTranslationTextAsync(request, cancellationToken);

/// <summary>
/// Translates audio into English.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions Runtime/Audio/SpeechRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public sealed class SpeechRequest
/// <param name="responseFormat">The format to audio in. Supported formats are mp3, opus, aac, flac, wav and pcm.</param>
/// <param name="speed">The speed of the generated audio. Select a value from 0.25 to 4.0. 1.0 is the default.</param>
[Preserve]
public SpeechRequest(string input, Model model = null, SpeechVoice voice = SpeechVoice.Alloy, SpeechResponseFormat responseFormat = SpeechResponseFormat.MP3, float? speed = null)
public SpeechRequest(string input, Model model = null, Voice voice = null, SpeechResponseFormat responseFormat = SpeechResponseFormat.MP3, float? speed = null)
{
Input = !string.IsNullOrWhiteSpace(input) ? input : throw new ArgumentException("Input cannot be null or empty.", nameof(input));
Model = string.IsNullOrWhiteSpace(model?.Id) ? Models.Model.TTS_1 : model;
Voice = voice;
Voice = string.IsNullOrWhiteSpace(voice?.Id) ? OpenAI.Voice.Alloy : voice;
ResponseFormat = responseFormat;
Speed = speed;
}
Expand All @@ -49,8 +49,8 @@ public SpeechRequest(string input, Model model = null, SpeechVoice voice = Speec
/// </summary>
[Preserve]
[JsonProperty("voice", DefaultValueHandling = DefaultValueHandling.Include)]
[FunctionProperty("The voice to use when generating the audio.", true)]
public SpeechVoice Voice { get; }
[FunctionProperty("The voice to use when generating the audio.", true, "alloy", "echo", "fable", "onyx", "nova", "shimmer")]
public string Voice { get; }

/// <summary>
/// The format to audio in. Supported formats are mp3, opus, aac, flac, wav and pcm.
Expand Down
3 changes: 3 additions & 0 deletions Runtime/Audio/SpeechVoice.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;

namespace OpenAI.Audio
{
[Obsolete("Use OpenAI.Voice instead.")]
public enum SpeechVoice
{
Alloy = 0,
Expand Down
3 changes: 3 additions & 0 deletions Runtime/Audio/TranscriptionSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace OpenAI.Audio
{
/// <summary>
/// Segment of the transcribed text and their corresponding details.
/// </summary>
[Preserve]
public sealed class TranscriptionSegment
{
Expand Down
3 changes: 3 additions & 0 deletions Runtime/Audio/TranscriptionWord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace OpenAI.Audio
{
/// <summary>
/// Extracted word and their corresponding timestamps.
/// </summary>
[Preserve]
public sealed class TranscriptionWord
{
Expand Down
2 changes: 1 addition & 1 deletion Runtime/Authentication/OpenAIAuthentication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ public override OpenAIAuthentication LoadFromDirectory(string directory = null,

var lines = File.ReadAllLines(filePath);
string apiKey = null;
string organizationId = null;
string projectId = null;
string organizationId = null;

foreach (var line in lines)
{
Expand Down
Loading

0 comments on commit d8afd72

Please sign in to comment.