Skip to content

Commit

Permalink
+ GetWordMetadata json input
Browse files Browse the repository at this point in the history
  • Loading branch information
NicklausBrain committed Dec 7, 2024
1 parent 4187761 commit 2db9159
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 108 deletions.
83 changes: 0 additions & 83 deletions My1kWordsEe/Services/Ai/OpenAiClient.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;

using CSharpFunctionalExtensions;

using My1kWordsEe.Models;

using OpenAI.Chat;

namespace My1kWordsEe.Services
Expand Down Expand Up @@ -111,85 +108,5 @@ public static async Task<Result<string>> GetDallEPrompt(this OpenAiClient openAi
MaxTokens = 400,
});
}

public static async Task<Result<SampleWord>> GetWordMetadata(
this OpenAiClient openAiClient,
string eeWord,
string? comment = null)
{
const string prompt =
"Teie sisend on eestikeelne sõna (ja selle sõna valikuline selgitus).\n" +
"Kui antud sõna ei ole eestikeelne, tagasta 404\n" +
"Teie väljund on sõna metaandmed JSON-is vastavalt antud lepingule:\n" +
"```\n{\n" +
"\"ee_word\": \"<antud sõna>\",\n" +
"\"en_word\": \"<english translation>\",\n" +
"\"en_words\": [<array of alternative english translations if applicable>],\n" +
"\"en_explanation\": \"<explanation of the word meaning in english>\",\n" +
"\"ee_explanation\": \"<sõna tähenduse seletus eesti keeles>\"\n" +
"}\n```\n";

var response = await openAiClient.CompleteAsync(
prompt,
string.IsNullOrEmpty(comment)
? eeWord
: $"{eeWord} ({comment})",
new ChatCompletionOptions
{
ResponseFormat = ChatResponseFormat.JsonObject,
Temperature = 0.333f
});

if (response.IsFailure)
{
return Result.Failure<SampleWord>(response.Error);
}

// could be ommited if we integrate an EE dictionary within the app
if (response.Value.Contains("404"))
{
return Result.Failure<SampleWord>("Not an Estonian word");
}

openAiClient.ParseJsonResponse<WordMetadata>(response).Deconstruct(
out bool _,
out bool isParsingError,
out WordMetadata wordMetadata,
out string parsingError);

if (isParsingError)
{
return Result.Failure<SampleWord>(parsingError);
}

return Result.Success(new SampleWord
{
EeWord = wordMetadata.EeWord,
EnWord = wordMetadata.EnWord,
EnWords = wordMetadata.EnWords,
EnExplanation = wordMetadata.EnExplanation,
EeExplanation = wordMetadata.EeExplanation,
});
}

private class WordMetadata
{
[JsonPropertyName("ee_word")]
public required string EeWord { get; set; }

[JsonPropertyName("en_word")]
public required string EnWord { get; set; }

[JsonPropertyName("en_explanation")]
public required string EnExplanation { get; set; }

[JsonPropertyName("ee_explanation")]
public required string EeExplanation { get; set; }

[JsonPropertyName("en_words")]
public required string[] EnWords { get; set; } = Array.Empty<string>();
}
}


}
22 changes: 11 additions & 11 deletions My1kWordsEe/Services/Cqs/AddSampleSentenceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ public class AddSampleSentenceCommand
{
public const int MaxSamples = 6;

private readonly AzureStorageClient azureBlobService;
private readonly OpenAiClient openAiService;
private readonly AzureStorageClient azureBlobClient;
private readonly OpenAiClient openAiClient;
private readonly AddAudioCommand addAudioCommand;
private readonly StabilityAiClient stabilityAiService;
private readonly StabilityAiClient stabilityAiClient;

public AddSampleSentenceCommand(
AzureStorageClient azureBlobService,
OpenAiClient openAiService,
AddAudioCommand createAudioCommand,
StabilityAiClient stabilityAiService)
{
this.azureBlobService = azureBlobService;
this.openAiService = openAiService;
this.azureBlobClient = azureBlobService;
this.openAiClient = openAiService;
this.addAudioCommand = createAudioCommand;
this.stabilityAiService = stabilityAiService;
this.stabilityAiClient = stabilityAiService;
}

public async Task<Result<SampleWord>> Invoke(SampleWord word)
Expand Down Expand Up @@ -69,15 +69,15 @@ public async Task<Result<SampleWord>> Invoke(SampleWord word)
}).ToArray()
};

return (await this.azureBlobService
return (await this.azureBlobClient
.SaveWordData(updatedWordData))
.Bind(r => Result.Success(updatedWordData));
}

private Task<Result<Uri>> GenerateImage(Sentence sentence) =>
this.openAiService.GetDallEPrompt(sentence.En).Bind(
this.stabilityAiService.GenerateImage).Bind(
this.azureBlobService.SaveImage);
this.openAiClient.GetDallEPrompt(sentence.En).Bind(
this.stabilityAiClient.GenerateImage).Bind(
this.azureBlobClient.SaveImage);

private Task<Result<Uri>> GenerateSpeech(Sentence sentence) =>
this.addAudioCommand.Invoke(sentence.Ee);
Expand Down Expand Up @@ -111,7 +111,7 @@ private async Task<Result<Sentence>> GetSampleSentence(SampleWord word)
word.EnExplanation
});

var result = await this.openAiService.CompleteJsonAsync<Sentence>(prompt, input, temperature: 0.7f);
var result = await this.openAiClient.CompleteJsonAsync<Sentence>(prompt, input, temperature: 0.7f);

