Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
93b8cefad7 | |||
2fd98b700d | |||
a714da0ca7 | |||
51d188f2ed | |||
40efd04bf0 | |||
7536bbd31d | |||
c87330a032 | |||
1ed2b8d731 | |||
0ea582f464 | |||
65553534d1 | |||
cadbf225a1 |
16 changed files with 163 additions and 58 deletions
28
Dockerfile
Normal file
28
Dockerfile
Normal file
|
@ -0,0 +1,28 @@
|
|||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY *.sln .
|
||||
COPY src/Nyanlabs.Umogen.Core/*.csproj src/Nyanlabs.Umogen.Core/
|
||||
COPY src/Nyanlabs.Umogen.Server/*.csproj src/Nyanlabs.Umogen.Server/
|
||||
|
||||
COPY test/Nyanlabs.Umogen.WebTests/*.csproj test/Nyanlabs.Umogen.WebTests/
|
||||
COPY test/Nyanlabs.Umogen.CoreTests/*.csproj test/Nyanlabs.Umogen.CoreTests/
|
||||
|
||||
RUN dotnet restore
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN dotnet publish -c Release -o /build
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
|
||||
RUN apt update -y
|
||||
RUN apt install -y libreoffice-writer-nogui
|
||||
|
||||
COPY --from=build /build /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT [ "dotnet", "Nyanlabs.Umogen.Server.dll" ]
|
BIN
out.pdf
BIN
out.pdf
Binary file not shown.
|
@ -2,7 +2,7 @@ namespace Nyanlabs.Umogen.Core.Models;
|
|||
|
||||
public record ApiRequest
|
||||
{
|
||||
public string Model { get; set; } = "gpt-3.5-turbo";
|
||||
public string Model { get; set; } = "gpt-4";
|
||||
public float Temperature { get; set; } = 0.7f;
|
||||
public ICollection<GptMessage> Messages { get; set; } = new List<GptMessage>();
|
||||
public bool Stream { get; set; }
|
||||
|
|
|
@ -16,7 +16,7 @@ public record Person(string Name, string Surname, string IdC, string Pesel, Date
|
|||
public DateTime? DoB { get; set; } = DoB;
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<LegalEntity> Companies { get; set; }
|
||||
public virtual ICollection<LegalEntity> Companies { get; set; } = default!;
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Nyanlabs.Umogen.Core.Models;
|
|||
public class UmoAnalModel
|
||||
{
|
||||
[JsonPropertyName("c_type")]
|
||||
public string ContractType { get; set; }
|
||||
public string ContractType { get; set; } = default!;
|
||||
[JsonPropertyName("j_pos")]
|
||||
public string JobPosition { get; set; }
|
||||
public string JobPosition { get; set; } = default!;
|
||||
[JsonPropertyName("k_lit")]
|
||||
public string ValueLiteral { get; set; }
|
||||
public string ValueLiteral { get; set; } = default!;
|
||||
[JsonPropertyName("conds")]
|
||||
public ICollection<string> Conditions { get; set; }
|
||||
public ICollection<string> Conditions { get; set; } = default!;
|
||||
|
||||
public UmoDoctype Doctype => UmoDoctypeBindings.GetFromName(ContractType).Value;
|
||||
public UmoDoctype Doctype => UmoDoctypeBindings.GetFromName(ContractType)!.Value;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ public class UmoDocumentResult(UmoDoctype? type, Person employee, IEntity employ
|
|||
.Replace(ENACT_DATE, DateTime.Now.ToString("dd.MM.yyyy"))
|
||||
.Replace(ISSUE_DATE, DateTime.Now.ToString("dd.MM.yyyy"))
|
||||
.Replace(PAYMENT_LIT, Anal.ValueLiteral)
|
||||
.Replace(PAYMENT, Payment.Value.ToString())
|
||||
.Replace(PAYMENT, Payment!.Value.ToString())
|
||||
.Replace(WORK_TYPE, Anal.JobPosition)
|
||||
.Replace(DYNAMIC_DATA, string.Join('\n', Anal.Conditions.Select(a => $"- {a}")));
|
||||
.Replace(DYNAMIC_DATA, string.Join(", ", Anal.Conditions.Select(x => x.Trim('-').Trim(' '))));
|
||||
string tmp = Path.GetTempFileName();
|
||||
await File.WriteAllTextAsync(tmp, xml);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ public class UmoEngine : IDisposable
|
|||
{
|
||||
if (isFilePath)
|
||||
{
|
||||
apiKey ??= Umogen.DEFAULT_API_KEY_FILE;
|
||||
apiKey ??= Environment.GetEnvironmentVariable("UMO_KEY_FILE") ?? Umogen.DEFAULT_API_KEY_FILE;
|
||||
if (!File.Exists(apiKey))
|
||||
{
|
||||
throw new ArgumentException($"No such file: {apiKey}");
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Nyanlabs.Umogen.Core;
|
|||
public class Umogen
|
||||
{
|
||||
public const string DEFAULT_API_KEY_FILE = "umogenkey.secret";
|
||||
public const string PROMPT = "You analyze employment prompt requests and return document type (one of these 'Umowa o Pracę', 'Umowa Zlecenie', 'Umowa o Dzieło') and elaborate description of job details as a list separated by hyphens and newlines. Also give a very generalized job position. You write them in format: '{ \"c_type\": \"<contract type>\", \"j_pos\": \"<rodzaj zawodu>\", \"k_lit\": \"<kwota słownie>\", \"conds\": [ <warunki zatrudnienia> ]'";
|
||||
public const string PROMPT = "You analyze employment prompt requests and return document type (one of these 'Umowa o Pracę', 'Umowa Zlecenie', 'Umowa o Dzieło') and elaborate description of job details as a list separated by hyphens and newlines. Also give a very generalized job position. You write them in format: '{ \"c_type\": \"<contract type>\", \"j_pos\": \"<rodzaj zawodu>\", \"k_lit\": \"<kwota słownie>\", \"conds\": [ <warunki zatrudnienia> ]'. Nie opisuj wynagrodzenia w '<warunki zatrudnienia>'. Add any clauses (anti-competitive, NDA, etc) to the bottom if requested.";
|
||||
public static readonly JsonSerializerOptions JSON_OPTS = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
|
|
|
@ -11,7 +11,8 @@ public class DataContext : DbContext
|
|||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder o)
|
||||
{
|
||||
o.UseSqlite("Data Source=data.db;");
|
||||
|
||||
o.UseSqlite($"Data Source={Environment.GetEnvironmentVariable("UMO_DATA") ?? "data.db"};");
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder m)
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
<div class="row justify-content-center align-items-center g-2">
|
||||
<div class="col mb-3">
|
||||
<label for="employer" class="form-label">Pracodawca (PESEL lub NIP)</label>
|
||||
<input type="text" class="form-control" id="employer" @onchange="ChgEmployer" value="@_employerId">
|
||||
<Autocomplete Value="@_employerId" AcceptedValues="GetEmployers()" Change="ChgEmployer" />
|
||||
<span class="validation-message">@(employer == null ? "" : $"{employer.GetName()}")</span>
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="employee" class="form-label">Pracownik (PESEL)</label>
|
||||
<input type="text" class="form-control" id="employee" @onchange="ChgEmployee" value="@_employeeId">
|
||||
<Autocomplete Value="@_employeeId" AcceptedValues="GetEmployees()" Change="ChgEmployee" />
|
||||
<span class="validation-message">@(employee == null ? "" : $"{employee.Name} {employee.Surname}")</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,7 +59,8 @@
|
|||
{
|
||||
_employerId = (string)e.Value!;
|
||||
employer = await db.Persons.AsNoTracking().SingleOrDefaultAsync(s => s.Pesel == _employerId) as IEntity ?? await
|
||||
db.Companies.AsNoTracking().SingleOrDefaultAsync(s => s.Nip == _employerId);
|
||||
db.Companies.AsNoTracking().Include(i => i.Representative).SingleOrDefaultAsync(s => s.Nip == _employerId);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task ChgEmployee(ChangeEventArgs e)
|
||||
|
@ -70,7 +71,7 @@
|
|||
|
||||
private string _validityText = "";
|
||||
|
||||
private async Task ChgValidity(ChangeEventArgs e)
|
||||
private void ChgValidity(ChangeEventArgs e)
|
||||
{
|
||||
string val = (string)e.Value!;
|
||||
_validityText = val;
|
||||
|
@ -96,6 +97,19 @@
|
|||
_validity = new ValidTime(now, span);
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> GetEmployers()
|
||||
{
|
||||
var pers = db.Persons.AsNoTracking().AsEnumerable().Select(p => ($"{p.Name} {p.Surname}", p.Pesel));
|
||||
var comp = db.Companies.AsNoTracking().AsEnumerable().Select(c => (c.Name, c.Nip!));
|
||||
|
||||
return pers.Union(comp);
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> GetEmployees()
|
||||
{
|
||||
return db.Persons.AsNoTracking().AsEnumerable().Select(p => ($"{p.Name} {p.Surname}", p.Pesel));
|
||||
}
|
||||
|
||||
private async Task Process()
|
||||
{
|
||||
disB = true;
|
||||
|
@ -103,7 +117,7 @@
|
|||
await Task.Yield();
|
||||
|
||||
output = string.Empty;
|
||||
using UmoEngine eng = new("/home/nya/Dev/csharp/umogen/umogenkey.secret");
|
||||
using UmoEngine eng = new();
|
||||
UmoProcess proc = new(eng);
|
||||
Thread.Yield();
|
||||
|
||||
|
@ -115,11 +129,11 @@
|
|||
}
|
||||
|
||||
var anal = System.Text.Json.JsonSerializer.Deserialize<UmoAnalModel>(output, Umogen.JSON_OPTS);
|
||||
UmoDocumentResult res = new(null, employee, employer, _validity, _payment,
|
||||
anal);
|
||||
UmoDocumentResult res = new(null, employee!, employer!, _validity, _payment,
|
||||
anal!);
|
||||
|
||||
var bytes = await res.ProcessPdf(Path.Combine("/home/nya/Dev/csharp/umogen/",
|
||||
$"templates/{anal.Doctype.TemplateDoc()}"));
|
||||
var bytes = await res.ProcessPdf(Path.Combine(Environment.GetEnvironmentVariable("UMO_TEMPLATES")!,
|
||||
anal!.Doctype.TemplateDoc()));
|
||||
await js.InvokeVoidAsync("blobby", bytes);
|
||||
|
||||
disB = false;
|
||||
|
|
|
@ -16,22 +16,13 @@
|
|||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7029;http://localhost:5214",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
51
src/Nyanlabs.Umogen.Server/Shared/Autocomplete.razor
Normal file
51
src/Nyanlabs.Umogen.Server/Shared/Autocomplete.razor
Normal file
|
@ -0,0 +1,51 @@
|
|||
<div class="relat" @onfocusin="(() => focus = true)">
|
||||
<input type="text" class="form-control" @oninput="Prechange" value="@Value">
|
||||
@if (focus)
|
||||
{
|
||||
<div class="autocomplete-items">
|
||||
@foreach (var tup in Filter())
|
||||
{
|
||||
<div @onclick="async (e) => await Select(tup.Item2)">
|
||||
@tup.Item1 (@tup.Item2)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@code {
|
||||
private bool focus = false;
|
||||
[Parameter]
|
||||
public IEnumerable<(string, string)> AcceptedValues { get; set; } = [];
|
||||
|
||||
|
||||
[Parameter]
|
||||
public string Value { get; set; } = "";
|
||||
|
||||
private async Task Prechange(ChangeEventArgs e)
|
||||
{
|
||||
Value = (string)e.Value!;
|
||||
StateHasChanged();
|
||||
await Change.InvokeAsync(e);
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<ChangeEventArgs> Change { get; set; }
|
||||
|
||||
private async Task Select(string s)
|
||||
{
|
||||
focus = false;
|
||||
Value = s;
|
||||
|
||||
await Prechange(new()
|
||||
{
|
||||
Value = s
|
||||
});
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> Filter()
|
||||
{
|
||||
return AcceptedValues.Where(v => v.Item1.StartsWith(Value, StringComparison.OrdinalIgnoreCase) ||
|
||||
v.Item2.StartsWith(Value, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
32
src/Nyanlabs.Umogen.Server/Shared/Autocomplete.razor.css
Normal file
32
src/Nyanlabs.Umogen.Server/Shared/Autocomplete.razor.css
Normal file
|
@ -0,0 +1,32 @@
|
|||
.relat {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.autocomplete {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.autocomplete-items {
|
||||
position: absolute;
|
||||
border: 1px solid #d4d4d4;
|
||||
border-bottom: none;
|
||||
border-top: none;
|
||||
z-index: 99;
|
||||
/*position the autocomplete items to be the same width as the container:*/
|
||||
top: 3rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.autocomplete-items div {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
}
|
||||
|
||||
.autocomplete-items div:hover {
|
||||
background-color: rgb(156, 237, 248);
|
||||
}
|
|
@ -5,5 +5,13 @@
|
|||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://+:8080"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
|
|
@ -8,24 +8,4 @@ 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("I would like to employ Jan Kowalski ID NO CBS3727348 for part time job as a shopkeeper and pay 1400zł.");
|
||||
|
||||
// await foreach (var str in enu)
|
||||
// {
|
||||
// Console.Write(str);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class PdfTest
|
|||
}
|
||||
|
||||
var anal = JsonSerializer.Deserialize<UmoAnalModel>(sb.ToString(), Core.Umogen.JSON_OPTS);
|
||||
UmoDocumentResult r = new(null, ModelEmployer, ModelEmployee, ValidTime.Invalid, 2137, anal);
|
||||
UmoDocumentResult r = new(null, ModelEmployer, ModelEmployee, ValidTime.Invalid, 2137, anal!);
|
||||
|
||||
// When
|
||||
byte[] b = await r.ProcessPdf(Path.Combine(root, $"templates/{r.DocType.TemplateDoc()}"));
|
||||
|
|
Loading…
Reference in a new issue