Compare commits
No commits in common. "3135428fb2a2a9a43ad2046e680ada06b03cec15" and "c3f3cc6acbeccae94771de908a5fd910944a15e1" have entirely different histories.
3135428fb2
...
c3f3cc6acb
17 changed files with 9 additions and 268 deletions
24
LICENSE
24
LICENSE
|
@ -1,24 +0,0 @@
|
||||||
Copyright (c) 2023 femsci
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
1. Any person intending to use the Software is required to pet a cat at least
|
|
||||||
twice within the month preceding the use of the Software.
|
|
||||||
|
|
||||||
2. Any person intending to use the Software must endear feline species with extraordinary affection.
|
|
||||||
|
|
||||||
3. The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public class ApiChoice
|
|
||||||
{
|
|
||||||
public string FinishReason { get; set; } = default!;
|
|
||||||
public int Index { get; set; }
|
|
||||||
public GptMessage? Message { get; set; }
|
|
||||||
public GptMessage? Delta { get; set; }
|
|
||||||
|
|
||||||
}
|
|
|
@ -4,7 +4,4 @@ public record ApiRequest
|
||||||
{
|
{
|
||||||
public string Model { get; set; } = "gpt-3.5-turbo";
|
public string Model { get; set; } = "gpt-3.5-turbo";
|
||||||
public float Temperature { get; set; } = 0.7f;
|
public float Temperature { get; set; } = 0.7f;
|
||||||
public ICollection<GptMessage> Messages { get; set; } = new List<GptMessage>();
|
|
||||||
public bool Stream { get; set; }
|
|
||||||
//public ApiResponseFormat ResponseFormat { get; set; } = new();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public class ApiResponse
|
|
||||||
{
|
|
||||||
public string Id { get; set; } = default!;
|
|
||||||
public string Model { get; set; } = default!;
|
|
||||||
public string Object { get; set; } = default!;
|
|
||||||
public UsageStats Usage { get; set; } = default!;
|
|
||||||
public ICollection<ApiChoice> Choices { get; set; } = new List<ApiChoice>();
|
|
||||||
public long Created { get; set; }
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public class ApiResponseFormat
|
|
||||||
{
|
|
||||||
public string Type { get; set; } = "json_object";
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public record GptMessage(string Role, string Content)
|
|
||||||
{
|
|
||||||
public string Role { get; } = Role;
|
|
||||||
public string Content { get; } = Content;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public interface IEntity : INLSerializable
|
|
||||||
{
|
|
||||||
public string GetName();
|
|
||||||
public string? IdCode();
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public class LegalEntity(string Name, string? Nip = null, string? Headquarters = null, Person? Representative = null) : IEntity, INLSerializable
|
|
||||||
{
|
|
||||||
public string Name { get; set; } = Name;
|
|
||||||
public string? Nip { get; set; } = Nip;
|
|
||||||
public string? Headquarters { get; set; } = Headquarters;
|
|
||||||
public Person? Representative { get; set; } = Representative;
|
|
||||||
|
|
||||||
public string GetName()
|
|
||||||
{
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? IdCode()
|
|
||||||
{
|
|
||||||
return Nip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string NLSerialize()
|
|
||||||
{
|
|
||||||
return $"{Name}; with NIP {Nip ?? "unknown"}{(Headquarters != null ? $"; located in {Headquarters}" : "")}{(Representative != null ? $"; represented by {Representative.GetName()}" : "")}";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
namespace Nyanlabs.Umogen.Core.Models;
|
||||||
|
|
||||||
public record Person(string Name, string Surname, string? Id = null, string? Pesel = null, DateTime? DoB = null) : IEntity, INLSerializable
|
public record Person(string Name, string Surname, string? Id = null, string? Pesel = null, DateTime? DoB = null) : INLSerializable
|
||||||
{
|
{
|
||||||
public string Name { get; set; } = Name;
|
public string Name { get; set; } = Name;
|
||||||
public string Surname { get; set; } = Surname;
|
public string Surname { get; set; } = Surname;
|
||||||
|
@ -8,16 +8,6 @@ public record Person(string Name, string Surname, string? Id = null, string? Pes
|
||||||
public string? Pesel { get; set; } = Pesel;
|
public string? Pesel { get; set; } = Pesel;
|
||||||
public DateTime? DoB { get; set; } = DoB;
|
public DateTime? DoB { get; set; } = DoB;
|
||||||
|
|
||||||
public string GetName()
|
|
||||||
{
|
|
||||||
return $"{Name} {Surname}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? IdCode()
|
|
||||||
{
|
|
||||||
return IDCode!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string NLSerialize()
|
public string NLSerialize()
|
||||||
{
|
{
|
||||||
return $"{Name} {Surname}; {(Pesel != null ? $"PESEL {Pesel}" : "unknown PESEL")}; {(IDCode != null ? $"ID series {IDCode}" : "unknown ID series")}; {(DoB != null ? $"born {DoB.Value:dd MMM yyyy}" : "unknown date of birth")}";
|
return $"{Name} {Surname}; {(Pesel != null ? $"PESEL {Pesel}" : "unknown PESEL")}; {(IDCode != null ? $"ID series {IDCode}" : "unknown ID series")}; {(DoB != null ? $"born {DoB.Value:dd MMM yyyy}" : "unknown date of birth")}";
|
||||||
|
|
|
@ -30,7 +30,7 @@ public static class UmoDoctypeBindings
|
||||||
|
|
||||||
public class UmoDocument : INLSerializable
|
public class UmoDocument : INLSerializable
|
||||||
{
|
{
|
||||||
public UmoDocument(UmoDoctype type, IEntity employer, Person employee, ValidTime? validTime = null)
|
public UmoDocument(UmoDoctype type, Person employer, Person employee, ValidTime? validTime = null)
|
||||||
{
|
{
|
||||||
Doctype = type;
|
Doctype = type;
|
||||||
Employer = employer;
|
Employer = employer;
|
||||||
|
@ -39,12 +39,12 @@ public class UmoDocument : INLSerializable
|
||||||
}
|
}
|
||||||
|
|
||||||
public UmoDoctype Doctype { get; set; }
|
public UmoDoctype Doctype { get; set; }
|
||||||
public IEntity Employer { get; set; }
|
public Person Employer { get; set; }
|
||||||
public Person Employee { get; set; }
|
public Person Employee { get; set; }
|
||||||
//Null is 'unspecified time'
|
//Null is 'unspecified time'
|
||||||
public ValidTime? ValidTime { get; set; }
|
public ValidTime? ValidTime { get; set; }
|
||||||
public string NLSerialize()
|
public string NLSerialize()
|
||||||
{
|
{
|
||||||
return $"{Doctype.Name().Item2} for {Employee.NLSerialize()} working for {Employer.NLSerialize()}; valid {ValidTime?.NLSerialize() ?? "for unspecified time"}.";
|
return $"{Doctype.Name().Item1} for {Employee.NLSerialize()} working for {Employer.NLSerialize()}; valid {ValidTime?.NLSerialize() ?? "for unspecified time"}.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
public class UsageStats
|
|
||||||
{
|
|
||||||
[JsonPropertyName("completion_tokens")]
|
|
||||||
public int CompletionTokens { get; set; }
|
|
||||||
[JsonPropertyName("prompt_tokens")]
|
|
||||||
public int PromptTokens { get; set; }
|
|
||||||
[JsonPropertyName("total_tokens")]
|
|
||||||
public int TotalTokens { get; set; }
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nyanlabs.Umogen.Core;
|
|
||||||
|
|
||||||
public class SseConsumer<TEvent> : IDisposable, IAsyncDisposable
|
|
||||||
{
|
|
||||||
public SseConsumer(Stream stream)
|
|
||||||
{
|
|
||||||
_stream = stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Stream _stream;
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<TEvent> ReadEvents()
|
|
||||||
{
|
|
||||||
var reader = new StreamReader(_stream);
|
|
||||||
|
|
||||||
while (!reader.EndOfStream)
|
|
||||||
{
|
|
||||||
string line = (await reader.ReadLineAsync())!;
|
|
||||||
//Second \n
|
|
||||||
await reader.ReadLineAsync();
|
|
||||||
|
|
||||||
//Remove 'data: '
|
|
||||||
line = line[6..].Trim();
|
|
||||||
|
|
||||||
yield return JsonSerializer.Deserialize<TEvent>(line, Umogen.JSON_OPTS) ?? throw new DataException("Invalid data...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_stream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
return _stream.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,7 +38,7 @@ public class UmoEngine : IDisposable
|
||||||
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
|
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal readonly HttpClient _http;
|
private readonly HttpClient _http;
|
||||||
|
|
||||||
public async Task<bool> ValidateKey()
|
public async Task<bool> ValidateKey()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
using System.Data;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
using Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
namespace Nyanlabs.Umogen.Core;
|
namespace Nyanlabs.Umogen.Core;
|
||||||
|
|
||||||
public class UmoProcess
|
public class UmoProcess
|
||||||
|
@ -15,40 +9,8 @@ public class UmoProcess
|
||||||
|
|
||||||
private readonly UmoEngine _eng;
|
private readonly UmoEngine _eng;
|
||||||
|
|
||||||
public async IAsyncEnumerable<string> Ask(string content)
|
public async Task Ask()
|
||||||
{
|
{
|
||||||
ApiRequest req = new()
|
|
||||||
{
|
|
||||||
Messages = new List<GptMessage>()
|
|
||||||
{
|
|
||||||
new("system", Umogen.PROMPT),
|
|
||||||
new("user", content)
|
|
||||||
},
|
|
||||||
Stream = true
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpRequestMessage msg = new(HttpMethod.Post, "chat/completions");
|
|
||||||
msg.Content = new StringContent(JsonSerializer.Serialize(req, options: Umogen.JSON_OPTS), Encoding.UTF8, "application/json");
|
|
||||||
var resp = await _eng._http.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead);
|
|
||||||
|
|
||||||
if (!resp.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
Console.WriteLine(await resp.Content.ReadAsStringAsync());
|
|
||||||
throw new DataException($"Cannot process request: {resp.StatusCode}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiStream = await resp.Content.ReadAsStreamAsync();
|
|
||||||
|
|
||||||
using var sseConsumer = new SseConsumer<ApiResponse>(apiStream);
|
|
||||||
await foreach (var chunk in sseConsumer.ReadEvents())
|
|
||||||
{
|
|
||||||
ApiChoice choice = chunk.Choices.First();
|
|
||||||
if (choice.FinishReason == "stop")
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return choice.Delta?.Content ?? throw new DataException("Message delta is null");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace Nyanlabs.Umogen.Core;
|
namespace Nyanlabs.Umogen.Core;
|
||||||
|
|
||||||
public class Umogen
|
public class Umogen
|
||||||
{
|
{
|
||||||
public const string DEFAULT_API_KEY_FILE = "umogenkey.secret";
|
public const string DEFAULT_API_KEY_FILE = "umogenkey.secret";
|
||||||
public const string PROMPT = "You write Polish legal contracts in Polish language in markdown format. Fill unknown fields with signature placeholder (underscore) with enough space to sign it with pen.";
|
public const string PROMPT = "You write Polish legal document in markdown format.";
|
||||||
public static readonly JsonSerializerOptions JSON_OPTS = new(JsonSerializerDefaults.Web)
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class NLSerializationTests
|
||||||
var query = doc.NLSerialize();
|
var query = doc.NLSerialize();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.Equal($"Umowa o Pracę for {ModelEmployee.NLSerialize()} working for {ModelEmployer.NLSerialize()}; valid for unspecified time.", query);
|
Assert.Equal($"Contract of Employment for {ModelEmployee.NLSerialize()} working for {ModelEmployer.NLSerialize()}; valid for unspecified time.", query);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -31,7 +31,7 @@ public class NLSerializationTests
|
||||||
var query = doc.NLSerialize();
|
var query = doc.NLSerialize();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.Equal($"Umowa o Pracę for {ModelEmployee.NLSerialize()} working for {ModelEmployer.NLSerialize()}; valid from 17 Nov 2023 until 18 Nov 2023.", query);
|
Assert.Equal($"Contract of Employment for {ModelEmployee.NLSerialize()} working for {ModelEmployer.NLSerialize()}; valid from 17 Nov 2023 until 18 Nov 2023.", query);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -64,19 +64,4 @@ public class NLSerializationTests
|
||||||
// Then
|
// Then
|
||||||
Assert.Equal("Kotek Miauczyński; unknown PESEL; unknown ID series; unknown date of birth", query);
|
Assert.Equal("Kotek Miauczyński; unknown PESEL; unknown ID series; unknown date of birth", query);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LegalEntity ModelCompany => new("Nyanbyte P.S.A.", "1313131313", "Miaumiaśna 13, Miauczki", ModelEmployer);
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CompanySerializationTest()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
LegalEntity company = ModelCompany;
|
|
||||||
|
|
||||||
// When
|
|
||||||
var query = company.NLSerialize();
|
|
||||||
|
|
||||||
// Then
|
|
||||||
Assert.Equal("Nyanbyte P.S.A.; with NIP 1313131313; located in Miaumiaśna 13, Miauczki; represented by Kotek Miauczyński", query);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Nyanlabs.Umogen.Core;
|
|
||||||
using Nyanlabs.Umogen.Core.Models;
|
|
||||||
|
|
||||||
namespace Nyanlabs.Umogen.WebTests;
|
|
||||||
|
|
||||||
public class GenerationTests
|
|
||||||
{
|
|
||||||
private Person ModelEmployer => new("Kotek", "Miauczyński", "CBS4327563", "04281308999", new DateTime(2004, 08, 13));
|
|
||||||
|
|
||||||
private Person ModelEmployee => new("Miau", "Kotczyński", "CBS69696969", "76011694336", new DateTime(1976, 1, 16));
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Meow4Me()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
var rootDir = Environment.CurrentDirectory.Replace("test/Nyanlabs.Umogen.WebTests/bin/Debug/net8.0", "");
|
|
||||||
|
|
||||||
UmoEngine eng = new(Path.Combine(rootDir, Core.Umogen.DEFAULT_API_KEY_FILE));
|
|
||||||
|
|
||||||
// When
|
|
||||||
UmoDocument doc = new(UmoDoctype.CONTR_EMPLOYMENT, ModelEmployer, ModelEmployee);
|
|
||||||
|
|
||||||
UmoProcess proc = new(eng);
|
|
||||||
var enu = proc.Ask(doc.NLSerialize());
|
|
||||||
|
|
||||||
await foreach (var str in enu)
|
|
||||||
{
|
|
||||||
Console.Write(str);
|
|
||||||
File.AppendAllText("/tmp/doc.md", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("~");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue