From 72570307c49e0a6a571bdf637edd5c26addb1361 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Thu, 12 Dec 2024 21:12:03 +0330 Subject: [PATCH] #454 ai/generate/poem/geo --- RMuseum/Controllers/GanjoorController.cs | 16 ++ RMuseum/RMuseum.xml | 34 ++++ RMuseum/Services/IGanjoorService.cs | 7 + .../GanjoorService-OpenAI-CoupletSummaries.cs | 175 +++++++++++++++++- 4 files changed, 222 insertions(+), 10 deletions(-) diff --git a/RMuseum/Controllers/GanjoorController.cs b/RMuseum/Controllers/GanjoorController.cs index fabfd1b4..3f9dea9d 100644 --- a/RMuseum/Controllers/GanjoorController.cs +++ b/RMuseum/Controllers/GanjoorController.cs @@ -4493,6 +4493,22 @@ namespace RMuseum.Controllers return Ok(); } + /// + /// geo tag poems using AI + /// + /// + /// + /// + [HttpPut("ai/generate/poem/geo")] + [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] + [ProducesResponseType((int)HttpStatusCode.OK)] + [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] + public IActionResult OpenAIStartFillingGeoLocations(int startFrom = 0, int count = 0) + { + _ganjoorService.OpenAIStartFillingGeoLocations(startFrom, count); + return Ok(); + } + diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index 13903b3a..21149af0 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -2305,6 +2305,14 @@ + + + geo tag poems using AI + + + + + readonly mode @@ -4231,6 +4239,18 @@ + + + + + + + + + + + + donation expenditures @@ -17018,6 +17038,13 @@ + + + geo tag poems using AI + + + + translation service implementation @@ -18956,6 +18983,13 @@ + + + geo tag poems using AI + + + + category paper sources diff --git a/RMuseum/Services/IGanjoorService.cs b/RMuseum/Services/IGanjoorService.cs index b01281a6..97ff604a 100644 --- a/RMuseum/Services/IGanjoorService.cs +++ b/RMuseum/Services/IGanjoorService.cs @@ -1545,5 +1545,12 @@ namespace RMuseum.Services /// void OpenAIStartFillingPoemSummaries(int startFrom, int count); + /// + /// geo tag poems using AI + /// + /// + /// + void OpenAIStartFillingGeoLocations(int startFrom, int count); + } } diff --git a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-OpenAI-CoupletSummaries.cs b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-OpenAI-CoupletSummaries.cs index f6ea827d..9da527ff 100644 --- a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-OpenAI-CoupletSummaries.cs +++ b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-OpenAI-CoupletSummaries.cs @@ -47,8 +47,8 @@ namespace RMuseum.Services.Implementation count == 0 ? startFrom == 0 ? await context.GanjoorVerses.AsNoTracking() - .Where(v => - ( + .Where(v => + ( v.VersePosition == VersePosition.Right || v.VersePosition == VersePosition.CenteredVerse1 @@ -98,7 +98,7 @@ namespace RMuseum.Services.Implementation ; await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Verse count = {verses.Count}"); - for ( var i = 0; i < verses.Count; i++ ) + for (var i = 0; i < verses.Count; i++) { var verse = verses[i]; var editableVerse = await context.GanjoorVerses.Where(v => v.Id == verse.Id).SingleAsync(); @@ -117,7 +117,7 @@ namespace RMuseum.Services.Implementation { await jobProgressServiceEF.UpdateJob(job.Id, i, $"{i} از {verses.Count} - {couplet}"); string command = "این بیت را به فارسی روان معنی کن، در متن اشاره نکن که این معنی این بیت است:"; - if(verse.VersePosition == VersePosition.Paragraph) + if (verse.VersePosition == VersePosition.Paragraph) { command = "این پاراگراف را به فارسی روان معنی کن، در متن اشاره نکن که این معنی این پاراگراف است:"; } @@ -137,14 +137,14 @@ namespace RMuseum.Services.Implementation if (completionResult.Successful) { string summary = completionResult.Choices.First().Message.Content; - if(summary.Contains("اکتبر")) + if (summary.Contains("اکتبر")) { summary = ""; } if (!string.IsNullOrEmpty(summary)) { summary = "هوش مصنوعی: " + summary; - + editableVerse.CoupletSummary = summary; context.Update(editableVerse); await context.SaveChangesAsync(); @@ -222,14 +222,14 @@ namespace RMuseum.Services.Implementation for (var i = 0; i < poems.Count; i++) { var poem = poems[i]; - + if (!string.IsNullOrEmpty(poem.PlainText)) { var editablePoem = await context.GanjoorPoems.Where(p => p.Id == poem.Id).SingleAsync(); - if(!string.IsNullOrEmpty(editablePoem.PoemSummary)) + if (!string.IsNullOrEmpty(editablePoem.PoemSummary)) continue; - + await jobProgressServiceEF.UpdateJob(job.Id, i, $"{i} از {poems.Count} - {poem.FullTitle}"); string command = "به فارسی روان خلاصه کن:"; var completionResult = await openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest @@ -255,7 +255,7 @@ namespace RMuseum.Services.Implementation if (!string.IsNullOrEmpty(summary)) { summary = "هوش مصنوعی: " + summary; - + editablePoem.PoemSummary = summary; context.Update(editablePoem); await context.SaveChangesAsync(); @@ -277,5 +277,160 @@ namespace RMuseum.Services.Implementation }); } + + /// + /// geo tag poems using AI + /// + /// + /// + public void OpenAIStartFillingGeoLocations(int startFrom, int count) + { + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC + { + LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); + var job = (await jobProgressServiceEF.NewJob($"OpenAIStartFillingGeoLocations - start: {startFrom} - count: {count}", "Open AI initialization")).Result; + try + { + + var openAiService = new OpenAIService(new OpenAIOptions() + { + ApiKey = Configuration["OpenAIAPIKey"], + BaseDomain = Configuration["OpenAIBaseUrl"] + }); + + await jobProgressServiceEF.UpdateJob(job.Id, 0, "Query data"); + + var poems = + count == 0 ? + startFrom == 0 ? + await context.GanjoorPoems.AsNoTracking() + .Where( + p => string.IsNullOrEmpty(p.PoemSummary) + ) + .ToListAsync() + : + await context.GanjoorPoems.AsNoTracking() + .Where( + p => string.IsNullOrEmpty(p.PoemSummary) + ) + .Skip(startFrom) + .ToListAsync() + : + await context.GanjoorPoems.AsNoTracking() + .Where( + p => string.IsNullOrEmpty(p.PoemSummary) + ) + .Skip(startFrom) + .Take(count) + .ToListAsync(); + await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Poems count = {poems.Count}"); + + for (var i = 0; i < poems.Count; i++) + { + var poem = poems[i]; + + if (true == await context.PoemGeoDateTags.AsNoTracking().Where(p => p.PoemId == poem.Id && p.MachineGenerated == false).AnyAsync()) + { + continue; + } + + + if (!string.IsNullOrEmpty(poem.PlainText)) + { + + await jobProgressServiceEF.UpdateJob(job.Id, i, $"{i} از {poems.Count} - {poem.FullTitle}"); + string command = "نام شهرها یا مکانهای جغرافیایی که در این متن آمده است را بده.اگر هیچ شهر یا مکان جغرافیایی در متن نیست جواب خالی برگردان." + Environment.NewLine + + "اگر نام مکان واقعاً اشاره به آن مکان نیست مثلاً در مورد مردی از اهالی آن شهر صحبت می‌کند یا در این متن آن کلمه معنی اسم مکان مورد نظر را نمی‌دهد آن را حذف کن." + Environment.NewLine + + "اگر هست به ازای هر مورد در یک خط ابتدا نام مکان، سپس یک سمی کالن، سپس عرض جغرافیایی سپس یک سمی کالن سپس طول جغرافیایی را بده." + Environment.NewLine + + "نمونهٔ جواب:" + Environment.NewLine + + "شیراز;29.5926;52.5836" + Environment.NewLine + + "برای پایان خط از استاندارد ویندوز استفاده کن."; + var completionResult = await openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest + { + Messages = new List + { + ChatMessage.FromSystem(command + + + Environment.NewLine + + + poem.Title + + Environment.NewLine + + poem.PlainText + ), + }, + Model = Betalgo.Ranul.OpenAI.ObjectModels.Models.Gpt_4o_mini, + }); + if (completionResult.Successful) + { + string aiResponse = completionResult.Choices.First().Message.Content; + if (aiResponse.Contains("اکتبر")) + { + aiResponse = ""; + } + if (!string.IsNullOrEmpty(aiResponse)) + { + var lines = aiResponse.Split(new[] { '\r', '\n' }); + foreach (var line in lines) + { + var parts = line.Split(';'); + if (parts.Length == 3) + { + var locationName = parts[0]; + if (!double.TryParse(parts[1], out double latitude)) + continue; + if (!double.TryParse(parts[2], out double longitude)) + continue; + GanjoorGeoLocation geoLocation = await context.GanjoorGeoLocations.AsNoTracking().Where(g => g.Name == locationName).FirstOrDefaultAsync(); + if (geoLocation == null) + { + geoLocation = new GanjoorGeoLocation() + { + Name = locationName, + Latitude = latitude, + Longitude = longitude, + MachineGenerated = true, + }; + context.Add(geoLocation); + await context.SaveChangesAsync(); + } + + if (true == await context.PoemGeoDateTags.AsNoTracking().Where(p => p.PoemId == poem.Id && p.LocationId == geoLocation.Id && p.CoupletIndex == 0).AnyAsync()) + { + continue; + } + + PoemGeoDateTag poemGeoDateTag = new PoemGeoDateTag() + { + PoemId = poem.Id, + CoupletIndex = 0, + LocationId = geoLocation.Id, + MachineGenerated = true, + }; + context.Add(poemGeoDateTag); + await context.SaveChangesAsync(); + } + + + } + } + } + + } + } + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + } + + } + }); + + } } } \ No newline at end of file