Skip to content

Commit

Permalink
handle assistant api
Browse files Browse the repository at this point in the history
  • Loading branch information
hoseinzadehashraf committed Dec 1, 2023
1 parent 1cf7737 commit a271317
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 25 deletions.
24 changes: 0 additions & 24 deletions Olive.Gpt/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,5 @@ public async Task<string> GetResponse(ChatMessage[] messages)

return result.ToString();
}

public async Task<string> GetThreadId()
{
var payload = new StringContent("", Encoding.UTF8, "application/json");

var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://api.openai.com/v1/threads") { Content = payload };
Client.DefaultRequestHeaders.Add("OpenAI-Beta", "assistants=v1");
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi Thread API to get completion. HTTP status code: " + response.StatusCode +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiThread>(result);

return jObject.Id;
}

public class OpenAiThread
{
public string Id { get; set; }
}
}
}
120 changes: 120 additions & 0 deletions Olive.Gpt/AssistantApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Olive.Gpt.AssistantDto;

namespace Olive.Gpt
{
public class AssistantApi
{
readonly JsonSerializerSettings Settings = new() { NullValueHandling = NullValueHandling.Ignore };
readonly HttpClient Client = new(CreateForgivingHandler()) { Timeout = 60.Seconds() };
string Model;

public AssistantApi(string apiKey, string model = "gpt-3.5-turbo")
{
Model = model;
Client.DefaultRequestHeaders.Authorization = new("Bearer", apiKey);
Client.DefaultRequestHeaders.Add("User-Agent", "olive/dotnet_openai_api");
Client.DefaultRequestHeaders.Add("OpenAI-Beta", "assistants=v1");
}

static HttpClientHandler CreateForgivingHandler() => new()
{
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
};

public async Task<string> CreateNewThread()
{
var payload = new StringContent("", Encoding.UTF8, "application/json");

var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://api.openai.com/v1/threads") { Content = payload };
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi New Thread API to get completion. HTTP status code: " + response.StatusCode +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiThreadDto>(result);

return jObject.Id;
}

private async Task<string> AddMessageToThread(ChatMessage[] messages, string threadId)
{
var jsonContent = JsonConvert.SerializeObject(new ChatRequest(messages) { Model = Model }, Settings);
var payload = new StringContent(jsonContent, Encoding.UTF8, "application/json");

var url = $"https://api.openai.com/v1/threads/{threadId}/messages";

var httpRequest = new HttpRequestMessage(HttpMethod.Post, url) { Content = payload };
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi Add Message API to get completion. HTTP status code: " + response.StatusCode +
". Request body: " + jsonContent +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiMessageDto>(result);

return jObject.Id;
}

public async Task<string> CreateNewRun(string assistantId, string threadId)
{
var payload = new StringContent(JsonConvert.SerializeObject(new { assistant_id = assistantId }, Settings), Encoding.UTF8, "application/json");

var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"https://api.openai.com/v1/threads/{threadId}/runs") { Content = payload };
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi New Run API to get completion. HTTP status code: " + response.StatusCode +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiRunDto>(result);

return jObject.Id;
}

public async Task<OpenAiRunStatus> GetRunStatus(string threadId, string runId)
{
var httpRequest = new HttpRequestMessage(HttpMethod.Get, $"https://api.openai.com/v1/threads/{threadId}/runs/{runId}");
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi Get Run API to get completion. HTTP status code: " + response.StatusCode +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiRunDto>(result);

return jObject.Status;
}

public async Task<OpenAiMessageDto[]> GetThreadMessages(string threadId, string lastMessageId)
{
var httpRequest = new HttpRequestMessage(HttpMethod.Get, $"https://api.openai.com/v1/threads/{threadId}/messages?limit=100&after={lastMessageId}&order=asc");
var response = await Client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);

if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Error calling OpenAi Get Run API to get completion. HTTP status code: " + response.StatusCode +
". Response body: " + await response.Content.ReadAsStringAsync());

var result = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<OpenAiMessagesDto>(result);

return jObject.Data;
}
}
}
7 changes: 7 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiMessageContentDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Olive.Gpt.AssistantDto;

public class OpenAiMessageContentDto
{
public string Type { get; set; }
public OpenAiMessageContentTextDto Text { get; set; }
}
6 changes: 6 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiMessageContentTextDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Olive.Gpt.AssistantDto;

public class OpenAiMessageContentTextDto
{
public string Value { get; set; }
}
8 changes: 8 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiMessageDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Olive.Gpt.AssistantDto;

public class OpenAiMessageDto
{
public string Id { get; set; }
public string Role { get; set; }
public OpenAiMessageContentDto Content { get; set; }
}
6 changes: 6 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiMessagesDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Olive.Gpt.AssistantDto;

public class OpenAiMessagesDto
{
public OpenAiMessageDto[] Data { get; set; }
}
7 changes: 7 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiRunDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Olive.Gpt.AssistantDto;

public class OpenAiRunDto
{
public string Id { get; set; }
public OpenAiRunStatus Status { get; set; }
}
17 changes: 17 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiRunStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Runtime.Serialization;

namespace Olive.Gpt.AssistantDto;

public enum OpenAiRunStatus
{
Queued,
[EnumMember(Value = "in_progress")]
InProgress,
[EnumMember(Value = "requires_action")]
RequiresAction,
Cancelling,
Cancelled,
Failed,
Completed,
Expired
}
12 changes: 12 additions & 0 deletions Olive.Gpt/AssistantDto/OpenAiThreadDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Olive.Gpt.AssistantDto
{
using System;
using System.Collections.Generic;
using System.Text;


public class OpenAiThreadDto
{
public string Id { get; set; }
}
}
2 changes: 1 addition & 1 deletion Olive.Gpt/Olive.Gpt.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>1.0.104</Version>
<Version>1.0.105</Version>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit a271317

Please sign in to comment.