return result;
}
Expand Down
107 changes: 100 additions & 7 deletions My1kWordsEe/Services/Cqs/AddSampleWordCommand.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
using CSharpFunctionalExtensions;
using System.Text.Json;
using System.Text.Json.Serialization;

using CSharpFunctionalExtensions;

using My1kWordsEe.Models;
using My1kWordsEe.Services.Db;

using OpenAI.Chat;

namespace My1kWordsEe.Services.Cqs
{
public class AddSampleWordCommand
{
private readonly OpenAiClient openAiService;
private readonly AzureStorageClient azureBlobService;
private readonly OpenAiClient openAiClient;
private readonly AzureStorageClient azureBlobClient;
private readonly AddAudioCommand addAudioCommand;

public AddSampleWordCommand(
OpenAiClient openAiService,
AzureStorageClient azureBlobService,
AddAudioCommand createAudioCommand)
{
this.azureBlobService = azureBlobService;
this.openAiService = openAiService;
this.azureBlobClient = azureBlobService;
this.openAiClient = openAiService;
this.addAudioCommand = createAudioCommand;
}

Expand All @@ -28,7 +33,7 @@ public async Task<Result<SampleWord>> Invoke(string eeWord, string? comment = nu
return Result.Failure<SampleWord>("Not an Estonian word");
}

(await openAiService.GetWordMetadata(eeWord, comment)).Deconstruct(
(await this.GetWordMetadata(eeWord, comment)).Deconstruct(
out bool _,
out bool isAiFailure,
out SampleWord sampleWord,
Expand All @@ -48,8 +53,96 @@ public async Task<Result<SampleWord>> Invoke(string eeWord, string? comment = nu
? sampleWord with { EeAudioUrl = audioUri }
: sampleWord;

return (await azureBlobService.SaveWordData(sampleWord))
return (await azureBlobClient.SaveWordData(sampleWord))
.Bind(_ => Result.Of(sampleWord));
}

private async Task<Result<SampleWord>> GetWordMetadata(
string eeWord,
string? comment = null)
{
const string prompt =
"Antud eestikeelse sõna kohta tuleb esitada metaandmed\n" +

"Teie sisend on JSON-objekt:" +
"```\n{\n" +
"\"EeWord\": \"<eestikeelne sõna>\", " +
"\"Comment\": \"<eestikeelse sõna valikuline selgitus eesti või inglise keeles>\n" +
"}\n```\n" +

"Kui antud sõna ei ole eestikeelne, tagasta 404\n" +
"Teie väljund on sõna metaandmed JSON-is vastavalt antud lepingule:\n" +
"```\n{\n" +
"\"ee_word\": \"<antud sõna>\",\n" +
"\"en_word\": \"<english translation>\",\n" +
"\"en_words\": [<array of alternative english translations if applicable>],\n" +
"\"en_explanation\": \"<explanation of the word meaning in english>\",\n" +
"\"ee_explanation\": \"<sõna tähenduse seletus eesti keeles>\"\n" +
"}\n```\n";

var input = JsonSerializer.Serialize(new
{
EeWord = eeWord,
Comment = comment
});

var response = await this.openAiClient.CompleteAsync(
prompt,
input,
new ChatCompletionOptions
{
ResponseFormat = ChatResponseFormat.JsonObject,
Temperature = 0.333f
});

if (response.IsFailure)
{
return Result.Failure<SampleWord>(response.Error);
}

// could be ommited if we integrate an EE dictionary within the app
if (response.Value.Contains("404"))
{
return Result.Failure<SampleWord>("Not an Estonian word");
}

openAiClient.ParseJsonResponse<WordMetadata>(response).Deconstruct(
out bool _,
out bool isParsingError,
out WordMetadata wordMetadata,
out string parsingError);

if (isParsingError)
{
return Result.Failure<SampleWord>(parsingError);
}

return Result.Success(new SampleWord
{
EeWord = wordMetadata.EeWord,
EnWord = wordMetadata.EnWord,
EnWords = wordMetadata.EnWords,
EnExplanation = wordMetadata.EnExplanation,
EeExplanation = wordMetadata.EeExplanation,
});
}

private class WordMetadata
{
[JsonPropertyName("ee_word")]
public required string EeWord { get; set; }

[JsonPropertyName("en_word")]
public required string EnWord { get; set; }

[JsonPropertyName("en_explanation")]
public required string EnExplanation { get; set; }

[JsonPropertyName("ee_explanation")]
public required string EeExplanation { get; set; }

[JsonPropertyName("en_words")]
public required string[] EnWords { get; set; } = Array.Empty<string>();
}
}
}
16 changes: 9 additions & 7 deletions My1kWordsEe/Services/Cqs/ValidateSampleWordCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using CSharpFunctionalExtensions;
using System.Text.Json;

using CSharpFunctionalExtensions;

using My1kWordsEe.Models;

Expand Down Expand Up @@ -34,12 +36,12 @@ public async Task<Result<ValidationResult>> Invoke(SampleWord sample)
"\"EeExplanationMessage\": \"<selgitus oma otsuse kohta>\"\n" +
"}\n```\n";

var input =
"{" +
" \"EeWord\": \"" + sample.EeWord + "\"," +
" \"EnWord\": \"" + sample.EnWord + "\"," +
" \"EnExplanation\": \"" + sample.EnExplanation + "\"" +
"}";
var input = JsonSerializer.Serialize(new
{
sample.EeWord,
sample.EnWord,
sample.EnExplanation
});

var result = await this.openAiClient.CompleteJsonAsync<ValidationResult>(prompt, input);

Expand Down

0 comments on commit 2db9159

Please sign in to comment.