Skip to content

Commit f148356

Browse files
author
Tomasz Juszczak
committed
Added tools to generate images from prompt �via -use image
1 parent b5d8a56 commit f148356

30 files changed

+1557
-85
lines changed

.idea/.idea.Slack-GPT-Socket/.idea/dataSources.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Slack-GPT-Socket.sln

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slack-GPT-Socket", "Slack-G
44
EndProject
55
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slack-GPT-Tests", "Slack-GPT-Tests\Slack-GPT-Tests.csproj", "{8513CAC6-F4FB-4821-B229-7B2E31E1DA66}"
66
EndProject
7+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slack-Gpt-Source-Generator", "Slack-Gpt-Source-Generator\Slack-Gpt-Source-Generator\Slack-Gpt-Source-Generator.csproj", "{DB1A83EB-8250-4974-B6FF-A7FC72D5F793}"
8+
EndProject
79
Global
810
GlobalSection(SolutionConfigurationPlatforms) = preSolution
911
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +20,9 @@ Global
1820
{8513CAC6-F4FB-4821-B229-7B2E31E1DA66}.Debug|Any CPU.Build.0 = Debug|Any CPU
1921
{8513CAC6-F4FB-4821-B229-7B2E31E1DA66}.Release|Any CPU.ActiveCfg = Release|Any CPU
2022
{8513CAC6-F4FB-4821-B229-7B2E31E1DA66}.Release|Any CPU.Build.0 = Release|Any CPU
23+
{DB1A83EB-8250-4974-B6FF-A7FC72D5F793}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24+
{DB1A83EB-8250-4974-B6FF-A7FC72D5F793}.Debug|Any CPU.Build.0 = Debug|Any CPU
25+
{DB1A83EB-8250-4974-B6FF-A7FC72D5F793}.Release|Any CPU.ActiveCfg = Release|Any CPU
26+
{DB1A83EB-8250-4974-B6FF-A7FC72D5F793}.Release|Any CPU.Build.0 = Release|Any CPU
2127
EndGlobalSection
2228
EndGlobal

Slack-GPT-Socket.sln.DotSettings.user

