From a5bbca328936669eb59b9a6d057c686f0442f591 Mon Sep 17 00:00:00 2001 From: Dustin Updyke Date: Tue, 28 May 2024 09:10:51 -0400 Subject: [PATCH] api interface work --- .../AnimationDefinitions/Chat/ChatClient.cs | 13 +- .../AnimationDefinitions/ChatJob.cs | 16 ++- .../AnimationDefinitions/SocialSharingJob.cs | 9 +- .../Animations/AnimationsManager.cs | 10 ++ .../ContentServices/ContentCreationService.cs | 120 +++--------------- .../ContentServices/IContentService.cs | 8 ++ .../ContentServices/IFormatterService.cs | 12 ++ .../Native/NativeContentFormatterService.cs | 32 +++-- .../Ollama/OllamaConnectorService.cs | 2 +- .../Ollama/OllamaFormatterService.cs | 39 +++++- .../OpenAi/OpenAIConnectorService.cs | 11 +- .../OpenAi/OpenAIFormatterService.cs | 21 +-- .../Shadows/ShadowsConnectorService.cs | 4 +- .../Shadows/ShadowsFormatterService.cs | 34 ++++- .../ghosts.client.linux.csproj | 2 +- 15 files changed, 183 insertions(+), 150 deletions(-) create mode 100644 src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs create mode 100644 src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs index 28c65a04..0d3c537d 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs @@ -10,6 +10,7 @@ using System.Text.Json; using System.Threading.Tasks; using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +using ghosts.api.Areas.Animator.Infrastructure.ContentServices; using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; using ghosts.api.Areas.Animator.Infrastructure.Extensions; using ghosts.api.Areas.Animator.Infrastructure.Models; @@ -27,12 +28,14 @@ public class ChatClient private readonly HttpClient _client; private string _token; private string UserId { get; set; } + private IFormatterService _formatterService; - public ChatClient(ChatJobConfiguration config) + public ChatClient(ChatJobConfiguration config, IFormatterService formatterService) { _configuration = config; this._baseUrl = _configuration.Chat.BaseUrl; this._client = new HttpClient(); + this._formatterService = formatterService; } private async Task AdminLogin() @@ -406,7 +409,7 @@ private async Task ExecuteRequest(HttpRequestMessage request) } } - public async Task Step(OllamaConnectorService llm, Random random, IEnumerable agents) + public async Task Step(Random random, IEnumerable agents) { await this.AdminLogin(); @@ -425,11 +428,11 @@ await this.CreateUser(new UserCreate }); } - await this.StepEx(llm, random, username, _configuration.Chat.DefaultUserPassword); + await this.StepEx(random, username, _configuration.Chat.DefaultUserPassword); } } - private async Task StepEx(OllamaConnectorService llm, Random random, string username, string password) + private async Task StepEx(Random random, string username, string password) { _log.Trace($"Managing {username}..."); @@ -542,7 +545,7 @@ private async Task StepEx(OllamaConnectorService llm, Random random, string user respondingTo = history.UserName; } - var message = await llm.ExecuteQuery(prompt); + var message = await this._formatterService.ExecuteQuery(prompt); message = message.Clean(this._configuration.Replacements, random); if (!string.IsNullOrEmpty(respondingTo)) diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs index 082b5ad9..1c7d427c 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs @@ -8,6 +8,7 @@ using Ghosts.Animator.Extensions; using ghosts.api.Areas.Animator.Hubs; using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat; +using ghosts.api.Areas.Animator.Infrastructure.ContentServices; using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; @@ -27,6 +28,7 @@ public class ChatJob private readonly ChatClient _chatClient; private readonly int _currentStep; private CancellationToken _cancellationToken; + private IFormatterService _formatterService; public ChatJob(ApplicationSettings configuration, IServiceScopeFactory scopeFactory, Random random, IHubContext activityHubContext, CancellationToken cancellationToken) @@ -44,8 +46,10 @@ public ChatJob(ApplicationSettings configuration, IServiceScopeFactory scopeFact var chatConfiguration = JsonSerializer.Deserialize(File.ReadAllText("config/chat.json"), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? throw new InvalidOperationException(); - var llm = new OllamaConnectorService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine); - this._chatClient = new ChatClient(chatConfiguration); + this._formatterService = + new ContentCreationService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine).FormatterService; + + this._chatClient = new ChatClient(chatConfiguration, this._formatterService); while (!_cancellationToken.IsCancellationRequested) { @@ -55,17 +59,17 @@ public ChatJob(ApplicationSettings configuration, IServiceScopeFactory scopeFact return; } - this.Step(llm, random, chatConfiguration); - Thread.Sleep(this._configuration.AnimatorSettings.Animations.SocialSharing.TurnLength); + this.Step(random, chatConfiguration); + Thread.Sleep(this._configuration.AnimatorSettings.Animations.Chat.TurnLength); this._currentStep++; } } - private async void Step(OllamaConnectorService llm, Random random, ChatJobConfiguration chatConfiguration) + private async void Step(Random random, ChatJobConfiguration chatConfiguration) { _log.Trace("Executing a chat step..."); var agents = this._context.Npcs.ToList().Shuffle(_random).Take(chatConfiguration.Chat.AgentsPerBatch); - await this._chatClient.Step(llm, random, agents); + await this._chatClient.Step(random, agents); } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs index e4873bdd..ea3703a5 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs @@ -33,6 +33,7 @@ public class SocialSharingJob private readonly CancellationToken _cancellationToken; private readonly ApplicationDbContext _context; private readonly IMachineUpdateService _updateService; + private readonly IFormatterService _formatterService; public SocialSharingJob(ApplicationSettings configuration, IServiceScopeFactory scopeFactory, Random random, IHubContext activityHubContext, CancellationToken cancellationToken) @@ -48,6 +49,9 @@ public SocialSharingJob(ApplicationSettings configuration, IServiceScopeFactory this._cancellationToken = cancellationToken; this._updateService = innerScope.ServiceProvider.GetRequiredService(); + + _formatterService = + new ContentCreationService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine).FormatterService; if (!_configuration.AnimatorSettings.Animations.SocialSharing.IsInteracting) { @@ -84,9 +88,6 @@ private async void Step() { _log.Trace("Social sharing step proceeding..."); - var contentService = - new ContentCreationService(_configuration.AnimatorSettings.Animations.SocialSharing.ContentEngine); - //take some random NPCs var activities = new List(); var rawAgents = this._context.Npcs.ToList(); @@ -102,7 +103,7 @@ private async void Step() foreach (var agent in agents) { _log.Trace($"Processing agent {agent.NpcProfile.Email}..."); - var tweetText = await contentService.GenerateTweet(agent); + var tweetText = await this._formatterService.GenerateTweet(agent); if (string.IsNullOrEmpty(tweetText)) { _log.Trace($"Content service generated no payload..."); diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs index fb1a72ab..ed6d611b 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs @@ -109,6 +109,7 @@ public Task StopAsync(CancellationToken cancellationToken) this._socialGraphJobCancellationTokenSource.Cancel(); this._socialGraphJobThread?.Join(); this.RemoveJob("SOCIALGRAPH"); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); } catch { @@ -120,6 +121,7 @@ public Task StopAsync(CancellationToken cancellationToken) this._socialSharingJobCancellationTokenSource.Cancel(); this._socialSharingJobThread?.Join(); this.RemoveJob("SOCIALSHARING"); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); } catch { @@ -131,6 +133,7 @@ public Task StopAsync(CancellationToken cancellationToken) this._socialSharingJobCancellationTokenSource.Cancel(); this._socialBeliefsJobThread?.Join(); this.RemoveJob("SOCIALBELIEF"); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); } catch { @@ -142,6 +145,7 @@ public Task StopAsync(CancellationToken cancellationToken) this._chatJobJobCancellationTokenSource.Cancel(); this._chatJobThread?.Join(); this.RemoveJob("CHAT"); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); } catch { @@ -153,6 +157,7 @@ public Task StopAsync(CancellationToken cancellationToken) this._fullAutonomyCancellationTokenSource.Cancel(); this._fullAutonomyJobThread?.Join(); this.RemoveJob("FULLAUTONOMY"); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); } catch { @@ -181,22 +186,27 @@ public Task StopJob(string jobId) case "SOCIALGRAPH": this._socialGraphJobCancellationTokenSource.Cancel(); this._socialGraphJobThread?.Join(); + this._socialGraphJobCancellationTokenSource = new CancellationTokenSource(); break; case "SOCIALSHARING": this._socialSharingJobCancellationTokenSource.Cancel(); this._socialSharingJobThread?.Join(); + this._socialSharingJobCancellationTokenSource = new CancellationTokenSource(); break; case "SOCIALBELIEFS": this._socialSharingJobCancellationTokenSource.Cancel(); this._socialBeliefsJobThread?.Join(); + this._socialSharingJobCancellationTokenSource = new CancellationTokenSource(); break; case "CHAT": this._chatJobJobCancellationTokenSource.Cancel(); this._chatJobThread?.Join(); + this._chatJobJobCancellationTokenSource = new CancellationTokenSource(); break; case "FULLAUTONOMY": this._fullAutonomyCancellationTokenSource.Cancel(); this._fullAutonomyJobThread?.Join(); + this._chatJobJobCancellationTokenSource = new CancellationTokenSource(); break; } diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs index 88ab7780..ad13b6fc 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs @@ -1,15 +1,12 @@ // Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. using System; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Native; using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; using ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; -using Ghosts.Api.Infrastructure.Extensions; using NLog; namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; @@ -21,6 +18,7 @@ public class ContentCreationService private OpenAiFormatterService _openAiFormatterService; private OllamaFormatterService _ollamaFormatterService; private ShadowsFormatterService _shadowsFormatterService; + public IFormatterService FormatterService; public ContentCreationService(ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings configuration) { @@ -31,124 +29,36 @@ public ContentCreationService(ApplicationSettings.AnimatorSettingsDetail.Content configuration.Model; if (_configuration.Source.ToLower() == "openai" && this._openAiFormatterService.IsReady) + { _openAiFormatterService = new OpenAiFormatterService(); + this.FormatterService = _openAiFormatterService; + } else if (_configuration.Source.ToLower() == "ollama") + { _ollamaFormatterService = new OllamaFormatterService(_configuration); + this.FormatterService = _ollamaFormatterService; + } else if (_configuration.Source.ToLower() == "shadows") + { _shadowsFormatterService = new ShadowsFormatterService(_configuration); + this.FormatterService = _shadowsFormatterService; + } _log.Trace($"Content service configured for {_configuration.Source} on {_configuration.Host} running {_configuration.Model}"); } public async Task GenerateNextAction(NpcRecord agent, string history) { - var nextAction = string.Empty; - try - { - if (_configuration.Source.ToLower() == "openai" && this._openAiFormatterService.IsReady) - { - nextAction = await this._openAiFormatterService.GenerateNextAction(agent, history).ConfigureAwait(false); - } - else if (_configuration.Source.ToLower() == "ollama") - { - nextAction = await this._ollamaFormatterService.GenerateNextAction(agent, history); - } - else if (_configuration.Source.ToLower() == "shadows") - { - nextAction = await this._shadowsFormatterService.GenerateNextAction(agent, history); - } - - _log.Info($"{agent.NpcProfile.Name}'s next action is: {nextAction}"); - } - catch (Exception e) - { - _log.Error(e); - } + var nextAction = await this.FormatterService.GenerateNextAction(agent, history); + _log.Info($"{agent.NpcProfile.Name}'s next action is: {nextAction}"); return nextAction; } - public async Task GenerateTweet(NpcRecord agent) + public async Task GenerateTweet(NpcRecord npc) { - string tweetText = null; - - try - { - if (_configuration.Source.ToLower() == "openai" && this._openAiFormatterService.IsReady) - { - tweetText = await this._openAiFormatterService.GenerateTweet(agent).ConfigureAwait(false); - } - else if (_configuration.Source.ToLower() == "ollama") - { - var tries = 0; - while (string.IsNullOrEmpty(tweetText)) - { - tweetText = await this._ollamaFormatterService.GenerateTweet(agent); - tries++; - if (tries > 5) - return null; - } - - var regArray = new [] {"\"activities\": \\[\"([^\"]+)\"", "\"activity\": \"([^\"]+)\"", "'activities': \\['([^\\']+)'\\]", "\"activities\": \\[\"([^\\']+)'\\]"} ; - - foreach (var reg in regArray) - { - var match = Regex.Match(tweetText,reg); - if (match.Success) - { - // Extract the activity - tweetText = match.Groups[1].Value; - break; - } - } - } - else if (_configuration.Source.ToLower() == "shadows") - { - var tries = 0; - while (string.IsNullOrEmpty(tweetText)) - { - tweetText = await this._shadowsFormatterService.GenerateTweet(agent); - tries++; - if (tries > 5) - return null; - } - - var regArray = new [] {"\"activities\": \\[\"([^\"]+)\"", "\"activity\": \"([^\"]+)\"", "'activities': \\['([^\\']+)'\\]", "\"activities\": \\[\"([^\\']+)'\\]"} ; - - foreach (var reg in regArray) - { - var match = Regex.Match(tweetText,reg); - if (match.Success) - { - // Extract the activity - tweetText = match.Groups[1].Value; - break; - } - } - } - - while (string.IsNullOrEmpty(tweetText)) - { - tweetText = NativeContentFormatterService.GenerateTweet(agent); - } - - tweetText = tweetText.ReplaceDoubleQuotesWithSingleQuotes(); // else breaks csv file, //TODO should replace this with a proper csv library - - tweetText = Clean(tweetText); - - _log.Info($"{agent.NpcProfile.Name} said: {tweetText}"); - } - catch (Exception e) - { - _log.Info(e); - } + var tweetText = await this.FormatterService.GenerateTweet(npc); + _log.Info($"{npc.NpcProfile.Name} said: {tweetText}"); return tweetText; } - private string Clean(string raw) - { - raw = raw.Replace("`", ""); - raw = raw.Replace("\"", ""); - raw = raw.Replace("'", ""); - return raw; - } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs new file mode 100644 index 00000000..1050ba16 --- /dev/null +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; + +public interface IContentService +{ + Task ExecuteQuery(string prompt); +} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs new file mode 100644 index 00000000..86c0e06c --- /dev/null +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using ghosts.api.Areas.Animator.Infrastructure.Models; + +namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; + +public interface IFormatterService +{ + Task GenerateNextAction(NpcRecord npc, string history); + Task GenerateTweet(NpcRecord npc); + + Task ExecuteQuery(string prompt); +} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs index cc38ef08..9ea6a741 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs @@ -1,36 +1,48 @@ using System; using System.Linq; +using System.Threading.Tasks; using Ghosts.Animator; using Ghosts.Animator.Extensions; using Ghosts.Animator.Models; using ghosts.api.Areas.Animator.Infrastructure.Models; using NLog; -using Npgsql.EntityFrameworkCore.PostgreSQL.ValueGeneration.Internal; namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Native; -public static class NativeContentFormatterService +public class NativeContentFormatterService : IFormatterService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); + + public async Task GenerateNextAction(NpcRecord npc, string history) + { + //TODO + return string.Empty; + } + + public async Task ExecuteQuery(string prompt) + { + //TODO + return string.Empty; + } - public static string GenerateTweet(NpcRecord agent) + public async Task GenerateTweet(NpcRecord npc) { string tweetText; - if (agent.NpcProfile.Birthdate.Date.DayOfYear == DateTime.Now.Date.DayOfYear) + if (npc.NpcProfile.Birthdate.Date.DayOfYear == DateTime.Now.Date.DayOfYear) { - tweetText = ProcessBirthday(agent.NpcProfile); + tweetText = ProcessBirthday(npc.NpcProfile); } else { var i = AnimatorRandom.Rand.Next(0, 15); tweetText = i switch { - 0 => ProcessAddress(agent.NpcProfile), - 1 => ProcessFamily(agent.NpcProfile), - 2 => ProcessEmployment(agent.NpcProfile), - 3 => ProcessEducation(agent.NpcProfile), - 4 => ProcessAccount(agent.NpcProfile), + 0 => ProcessAddress(npc.NpcProfile), + 1 => ProcessFamily(npc.NpcProfile), + 2 => ProcessEmployment(npc.NpcProfile), + 3 => ProcessEducation(npc.NpcProfile), + 4 => ProcessAccount(npc.NpcProfile), _ => Faker.Lorem.Sentence() //default is just text, no personal information }; } diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs index a5be5ec5..d53860c9 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs @@ -15,7 +15,7 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; -public class OllamaConnectorService +public class OllamaConnectorService : IContentService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings _configuration; diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs index 58869f84..2a9ab4a2 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; @@ -8,11 +9,11 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; -public class OllamaFormatterService +public class OllamaFormatterService : IFormatterService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings _configuration; - private OllamaConnectorService _ollamaConnectorService; + private OllamaConnectorService _connectorService; public OllamaFormatterService(ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings configuration) { @@ -22,7 +23,12 @@ public OllamaFormatterService(ApplicationSettings.AnimatorSettingsDetail.Content _configuration.Model = Environment.GetEnvironmentVariable("OLLAMA_MODEL") ?? configuration.Model; - _ollamaConnectorService = new OllamaConnectorService(_configuration); + _connectorService = new OllamaConnectorService(_configuration); + } + + public async Task ExecuteQuery(string prompt) + { + return await this._connectorService.ExecuteQuery(prompt); } public async Task GenerateTweet(NpcRecord npc) @@ -37,7 +43,30 @@ public async Task GenerateTweet(NpcRecord npc) messages.Append(s); } - return await _ollamaConnectorService.ExecuteQuery(messages.ToString()); + var tweetText = await _connectorService.ExecuteQuery(messages.ToString()); + var tries = 0; + while (string.IsNullOrEmpty(tweetText)) + { + tweetText = await _connectorService.ExecuteQuery(messages.ToString()); + tries++; + if (tries > 5) + return null; + } + + var regArray = new [] {"\"activities\": \\[\"([^\"]+)\"", "\"activity\": \"([^\"]+)\"", "'activities': \\['([^\\']+)'\\]", "\"activities\": \\[\"([^\\']+)'\\]"} ; + + foreach (var reg in regArray) + { + var match = Regex.Match(tweetText,reg); + if (match.Success) + { + // Extract the activity + tweetText = match.Groups[1].Value; + break; + } + } + + return tweetText; } public async Task GenerateNextAction(NpcRecord npc, string history) @@ -62,6 +91,6 @@ public async Task GenerateNextAction(NpcRecord npc, string history) // _log.Trace(messages.ToString()); - return await _ollamaConnectorService.ExecuteQuery(messages.ToString()); + return await _connectorService.ExecuteQuery(messages.ToString()); } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs index 1b28f7af..2c8dbf7c 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs @@ -11,7 +11,7 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; -public class OpenAiConnectorService +public class OpenAiConnectorService : IContentService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly OpenAIService _service; @@ -54,6 +54,15 @@ public OpenAiConnectorService() this.IsReady = true; } + public async Task ExecuteQuery(string prompt) + { + var messages = new List + { + ChatMessage.FromSystem(prompt) + }; + return await this.ExecuteQuery(messages); + } + //TODO: shouldn't this method save off every request and response somewhere? public async Task ExecuteQuery(IList messages) { diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs index 0b79f9cd..53ad4bf4 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs @@ -7,17 +7,22 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; -public class OpenAiFormatterService +public class OpenAiFormatterService : IFormatterService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly OpenAiConnectorService _openAiConnectorService; + private readonly OpenAiConnectorService _connectorService; public bool IsReady { get; set; } public OpenAiFormatterService() { - _openAiConnectorService = new OpenAiConnectorService(); - this.IsReady = _openAiConnectorService.IsReady; + _connectorService = new OpenAiConnectorService(); + this.IsReady = _connectorService.IsReady; + } + + public async Task ExecuteQuery(string prompt) + { + return await this._connectorService.ExecuteQuery(prompt); } public async Task GenerateTweet(NpcRecord npc) @@ -34,7 +39,7 @@ public async Task GenerateTweet(NpcRecord npc) messages.Add(ChatMessage.FromSystem(s)); } - return await _openAiConnectorService.ExecuteQuery(messages); + return await _connectorService.ExecuteQuery(messages); } public async Task GenerateNextAction(NpcRecord npc, string history) @@ -53,7 +58,7 @@ public async Task GenerateNextAction(NpcRecord npc, string history) messages.Add(ChatMessage.FromSystem(s)); } - return await _openAiConnectorService.ExecuteQuery(messages); + return await _connectorService.ExecuteQuery(messages); } public async Task GeneratePowershellScript(NpcRecord npc) @@ -66,7 +71,7 @@ public async Task GeneratePowershellScript(NpcRecord npc) ChatMessage.FromSystem("Generate a relevant powershell script for this person to execute on their windows computer") }; - return await _openAiConnectorService.ExecuteQuery(messages); + return await _connectorService.ExecuteQuery(messages); } public async Task GenerateCommand(NpcRecord npc) @@ -79,7 +84,7 @@ public async Task GenerateCommand(NpcRecord npc) ChatMessage.FromSystem("Generate a relevant command-line command for this person to execute on their windows computer") }; - return await _openAiConnectorService.ExecuteQuery(messages); + return await _connectorService.ExecuteQuery(messages); } //public async Task GenerateDocumentContent(NPC npc) diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs index 4d170968..a62c080c 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs @@ -15,7 +15,7 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; -public class ShadowsConnectorService +public class ShadowsConnectorService : IContentService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings _configuration; @@ -34,7 +34,7 @@ public async Task ExecuteQuery(string prompt) return await ExecuteQuery(_configuration.Model, prompt); } - public async Task ExecuteQuery(string modelName, string prompt, string system = null, + private async Task ExecuteQuery(string modelName, string prompt, string system = null, string template = null, string context = null, string options = null, Action callback = null) { Dictionary payload = null; diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs index dd9d2b91..83a4cd77 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs +++ b/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; @@ -8,7 +9,7 @@ namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; -public class ShadowsFormatterService +public class ShadowsFormatterService : IFormatterService { private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly ApplicationSettings.AnimatorSettingsDetail.ContentEngineSettings _configuration; @@ -25,6 +26,11 @@ public ShadowsFormatterService(ApplicationSettings.AnimatorSettingsDetail.Conten _connectorService = new ShadowsConnectorService(_configuration); } + public async Task ExecuteQuery(string prompt) + { + return await this._connectorService.ExecuteQuery(prompt); + } + public async Task GenerateTweet(NpcRecord npc) { var flattenedAgent = GenericContentHelpers.GetFlattenedNpc(npc); @@ -37,7 +43,31 @@ public async Task GenerateTweet(NpcRecord npc) messages.Append(s); } - return await _connectorService.ExecuteQuery(messages.ToString()); + var tweetText = await _connectorService.ExecuteQuery(messages.ToString()); + + var tries = 0; + while (string.IsNullOrEmpty(tweetText)) + { + tweetText = await GenerateTweet(npc); + tries++; + if (tries > 5) + return null; + } + + var regArray = new [] {"\"activities\": \\[\"([^\"]+)\"", "\"activity\": \"([^\"]+)\"", "'activities': \\['([^\\']+)'\\]", "\"activities\": \\[\"([^\\']+)'\\]"} ; + + foreach (var reg in regArray) + { + var match = Regex.Match(tweetText,reg); + if (match.Success) + { + // Extract the activity + tweetText = match.Groups[1].Value; + break; + } + } + + return tweetText; } public async Task GenerateNextAction(NpcRecord npc, string history) diff --git a/src/ghosts.client.linux/ghosts.client.linux.csproj b/src/ghosts.client.linux/ghosts.client.linux.csproj index bc4bc4c6..bee1a276 100755 --- a/src/ghosts.client.linux/ghosts.client.linux.csproj +++ b/src/ghosts.client.linux/ghosts.client.linux.csproj @@ -7,7 +7,7 @@ 8.0.0.0 8.0.0.0 8.0.0.0 - 8.0.14.0 + 8.0.51.50 false