-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ccddc3
commit a2edc20
Showing
12 changed files
with
405 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System.Net.Http.Json; | ||
using Together.Models.Error; | ||
|
||
namespace Together.Clients; | ||
|
||
public abstract class BaseClient | ||
{ | ||
protected readonly HttpClient HttpClient; | ||
|
||
protected BaseClient(HttpClient httpClient) | ||
{ | ||
HttpClient = httpClient; | ||
} | ||
|
||
protected async Task<TResponse> SendRequestAsync<TRequest, TResponse>(string requestUri, TRequest request, CancellationToken cancellationToken) | ||
{ | ||
var responseMessage = await HttpClient.PostAsJsonAsync(requestUri, request, cancellationToken); | ||
return await HandleResponseAsync<TResponse>(responseMessage, cancellationToken); | ||
} | ||
|
||
protected async Task<TResponse> SendRequestAsync<TResponse>(string requestUri, HttpMethod method, HttpContent? content, CancellationToken cancellationToken) | ||
{ | ||
using var request = new HttpRequestMessage(method, requestUri); | ||
if (content != null) | ||
{ | ||
request.Content = content; | ||
} | ||
|
||
var responseMessage = await HttpClient.SendAsync(request, cancellationToken); | ||
return await HandleResponseAsync<TResponse>(responseMessage, cancellationToken); | ||
} | ||
|
||
private static async Task<TResponse> HandleResponseAsync<TResponse>(HttpResponseMessage responseMessage, CancellationToken cancellationToken) | ||
{ | ||
if (responseMessage.IsSuccessStatusCode) | ||
{ | ||
if (typeof(TResponse) == typeof(HttpResponseMessage) && responseMessage is TResponse response) | ||
{ | ||
return response; | ||
} | ||
|
||
var result = await responseMessage.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken); | ||
return result!; | ||
} | ||
|
||
var errorResponse = await responseMessage.Content.ReadFromJsonAsync<ErrorResponse>(cancellationToken: cancellationToken); | ||
if (errorResponse?.Error != null) | ||
{ | ||
throw new Exception(errorResponse.Error.Message); | ||
} | ||
|
||
var statusCode = responseMessage.StatusCode; | ||
var errorContent = await responseMessage.Content.ReadAsStringAsync(cancellationToken); | ||
throw new Exception($"Request failed with status code {statusCode}: {errorContent}"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using System.Runtime.CompilerServices; | ||
using System.Text.Json; | ||
using Together.Models.ChatCompletions; | ||
|
||
namespace Together.Clients; | ||
|
||
public class ChatCompletionClient(HttpClient httpClient) : BaseClient(httpClient) | ||
{ | ||
public async Task<ChatCompletionResponse> CreateAsync(ChatCompletionRequest request, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<ChatCompletionRequest, ChatCompletionResponse>("/chat/completions", request, cancellationToken); | ||
} | ||
|
||
public async IAsyncEnumerable<ChatCompletionChunk> CreateStreamAsync(ChatCompletionRequest request, | ||
[EnumeratorCancellation] CancellationToken cancellationToken = default) | ||
{ | ||
var responseMessage = await SendRequestAsync<ChatCompletionRequest, HttpResponseMessage>("/chat/completions", request, cancellationToken); | ||
|
||
await using var stream = await responseMessage.Content.ReadAsStreamAsync(cancellationToken); | ||
using var reader = new StreamReader(stream); | ||
|
||
while (await reader.ReadLineAsync(cancellationToken) is string line) | ||
{ | ||
if (!line.StartsWith("data:")) | ||
continue; | ||
|
||
var eventData = line.Substring("data:".Length) | ||
.Trim(); | ||
if (eventData is null or "[DONE]") | ||
break; | ||
|
||
var result = JsonSerializer.Deserialize<ChatCompletionChunk>(eventData); | ||
|
||
if (result is not null) | ||
yield return result; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Net.Http.Json; | ||
using Together.Models.Completions; | ||
|
||
namespace Together.Clients; | ||
|
||
public class CompletionClient(HttpClient httpClient) : BaseClient(httpClient) | ||
{ | ||
|
||
|
||
public async Task<CompletionResponse> CreateAsync(CompletionRequest request, CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<CompletionRequest, CompletionResponse>("/completions", request, cancellationToken); | ||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Together.Models.Embeddings; | ||
|
||
namespace Together.Clients; | ||
|
||
public class EmbeddingClient(HttpClient httpClient) : BaseClient(httpClient) | ||
{ | ||
|
||
|
||
public async Task<EmbeddingResponse> CreateAsync(EmbeddingRequest request, CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<EmbeddingRequest, EmbeddingResponse>("/embeddings", request, cancellationToken); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
using System.Net.Http.Headers; | ||
using Together.Models.Files; | ||
|
||
namespace Together.Clients; | ||
|
||
public class FileClient(HttpClient httpClient) : BaseClient(httpClient) | ||
{ | ||
public async Task<FileResponse> UploadAsync( | ||
string filePath, | ||
FilePurpose? purpose = null, | ||
bool checkFile = true, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
purpose ??= FilePurpose.FineTune; | ||
|
||
if (checkFile && !File.Exists(filePath)) | ||
{ | ||
throw new FileNotFoundException("File not found", filePath); | ||
} | ||
|
||
using var form = new MultipartFormDataContent(); | ||
using var fileStream = File.OpenRead(filePath); | ||
using var content = new StreamContent(fileStream); | ||
|
||
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); | ||
form.Add(content, "file", Path.GetFileName(filePath)); | ||
form.Add(new StringContent(purpose.ToString().ToLowerInvariant()), "purpose"); | ||
|
||
return await SendRequestAsync<FileResponse>("/files", HttpMethod.Post, form, cancellationToken); | ||
} | ||
|
||
public async Task<FileList> ListAsync(CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<FileList>("/files", HttpMethod.Get, null, cancellationToken); | ||
} | ||
|
||
public async Task<FileResponse> RetrieveAsync(string fileId, CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<FileResponse>($"/files/{fileId}", HttpMethod.Get, null, cancellationToken); | ||
} | ||
|
||
public async Task<FileObject> RetrieveContentAsync(string fileId, string? outputPath = null, CancellationToken cancellationToken = default) | ||
{ | ||
var fileName = outputPath ?? NormalizeKey($"{fileId}.jsonl"); | ||
var response = await HttpClient.GetAsync($"/files/{fileId}/content", cancellationToken); | ||
response.EnsureSuccessStatusCode(); | ||
|
||
await using var fs = File.Create(fileName); | ||
await response.Content.CopyToAsync(fs, cancellationToken); | ||
|
||
var fileInfo = new FileInfo(fileName); | ||
return new FileObject | ||
{ | ||
Object = "local", | ||
Id = fileId, | ||
Filename = fileName, | ||
Size = (int)fileInfo.Length | ||
}; | ||
} | ||
|
||
public async Task<FileDeleteResponse> DeleteAsync(string fileId, CancellationToken cancellationToken = default) | ||
{ | ||
return await SendRequestAsync<FileDeleteResponse>($"/files/{fileId}", HttpMethod.Delete, null, cancellationToken); | ||
} | ||
|
||
private static string NormalizeKey(string key) => string.Join("_", key.Split(Path.GetInvalidFileNameChars())); | ||
} |
Oops, something went wrong.