+2-39
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,6 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2-
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=518a87a3_002D49c7_002D40fb_002Dbec1_002D478ce2091847/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="GptClientEdgeCasesTests_1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
2+
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=2635d6bc_002Dcf49_002D4263_002D8299_002Df4a2606fe890/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="TestGptTool_Json" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
33
&lt;TestAncestor&gt;&#xD;
4-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientEdgeCasesTests.GptClientEdgeCasesTests_1&lt;/TestId&gt;&#xD;
5-
&lt;/TestAncestor&gt;&#xD;
6-
&lt;/SessionState&gt;</s:String>
7-
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=7a21a381_002D1bd7_002D4190_002Daea7_002D60bbc3080eac/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="GptClientEdgeCasesTests_1 #3" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
8-
&lt;TestAncestor&gt;&#xD;
9-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientEdgeCasesTests.GptClientEdgeCasesTests_1&lt;/TestId&gt;&#xD;
10-
&lt;/TestAncestor&gt;&#xD;
11-
&lt;/SessionState&gt;</s:String>
12-
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=bc0f8e87_002D43a6_002D4830_002D802e_002Db69debc2f54b/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="GptClientEdgeCasesTests_1 #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
13-
&lt;TestAncestor&gt;&#xD;
14-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientEdgeCasesTests.GptClientEdgeCasesTests_1&lt;/TestId&gt;&#xD;
15-
&lt;/TestAncestor&gt;&#xD;
16-
&lt;/SessionState&gt;</s:String>
17-
18-
19-
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=e72966db_002D060a_002D4577_002D858b_002D3601c1cb06de/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="ContextBlockSanitation_OK" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
20-
&lt;TestAncestor&gt;&#xD;
21-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.TestContextBlockSanitation.ContextBlockSanitation_OK&lt;/TestId&gt;&#xD;
22-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.TestApplicationClass.TestApplicationVersion_Ok&lt;/TestId&gt;&#xD;
23-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientResolverTests&lt;/TestId&gt;&#xD;
24-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientUserCommandsTests.ResolveParameters_UserCommand_Ok&lt;/TestId&gt;&#xD;
25-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientUserCommandsTests.ResolveParameters_UserCommand_AddMultiple_Test_Ok&lt;/TestId&gt;&#xD;
26-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientUserCommandsTests.ResolveParameters_UserCommand_Remove_NotFound_Ok&lt;/TestId&gt;&#xD;
27-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientUserCommandsTests.ResolveParameters_UserCommand_Exists_NotFound_Ok&lt;/TestId&gt;&#xD;
28-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.ExecuteCommand_Ok&lt;/TestId&gt;&#xD;
29-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.HelpCommand_CustomGlobal_Ok&lt;/TestId&gt;&#xD;
30-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_List_Ok&lt;/TestId&gt;&#xD;
31-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_Add_And_List_Ok&lt;/TestId&gt;&#xD;
32-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_AddRemove_And_List_Ok&lt;/TestId&gt;&#xD;
33-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_AddRemove_And_List_CannotRemove&lt;/TestId&gt;&#xD;
34-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_AddSameCommand_MultipleUsers_CannotRemove&lt;/TestId&gt;&#xD;
35-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.WhatsNewCommand_Ok&lt;/TestId&gt;&#xD;
36-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.WhatsNewCommand_Error&lt;/TestId&gt;&#xD;
37-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.TestLiteDB.TestNullConnectionString_Ok&lt;/TestId&gt;&#xD;
38-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_AddOverwrite_Ok&lt;/TestId&gt;&#xD;
39-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.Handlers.CommandHandlerTests.CommandsCommand_RemoveSingle_Ok&lt;/TestId&gt;&#xD;
40-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientEdgeCasesTests.GptClientEdgeCasesTests_1&lt;/TestId&gt;&#xD;
41-
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net7.0::Slack_GPT_Tests.GptApi.GptClientEdgeCasesTests.GptClientEdgeCases_Ok&lt;/TestId&gt;&#xD;
4+
&lt;TestId&gt;NUnit3x::8513CAC6-F4FB-4821-B229-7B2E31E1DA66::net8.0::Slack_GPT_Tests.GptApi.GptToolJsonTests.TestGptTool_Json&lt;/TestId&gt;&#xD;
425
&lt;/TestAncestor&gt;&#xD;
436
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using System.Runtime.Serialization;
2+
using Humanizer;
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Converters;
5+
using OpenAI;
6+
using OpenAI.Images;
7+
using Slack_GPT_Socket.GptApi;
8+
9+
namespace Slack_GPT_Socket.Functions;
10+
11+
[JsonConverter(typeof(StringEnumConverter))]
12+
public enum QualityEnum
13+
{
14+
[EnumMember(Value = "standard")] Standard,
15+
[EnumMember(Value = "hd")] HighDefinition
16+
}
17+
18+
[JsonConverter(typeof(StringEnumConverter))]
19+
public enum SizeEnum
20+
{
21+
Square,
22+
Portrait,
23+
Landscape
24+
}
25+
26+
[JsonConverter(typeof(StringEnumConverter))]
27+
public enum StyleEnum
28+
{
29+
[EnumMember(Value = "vivid")] Vivid,
30+
[EnumMember(Value = "natural")] Natural
31+
}
32+
33+
/// <summary>
34+
/// Generate an image based on the given prompt, returns the URL of the generated image.
35+
/// </summary>
36+
public partial class GenerateImageTool : BaseGptTool, IExpressionGptTool<string, string, QualityEnum?, SizeEnum?, StyleEnum?>
37+
{
38+
private readonly OpenAIClient _api;
39+
40+
public override string[] Aliases { get; } =
41+
{
42+
"image",
43+
"generate-image",
44+
};
45+
46+
public GenerateImageTool(OpenAIClient api) : this()
47+
{
48+
_api = api;
49+
}
50+
51+
/// <summary>
52+
/// Generate an image based on the given prompt, returns the byte array of the generated image, that is then
53+
/// attached AUTOMATICALLY to the response message. Do not mention the image in the response message.
54+
/// </summary>
55+
/// <param name="prompt">
56+
/// Prompt field guides the AI in generating images by providing a clear, concise description of the desired
57+
/// scene or subject, including specific details like the setting, style, and mood. Use descriptive language to specify
58+
/// key elements, context, and artistic styles to ensure the resulting image closely aligns with your vision.
59+
/// </param>
60+
/// <param name="name">
61+
/// Short image name that will be used as file name. Use hyphen and leave out extension format. Use
62+
/// hyphens to mark words
63+
/// </param>
64+
/// <param name="quality">
65+
/// The quality of the image that will be generated. hd creates images with finer details and greater
66+
/// consistency across the image.
67+
/// </param>
68+
/// <param name="size">The size of the generated images, default is square</param>
69+
/// <param name="style">
70+
/// The style of the generated images. Vivid causes the model to lean towards generating hyper-real and
71+
/// dramatic images. Natural causes the model to produce more natural, less hyper-real looking images. Defaults to
72+
/// vivid
73+
/// </param>
74+
/// <returns></returns>
75+
public async Task<CallExpressionResult> CallExpression(string prompt, string name, QualityEnum? quality,
76+
SizeEnum? size, StyleEnum? style)
77+
{
78+
var client = _api.GetImageClient("dall-e-3");
79+
80+
GeneratedImageQuality? generatedImageQuality = quality switch
81+
{
82+
QualityEnum.Standard => GeneratedImageQuality.Standard,
83+
QualityEnum.HighDefinition => GeneratedImageQuality.High,
84+
_ => default
85+
};
86+
87+
GeneratedImageSize? generatedImageSize = size switch
88+
{
89+
SizeEnum.Square => GeneratedImageSize.W1024xH1024,
90+
SizeEnum.Portrait => GeneratedImageSize.W1024xH1792,
91+
SizeEnum.Landscape => GeneratedImageSize.W1792xH1024,
92+
_ => default
93+
};
94+
95+
GeneratedImageStyle? generatedImageStyle = style switch
96+
{
97+
StyleEnum.Vivid => GeneratedImageStyle.Vivid,
98+
StyleEnum.Natural => GeneratedImageStyle.Natural,
99+
_ => default
100+
};
101+
102+
var generateImageAsync = await client.GenerateImageAsync(prompt, new ImageGenerationOptions
103+
{
104+
Quality = generatedImageQuality,
105+
Size = generatedImageSize,
106+
Style = generatedImageStyle,
107+
ResponseFormat = GeneratedImageFormat.Bytes
108+
});
109+
110+
var imageBytes = generateImageAsync.Value.ImageBytes;
111+
var revisedPrompt = generateImageAsync.Value.RevisedPrompt;
112+
113+
using var memoryStream = new MemoryStream();
114+
await imageBytes.ToStream().CopyToAsync(memoryStream);
115+
var bytes = memoryStream.ToArray();
116+
117+
return new CallExpressionResult
118+
{
119+
TextResponse = "Generated using prompt: " + revisedPrompt + ". Image data is part of the message, do not embed it in the message.",
120+
Files = new List<FileAttachment>
121+
{
122+
new()
123+
{
124+
MimeType = "image/png",
125+
Data = bytes,
126+
Name = $"{name}.png",
127+
Title = name.Humanize()
128+
}
129+
}
130+
};
131+
}
132+
}

0 commit comments

Comments
 (0)