From 2c09e5ac1c0dae37fbb94b554a7116ae9c4ca501 Mon Sep 17 00:00:00 2001 From: Pavel Zhur Date: Sun, 15 Sep 2024 01:33:34 +0300 Subject: [PATCH 1/3] dragon images direct --- .../Model/Enums/InteractionType.cs | 5 +- .../Commands/Images.cs | 100 ++++++++++++++++++ .../PipelineHandlers/AiDialogHandler.cs | 36 +------ .../ServiceCollectionExtensions.cs | 2 + .../Services/Availability.cs | 41 +++++++ .../Services/SingletonAbstractions.cs | 9 +- 6 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 OneShelf.OneDragon/OneShelf.OneDragon.Processor/Commands/Images.cs create mode 100644 OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/Availability.cs diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Database/Model/Enums/InteractionType.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Database/Model/Enums/InteractionType.cs index 8b8d2e4a..42aa5966 100644 --- a/OneShelf.OneDragon/OneShelf.OneDragon.Database/Model/Enums/InteractionType.cs +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Database/Model/Enums/InteractionType.cs @@ -6,5 +6,8 @@ public enum InteractionType AiMemoryPoint, AiResetDialog, AiImagesLimit, - AiImagesSuccess + AiImagesSuccess, + + DirectImagesSuccess, + DirectImagesLimit, } \ No newline at end of file diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Commands/Images.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Commands/Images.cs new file mode 100644 index 00000000..e1760210 --- /dev/null +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Commands/Images.cs @@ -0,0 +1,100 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using OneShelf.Common.OpenAi.Services; +using OneShelf.OneDragon.Database; +using OneShelf.OneDragon.Database.Model.Enums; +using OneShelf.OneDragon.Processor.Model; +using OneShelf.OneDragon.Processor.Services; +using OneShelf.Telegram.Model.CommandAttributes; +using OneShelf.Telegram.Model.Ios; +using OneShelf.Telegram.Services.Base; +using Telegram.BotAPI; +using Telegram.BotAPI.AvailableMethods; +using Telegram.BotAPI.AvailableTypes; + +namespace OneShelf.OneDragon.Processor.Commands; + +[AdminCommand("images", "Картинки", "Сделать картинки по текстовому описанию")] +public class Images : Command +{ + private readonly DragonDatabase _dragonDatabase; + private readonly DragonScope _scope; + private readonly Availability _availability; + private readonly DialogRunner _dialogRunner; + private readonly TelegramBotClient _api; + + public Images(Io io, DragonDatabase dragonDatabase, DragonScope scope, Availability availability, DialogRunner dialogRunner, IOptions options) + : base(io) + { + _dragonDatabase = dragonDatabase; + _scope = scope; + _availability = availability; + _dialogRunner = dialogRunner; + _api = new(options.Value.Token); + } + + protected override async Task ExecuteQuickly() + { + var imagesUnavailableUntil = await _availability.GetImagesUnavailableUntil(DateTime.Now); + if (imagesUnavailableUntil != null) + { + Io.WriteLine($"Картинок нет до {imagesUnavailableUntil.Value:g} UTC"); + + _dragonDatabase.Interactions.Add(new() + { + CreatedOn = DateTime.Now, + ChatId = _scope.ChatId, + UserId = Io.UserId, + UpdateId = _scope.UpdateId, + InteractionType = InteractionType.DirectImagesLimit, + Serialized = "reset", + }); + + return; + } + + var query = Io.FreeChoice("Подробное описание:"); + var count = Io.StrictChoice("Сколько?", int.Parse, new[] { "1", "2", "3", "4", "5" }); + + if (count is not (>= 1 and <= 5)) + { + Io.WriteLine("Многовато или маловато."); + return; + } + + Io.WriteLine("Рисую..."); + + Scheduled(Background(query, count)); + } + + private async Task Background(string query, int count) + { + var aiParameters = await _dragonDatabase.AiParameters.SingleAsync(); + var images = await _dialogRunner.GenerateImages(Enumerable.Repeat(query, count).ToList(), new() + { + ImagesVersion = aiParameters.DalleVersion, + UserId = _scope.UserId, + DomainId = -1, + Version = aiParameters.GptVersion, + ChatId = _scope.ChatId, + UseCase = "direct images", + AdditionalBillingInfo = "one dragon", + SystemMessage = "no message", + }); + + _dragonDatabase.Interactions.Add(new() + { + CreatedOn = DateTime.Now, + ChatId = _scope.ChatId, + UserId = Io.UserId, + UpdateId = _scope.UpdateId, + InteractionType = InteractionType.DirectImagesSuccess, + Serialized = count.ToString(), + ShortInfoSerialized = query, + }); + + await _dragonDatabase.SaveChangesAsync(); + + await _api.SendMediaGroupAsync(new(_scope.ChatId, images.Select(x => new InputMediaPhoto(x.ToString()) {Caption = "1"}))); + } +} \ No newline at end of file diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs index 4a29ddf4..5c7e5acd 100644 --- a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs @@ -18,16 +18,18 @@ public class AiDialogHandler : AiDialogHandlerBase { private readonly DragonDatabase _dragonDatabase; private readonly DragonScope _dragonScope; + private readonly Availability _availability; public AiDialogHandler( IScopedAbstractions scopedAbstractions, ILogger> logger, DialogRunner dialogRunner, - DragonDatabase dragonDatabase, DragonScope dragonScope) + DragonDatabase dragonDatabase, DragonScope dragonScope, Availability availability) : base(scopedAbstractions, logger, dragonDatabase, dialogRunner) { _dragonDatabase = dragonDatabase; _dragonScope = dragonScope; + _availability = availability; } protected override void OnInitializing(Update update) @@ -50,37 +52,7 @@ protected override bool CheckRelevant(Update update) } protected override async Task GetImagesUnavailableUntil(DateTime now) - { - var user = await _dragonDatabase.Users.SingleAsync(x => x.Id == _dragonScope.UserId); - if (!user.UseLimits) return null; - - var limits = await _dragonDatabase.Limits.Where(x => x.Images.HasValue).ToListAsync(); - if (!limits.Any()) return null; - - DateTime Since(TimeSpan window) => now.Add(-window); - - var imagesSince = Since(limits.Max(x => x.Window)); - var images = (await _dragonDatabase.Interactions - .Where(x => x.UserId == _dragonScope.UserId && x.ChatId == _dragonScope.ChatId) - .Where(x => x.InteractionType == InteractionType.AiImagesSuccess) - .Where(x => x.CreatedOn >= imagesSince) - .ToListAsync()) - .Select(x => (x.CreatedOn, count: int.Parse(x.Serialized))) - .ToList(); - - DateTime? imagesUnavailableUntil = null; - foreach (var limit in limits) - { - if (images.Where(x => x.CreatedOn >= Since(limit.Window)).Sum(x => x.count) >= limit.Images!.Value) - { - imagesUnavailableUntil ??= DateTime.MinValue; - var value = images.Min(x => x.CreatedOn).Add(limit.Window); - imagesUnavailableUntil = imagesUnavailableUntil > value ? imagesUnavailableUntil : value; - } - } - - return imagesUnavailableUntil; - } + => await _availability.GetImagesUnavailableUntil(now); protected override async Task GetChatUnavailableUntil() { diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/ServiceCollectionExtensions.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/ServiceCollectionExtensions.cs index c52a9c50..7adc2a10 100644 --- a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/ServiceCollectionExtensions.cs +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/ServiceCollectionExtensions.cs @@ -27,6 +27,7 @@ public static IServiceCollection AddProcessor(this IServiceCollection services, .AddCommand() .AddCommand() .AddCommand() + .AddCommand() .AddPipelineHandlerInOrder() .AddPipelineHandlerInOrder() @@ -38,6 +39,7 @@ public static IServiceCollection AddProcessor(this IServiceCollection services, services .AddDragonDatabase() .AddOpenAi(configuration) + .AddScoped() .AddScoped(); return services; diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/Availability.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/Availability.cs new file mode 100644 index 00000000..5c0d18b1 --- /dev/null +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/Availability.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore; +using OneShelf.OneDragon.Database; +using OneShelf.OneDragon.Database.Model.Enums; + +namespace OneShelf.OneDragon.Processor.Services; + +public class Availability(DragonDatabase dragonDatabase, DragonScope dragonScope) +{ + public async Task GetImagesUnavailableUntil(DateTime now) + { + var user = await dragonDatabase.Users.SingleAsync(x => x.Id == dragonScope.UserId); + if (!user.UseLimits) return null; + + var limits = await dragonDatabase.Limits.Where(x => x.Images.HasValue).ToListAsync(); + if (!limits.Any()) return null; + + DateTime Since(TimeSpan window) => now.Add(-window); + + var imagesSince = Since(limits.Max(x => x.Window)); + var images = (await dragonDatabase.Interactions + .Where(x => x.UserId == dragonScope.UserId && x.ChatId == dragonScope.ChatId) + .Where(x => x.InteractionType == InteractionType.AiImagesSuccess) + .Where(x => x.CreatedOn >= imagesSince) + .ToListAsync()) + .Select(x => (x.CreatedOn, count: int.Parse(x.Serialized))) + .ToList(); + + DateTime? imagesUnavailableUntil = null; + foreach (var limit in limits) + { + if (images.Where(x => x.CreatedOn >= Since(limit.Window)).Sum(x => x.count) >= limit.Images!.Value) + { + imagesUnavailableUntil ??= DateTime.MinValue; + var value = images.Min(x => x.CreatedOn).Add(limit.Window); + imagesUnavailableUntil = imagesUnavailableUntil > value ? imagesUnavailableUntil : value; + } + } + + return imagesUnavailableUntil; + } +} \ No newline at end of file diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/SingletonAbstractions.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/SingletonAbstractions.cs index cbe8bd1c..99529519 100644 --- a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/SingletonAbstractions.cs +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/Services/SingletonAbstractions.cs @@ -9,14 +9,19 @@ public class SingletonAbstractions : ISingletonAbstractions { public List> GetCommandsGrid() => [ [ - typeof(Start), + typeof(Images), + ], + [ typeof(Help), typeof(ViewBilling), typeof(Amnesia) ], + [ + typeof(Start), + ], [ typeof(UpdateCommands), - ] + ], ]; public Type? GetDefaultCommand() => null; From e2078e908e5b4093d275492833a25821cac313de Mon Sep 17 00:00:00 2001 From: Pavel Zhur Date: Sun, 15 Sep 2024 01:46:14 +0300 Subject: [PATCH 2/3] image prompts traces --- .../PipelineHandlers/AiDialogHandler.cs | 10 +++++++++- .../PipelineHandlers/AiDialogHandlerBase.cs | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs index 5c7e5acd..ec8fe15d 100644 --- a/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs +++ b/OneShelf.OneDragon/OneShelf.OneDragon.Processor/PipelineHandlers/AiDialogHandler.cs @@ -5,6 +5,7 @@ using OneShelf.OneDragon.Database; using OneShelf.OneDragon.Database.Model; using OneShelf.OneDragon.Database.Model.Enums; +using OneShelf.OneDragon.Processor.Model; using OneShelf.OneDragon.Processor.Services; using OneShelf.Telegram.Ai.Model; using OneShelf.Telegram.Ai.PipelineHandlers; @@ -19,17 +20,22 @@ public class AiDialogHandler : AiDialogHandlerBase private readonly DragonDatabase _dragonDatabase; private readonly DragonScope _dragonScope; private readonly Availability _availability; + private readonly IOptions _options; public AiDialogHandler( IScopedAbstractions scopedAbstractions, ILogger> logger, DialogRunner dialogRunner, - DragonDatabase dragonDatabase, DragonScope dragonScope, Availability availability) + DragonDatabase dragonDatabase, + DragonScope dragonScope, + Availability availability, + IOptions options) : base(scopedAbstractions, logger, dragonDatabase, dialogRunner) { _dragonDatabase = dragonDatabase; _dragonScope = dragonScope; _availability = availability; + _options = options; } protected override void OnInitializing(Update update) @@ -37,6 +43,8 @@ protected override void OnInitializing(Update update) _dragonDatabase.InitializeInteractionsRepositoryScope(update.Message!.From!.Id, update.Message.Chat.Id); } + protected override bool TraceImages => _options.Value.IsAdmin(_dragonScope.UserId); + protected override IInteraction CreateInteraction(Update update) => new Interaction { ChatId = update.Message!.Chat.Id, diff --git a/OneShelf.Telegram/OneShelf.Telegram.Ai/PipelineHandlers/AiDialogHandlerBase.cs b/OneShelf.Telegram/OneShelf.Telegram.Ai/PipelineHandlers/AiDialogHandlerBase.cs index bfb95c8d..ecefd31d 100644 --- a/OneShelf.Telegram/OneShelf.Telegram.Ai/PipelineHandlers/AiDialogHandlerBase.cs +++ b/OneShelf.Telegram/OneShelf.Telegram.Ai/PipelineHandlers/AiDialogHandlerBase.cs @@ -233,6 +233,8 @@ protected virtual void OnInitializing(Update update) { } + protected virtual bool TraceImages => false; + protected async Task Respond(Update update) { var now = DateTime.Now; @@ -352,6 +354,18 @@ protected async Task Respond(Update update) { try { + if (TraceImages) + { + try + { + await SendMessage(update, string.Join(Environment.NewLine, newMessagePoint.ImageTraces.Select(x => $"- {x}").Prepend(string.Empty).Prepend("Traces:")), false); + } + catch (Exception e) + { + _logger.LogError(e, "Error writing the traces."); + } + } + if (!string.IsNullOrWhiteSpace(text)) { await SendMessage(update, text, result.Images, false); From 8e015f705e0209e57e15f38f93c4871c336ef879 Mon Sep 17 00:00:00 2001 From: Pavel Zhur Date: Sun, 15 Sep 2024 01:48:23 +0300 Subject: [PATCH 3/3] telegram videos functions removed from the microservices build --- .github/workflows/microservices.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/microservices.yml b/.github/workflows/microservices.yml index de397bb4..7de26c48 100644 --- a/.github/workflows/microservices.yml +++ b/.github/workflows/microservices.yml @@ -61,8 +61,8 @@ jobs: run: dotnet publish OneShelf.Sources/OneShelf.Sources.Self.Api/OneShelf.Sources.Self.Api.csproj --no-restore - name: Publish 11 run: dotnet publish OneShelf.OneDragon/OneShelf.OneDragon.Runner.Functions/OneShelf.OneDragon.Runner.Functions.csproj --no-restore - - name: Publish 12 - run: dotnet publish OneShelf.Videos/OneShelf.Videos.Telegram.Functions/OneShelf.Videos.Telegram.Functions.csproj --no-restore +# - name: Publish 12 +# run: dotnet publish OneShelf.Videos/OneShelf.Videos.Telegram.Functions/OneShelf.Videos.Telegram.Functions.csproj --no-restore # - uses: actions/upload-artifact@v4 # with: @@ -116,7 +116,7 @@ jobs: - run: Compress-Archive -Path OneShelf.Collectives/OneShelf.Collectives.Api/bin/Release/net8.0/publish/* -Destination OneShelf.Collectives.Api.zip - run: Compress-Archive -Path OneShelf.Sources/OneShelf.Sources.Self.Api/bin/Release/net8.0/publish/* -Destination OneShelf.Sources.Self.Api.zip - run: Compress-Archive -Path OneShelf.OneDragon/OneShelf.OneDragon.Runner.Functions/bin/Release/net8.0/publish/* -Destination OneShelf.OneDragon.Runner.Functions.zip - - run: Compress-Archive -Path OneShelf.Videos/OneShelf.Videos.Telegram.Functions/bin/Release/net8.0/publish/* -Destination OneShelf.Videos.Telegram.Functions.zip +# - run: Compress-Archive -Path OneShelf.Videos/OneShelf.Videos.Telegram.Functions/bin/Release/net8.0/publish/* -Destination OneShelf.Videos.Telegram.Functions.zip # - name: Test # run: dotnet test --no-build --verbosity normal