Skip to content

Commit

Permalink
docs: Updated generated docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
HavenDV committed Oct 25, 2024
1 parent 373365d commit 4e5bdd8
Show file tree
Hide file tree
Showing 16 changed files with 549 additions and 65 deletions.
16 changes: 12 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
[![Discord](https://img.shields.io/discord/1115206893015662663?label=Discord&logo=discord&logoColor=white&color=d82679)](https://discord.gg/Ca2xhfBf3v)

## Features 🔥
- Fully generated C# SDK based on [official OpenAI OpenAPI specification](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml) using [OpenApiGenerator](https://github.com/HavenDV/OpenApiGenerator)
- Fully generated C# SDK based on [official OpenAI OpenAPI specification](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml) using [AutoSDK](https://github.com/tryAGI/AutoSDK)
- Same day update to support new features
- Updated and supported automatically if there are no breaking changes
- Contains a supported list of constants such as current prices, models, and other
- Source generator to define functions natively through C# interfaces
- All modern .NET features - nullability, trimming, NativeAOT, etc.
- Support .Net Framework/.Net Standard 2.0
- Support all OpenAI API endpoints including completions, chat, embeddings, images, assistants and more.
- Regularly tested for compatibility with popular custom providers like OpenRouter/DeepSeek
- Regularly tested for compatibility with popular custom providers like OpenRouter/DeepSeek/Ollama/LM Studio and many others

## Documentation
Examples and documentation can be found here: https://tryagi.github.io/OpenAI/
Expand Down Expand Up @@ -46,6 +46,7 @@ You still can use the full response objects if you need more information, just r
### Tools
```csharp
using OpenAI;
using CSharpToJsonSchema;

public enum Unit
{
Expand All @@ -61,7 +62,7 @@ public class Weather
public string Description { get; set; } = string.Empty;
}

[OpenAiTools(Strict = true)] // false by default. You can't use parameters with default values in Strict mode.
[GenerateJsonSchema(Strict = true)] // false by default. You can't use parameters with default values in Strict mode.
public interface IWeatherFunctions
{
[Description("Get the current weather in a given location")]
Expand All @@ -88,7 +89,7 @@ public class WeatherService : IWeatherFunctions
using var api = new OpenAiApi("API_KEY");

var service = new WeatherService();
var tools = service.AsTools();
var tools = service.AsTools().AsOpenAiTools();

var messages = new List<ChatCompletionRequestMessage>
{
Expand Down Expand Up @@ -177,10 +178,17 @@ using OpenAI;
using var api = CustomProviders.GitHubModels("GITHUB_TOKEN");
using var api = CustomProviders.Azure("API_KEY", "ENDPOINT");
using var api = CustomProviders.DeepInfra("API_KEY");
using var api = CustomProviders.Groq("API_KEY");
using var api = CustomProviders.DeepSeek("API_KEY");
using var api = CustomProviders.Fireworks("API_KEY");
using var api = CustomProviders.OpenRouter("API_KEY");
using var api = CustomProviders.Together("API_KEY");
using var api = CustomProviders.Perplexity("API_KEY");
using var api = CustomProviders.SambaNova("API_KEY");
using var api = CustomProviders.Mistral("API_KEY");
using var api = CustomProviders.Codestral("API_KEY");
using var api = CustomProviders.Ollama();
using var api = CustomProviders.LmStudio();
```

### Constants
Expand Down
197 changes: 197 additions & 0 deletions docs/samples/Assistants.AllTools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
```csharp
using var api = GetAuthenticatedClient();

OpenAIFile favoriteNumberFile = await api.Files.CreateFileAsync(
file: """
This file contains the favorite numbers for individuals.
John Doe: 14
Bob Doe: 32
Jane Doe: 44
"""u8.ToArray(),
filename: "favorite_numbers.txt",
purpose: CreateFileRequestPurpose.Assistants);

var service = new AllToolsService();
IList<ChatCompletionTool> tools = service.AsTools().AsOpenAiTools();

AssistantObject assistant = await api.Assistants.CreateAssistantAsync(
model: CreateAssistantRequestModel.Gpt4o,
instructions: "Use functions to resolve family relations into the names of people. Use file search to "
+ " look up the favorite numbers of people. Use code interpreter to create graphs of lines.",
tools: tools
.Select(x => new ToolsItem2(new AssistantToolsFunction
{
Function = x.Function,
}))
.Concat([
new AssistantToolsFileSearch(),
new AssistantToolsCode()
])
.ToArray(),
toolResources: new CreateAssistantRequestToolResources
{
FileSearch = new CreateAssistantRequestToolResourcesFileSearch
{
VectorStores = new List<CreateAssistantRequestToolResourcesFileSearchVectorStore>
{
new()
{
FileIds = [favoriteNumberFile.Id],
},
},
},
});

RunObject run = await api.Assistants.CreateThreadAndRunAsync(
assistantId: assistant.Id,
new CreateThreadRequest
{
Messages = [
"Create a graph of a line with a slope that's my father's favorite number "
+ "and an offset that's my mother's favorite number.",
"Include people's names in your response and cite where you found them."
],
});

// Poll the run until it is no longer queued or in progress.
while (run.Status is RunObjectStatus.Queued or RunObjectStatus.InProgress or RunObjectStatus.RequiresAction)
{
await Task.Delay(TimeSpan.FromSeconds(1));
run = await api.Assistants.GetRunAsync(run.ThreadId, run.Id);

// If the run requires action, resolve them.
if (run.Status == RunObjectStatus.RequiresAction)
{
List<SubmitToolOutputsRunRequestToolOutput> toolOutputs = [];

foreach (RunToolCallObject toolCall in run.RequiredAction?.SubmitToolOutputs.ToolCalls ?? [])
{
var json = await service.CallAsync(
functionName: toolCall.Function.Name,
argumentsAsJson: toolCall.Function.Arguments);
toolOutputs.Add(new SubmitToolOutputsRunRequestToolOutput
{
ToolCallId = toolCall.Id,
Output = json,
});
}

// Submit the tool outputs to the assistant, which returns the run to the queued state.
run = await api.Assistants.SubmitToolOuputsToRunAsync(
threadId: run.ThreadId,
runId: run.Id,
toolOutputs: toolOutputs);
}
}

// With the run complete, list the messages and display their content
if (run.Status == RunObjectStatus.Completed)
{
ListMessagesResponse messages
= await api.Assistants.ListMessagesAsync(run.ThreadId, order: ListMessagesOrder.Asc);

foreach (MessageObject message in messages.Data)
{
Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: ");
foreach (ContentItem2 contentItem in message.Content)
{
if (contentItem.MessageImageFileObject is {} imageFile)
{
OpenAIFile imageInfo = await api.Files.RetrieveFileAsync(imageFile.ImageFile.FileId);
byte[] imageBytes = await api.Files.DownloadFileAsync(imageFile.ImageFile.FileId);

FileInfo fileInfo = new($"{imageInfo.Filename}.png");

await File.WriteAllBytesAsync(fileInfo.FullName, imageBytes);

Console.WriteLine($"<image: {new Uri(fileInfo.FullName).AbsoluteUri}>");
}
if (contentItem.MessageImageUrlObject is {} imageUrl)
{
Console.WriteLine($" <Image URL> {imageUrl.ImageUrl.Url}");
}
if (contentItem.MessageTextObject is {} text)
{
Console.WriteLine($"{text.Text.Value}");

// Include annotations, if any.
if (text.Text.Annotations.Count > 0)
{
Console.WriteLine();
foreach (AnnotationsItem annotation in text.Text.Annotations)
{
if (annotation.MessageContentTextFileCitationObject is {} fileCitation)
{
Console.WriteLine($"* File citation, file ID: {fileCitation.FileCitation.FileId}");
Console.WriteLine($"* Text to replace: {fileCitation.Text}");
Console.WriteLine($"* Message content index range: {fileCitation.StartIndex}-{fileCitation.EndIndex}");
}
if (annotation.MessageContentTextFilePathObject is {} filePath)
{
Console.WriteLine($"* File output, new file ID: {filePath.FilePath.FileId}");
Console.WriteLine($"* Text to replace: {filePath.Text}");
Console.WriteLine($"* Message content index range: {filePath.StartIndex}-{filePath.EndIndex}");
}
}
}
}
if (contentItem.MessageRefusalObject is {} refusal)
{
Console.WriteLine($"Refusal: {refusal.Refusal}");
}
}
Console.WriteLine();
}


// List run steps for details about tool calls
ListRunStepsResponse runSteps = await api.Assistants.ListRunStepsAsync(
threadId: run.ThreadId,
runId: run.Id,
order: ListRunStepsOrder.Asc);
foreach (RunStepObject step in runSteps.Data)
{
Console.WriteLine($"Run step: {step.Status}");
foreach (var toolCall in step.StepDetails.ToolCalls?.ToolCalls ?? [])
{
if (toolCall.RunStepDetailsCodeObject is {} codeInterpreter)
{
Console.WriteLine($" --> Tool call: {codeInterpreter.Type}");
foreach (var output in codeInterpreter.CodeInterpreter.Outputs)
{
if (output.Logs is {} logs)
{
Console.WriteLine($" --> Output: {logs.Logs}");
}
if (output.Image is {} image)
{
Console.WriteLine($" --> Output: {image.Image.FileId}");
}
}
}
if (toolCall.RunStepDetailsFileSearchObject is {} fileSearch)
{
Console.WriteLine($" --> Tool call: {fileSearch.Type}");
foreach (var output in fileSearch.FileSearch.Results ?? [])
{
Console.WriteLine($" --> Output: {output.FileId}");
}
}
if (toolCall.RunStepDetailsFunctionObject is {} tool)
{
Console.WriteLine($" --> Tool call: {tool.Type}");
}
}
}
}
else
{
throw new NotImplementedException(run.Status.ToString());
}

// Optionally, delete any persistent resources you no longer need.
_ = await api.Assistants.DeleteThreadAsync(run.ThreadId);
_ = await api.Assistants.DeleteAssistantAsync(assistant.Id);
_ = await api.Files.DeleteFileAsync(favoriteNumberFile.Id);
```
24 changes: 24 additions & 0 deletions docs/samples/Assistants.AllToolsService.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
```csharp
[GenerateJsonSchema(Strict = false)]
public interface IAllToolsService
{
[Description("Provided a family relation type like 'father' or 'mother', "
+ "gets the name of the related person from the user.")]
public string GetNameOfFamilyMember(
[Description("The relation to the user to query, e.g. 'mother' or 'father'")]
string relation);
}

public class AllToolsService : IAllToolsService
{
public string GetNameOfFamilyMember(string relation)
{
return relation switch
{
not null when relation.Contains("father") => "John Doe",
not null when relation.Contains("mother") => "Jane Doe",
_ => throw new ArgumentException(relation, nameof(relation))
};
}
}
```
74 changes: 38 additions & 36 deletions docs/samples/Assistants.AssistantsWithVision.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,12 @@ await File.WriteAllBytesAsync(appleFileInfo.FullName, appleBytes);

Console.WriteLine($"Apple image available at:\n{new Uri(appleFileInfo.FullName).AbsoluteUri}");

ImagesResponse orangeImage = await api.Images.CreateImageAsync(
prompt: "picture of orange",
responseFormat: CreateImageRequestResponseFormat.B64Json);
byte[] orangeBytes = orangeImage.Data[0].Bytes;

FileInfo orangeFileInfo = new($"{Guid.NewGuid()}.png");

await File.WriteAllBytesAsync(orangeFileInfo.FullName, orangeBytes);

Console.WriteLine($"Orange image available at:\n{new Uri(orangeFileInfo.FullName).AbsoluteUri}");
Console.WriteLine($"Orange image available at:\n{new Uri("https://raw.githubusercontent.com/tryAGI/OpenAI/d237b700b03fe9913a6ff53fa623041e87705f2f/assets/orange.png")}");

OpenAIFile pictureOfAppleFile = await api.Files.CreateFileAsync(
file: appleBytes,
filename: appleFileInfo.Name,
purpose: CreateFileRequestPurpose.Vision);
OpenAIFile pictureOfOrangeFile = await api.Files.CreateFileAsync(
file: orangeBytes,
filename: orangeFileInfo.Name,
purpose: CreateFileRequestPurpose.Vision);

AssistantObject assistant = await api.Assistants.CreateAssistantAsync(
model: CreateAssistantRequestModel.Gpt4o,
Expand All @@ -42,7 +29,7 @@ ThreadObject thread = await api.Assistants.CreateThreadAsync(new CreateThreadReq
Messages = [
"Hello, assistant! Please compare these two images for me:",
pictureOfAppleFile,
pictureOfOrangeFile,
new Uri("https://raw.githubusercontent.com/tryAGI/OpenAI/d237b700b03fe9913a6ff53fa623041e87705f2f/assets/orange.png"),
]
});

Expand All @@ -53,33 +40,48 @@ var streamingUpdates = api.Assistants.CreateRunAsStreamAsync(

await foreach (AssistantStreamEvent streamingUpdate in streamingUpdates)
{
if (streamingUpdate.IsRun && streamingUpdate.Run.Value.IsValue1) // RunCreated
if (streamingUpdate.Error is {} error)
{
Console.WriteLine("--- Run started! ---");
Console.WriteLine("--- Error ---");
Console.WriteLine($"Message: {error.Data.Message}");
Console.WriteLine($"Code: {error.Data.Code}");
Console.WriteLine($"Type: {error.Data.Type}");
}
if (streamingUpdate is { IsMessage: true, Message: var messageStreamEvent } &&
messageStreamEvent.Value is { IsValue3: true, Value3: var delta })
if (streamingUpdate.Run is {} run)
{
foreach (var deltaVariation in delta.Data.Delta.Content ?? [])
if (run.Value1 is { Event: RunStreamEventVariant1Event.ThreadRunCreated })
{
if (deltaVariation.IsValue1)
{
Console.WriteLine();
Console.WriteLine(deltaVariation.Value1.ImageFile?.FileId);
}
if (deltaVariation.IsValue2)
{
Console.Write(deltaVariation.Value2.Text?.Value);
}
if (deltaVariation.IsValue3)
Console.WriteLine("--- Run created! ---");
}
}
if (streamingUpdate.Message is {} message)
{
if (message.Value3 is
{
Console.WriteLine();
Console.WriteLine(deltaVariation.Value3.Refusal);
}
if (deltaVariation.IsValue4)
Event: MessageStreamEventVariant3Event.ThreadMessageDelta
} delta)
{
foreach (var deltaVariation in delta.Data.Delta.Content ?? [])
{
Console.WriteLine();
Console.WriteLine(deltaVariation.Value4.ImageUrl?.Url);
if (deltaVariation.Value1 is {} imageFile)
{
Console.WriteLine();
Console.WriteLine(imageFile.ImageFile?.FileId);
}
if (deltaVariation.Value2 is {} text)
{
Console.Write(text.Text?.Value);
}
if (deltaVariation.Value3 is {} refusal)
{
Console.WriteLine();
Console.WriteLine(refusal.Refusal);
}
if (deltaVariation.Value4 is {} imageUrl)
{
Console.WriteLine();
Console.WriteLine(imageUrl.ImageUrl?.Url);
}
}
}
}
Expand Down
Loading

0 comments on commit 4e5bdd8

Please sign in to comment.