Skip to content

Initial implementation of Embedding data type. #1059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 59 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5729d80
Initial implementation of Embedding data type.
Sep 5, 2024
6b3c965
Fix failing tests because OpenAI-DotNet.dll.
claudiamurialdo Sep 9, 2024
88e8656
Add OpenAI-DotNet to Unit test.
Sep 10, 2024
182c7b7
Add getGxembedding function.
Sep 10, 2024
69283a5
Add default constructor to GxEmbedding
Sep 10, 2024
77fdde6
Improve embedding methods.
Sep 11, 2024
3b4a929
Add missing parameter.
Sep 11, 2024
28fca72
Add messages parameter to GenerateEmbedding method
Sep 12, 2024
58f2cc2
Fix Message
Sep 12, 2024
b2be822
Improve embedding handling.
Sep 12, 2024
a8a8964
Add model and dimensions to database operations.
Sep 16, 2024
63d5e99
Apply configuration settings for OpenAI provider
Sep 17, 2024
7a70ca7
Fix Empty value for GxEmbedding.
Sep 18, 2024
f730c1f
The embedding model and dimensions were not set in the instance retur…
claudiamurialdo Oct 16, 2024
ffd749a
Migrate from OpenAI-DotNet to OpenAI api.
claudiamurialdo Nov 13, 2024
7cbdbc1
Refactor Embedding classes
claudiamurialdo Nov 14, 2024
bd1aaaf
Merge branch 'master' into embedding-data-type
claudiamurialdo Nov 14, 2024
c9114c4
Update Assistant interface
claudiamurialdo Nov 14, 2024
7a3f3a7
Minor code cleanups
claudiamurialdo Nov 14, 2024
504d406
Minor code cleanups
claudiamurialdo Nov 14, 2024
c15535b
Maintain implicit 'saia:agent:' prefix
claudiamurialdo Nov 14, 2024
d783a02
Make GXAgent public.
claudiamurialdo Nov 15, 2024
919c3ff
Change CallAssistant signature for result parameter (object).
claudiamurialdo Nov 15, 2024
f51076b
Add error handling for AgentObject.
claudiamurialdo Nov 15, 2024
22573c6
Add trace messages.
claudiamurialdo Nov 18, 2024
617a86e
Add CallResult.cs to .NETFramework standard classes
claudiamurialdo Nov 19, 2024
67b5b7b
Add missing file.
claudiamurialdo Nov 19, 2024
71f69e1
The EmbeddingService class must be public to allow dynamic creation f…
claudiamurialdo Nov 19, 2024
69d8b60
Add ChatMessage datatype.
claudiamurialdo Nov 25, 2024
09a1786
Change Namespace.
claudiamurialdo Nov 25, 2024
8f48ddf
Add CallAgent with chathistory parameter.
claudiamurialdo Nov 25, 2024
9748909
Implement CallAgent method.
claudiamurialdo Nov 25, 2024
e3a2eba
Convert chatMessages to openaichatmessages
claudiamurialdo Nov 27, 2024
bfaf671
Add missing null check.
claudiamurialdo Nov 27, 2024
b525b54
Handle exception when accessing an invalid chatCompetion.content.
claudiamurialdo Nov 27, 2024
c37bf0e
Replace OpenAI client with direct HttpClient call, as 'variables' is …
claudiamurialdo Nov 28, 2024
dbb369a
Remove unused classes and methods.
claudiamurialdo Nov 28, 2024
f692e68
Fix build error.
claudiamurialdo Nov 28, 2024
7e8efb2
Revert changes commited by mistake.
claudiamurialdo Nov 28, 2024
91f3b8b
Fix casing error.
claudiamurialdo Nov 29, 2024
b21653a
Move ProcessTollCall to GXAgent class in order to define CallTool vir…
claudiamurialdo Dec 12, 2024
831824e
Merge branch 'master' into embedding-data-type
claudiamurialdo Dec 13, 2024
5e7f23a
Fix id for finish reason tool_calls
claudiamurialdo Dec 13, 2024
c73d14e
Merge branch 'embedding-data-type' of https://github.com/genexuslabs/…
claudiamurialdo Dec 13, 2024
b94e7ff
minor
claudiamurialdo Dec 13, 2024
503806f
Fix failing test.
claudiamurialdo Dec 13, 2024
7e03762
"temporarily disabled" test
claudiamurialdo Dec 13, 2024
7716efb
Merge branch 'master' into embedding-data-type
claudiamurialdo Feb 11, 2025
48ff16b
Add support for embedding data type in mysql.
claudiamurialdo Feb 11, 2025
c9338c4
Fix merge error.
claudiamurialdo Feb 11, 2025
d67d0f3
Handle embedding (vector datatype) in MySQL by storing it as a byte a…
claudiamurialdo Feb 18, 2025
d9eb7b4
Selects the appropriate distance function based on the MySQL variant.
claudiamurialdo Mar 5, 2025
e7ecc5d
Open connection before retrieving server version.
claudiamurialdo Mar 6, 2025
603f99f
Avoid NotSupportedException when setting an invalid isolation level (…
claudiamurialdo Mar 10, 2025
59427a7
Added ChatResult data type for the Chat Result external object in the…
claudiamurialdo Apr 13, 2025
9691e5a
Added ChatAgent method (currently a dummy implementation)
claudiamurialdo Apr 16, 2025
9836815
Add initial implementation of ChatAgent method
claudiamurialdo Apr 16, 2025
afc1f3c
Keep previous CallAgent interface.
claudiamurialdo Apr 16, 2025
f1ffe01
Event stream response was not processed as chunked in HttpClient.
claudiamurialdo Apr 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions dotnet/DotNetStandardClasses.sln
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogTest", "test\benchmarks\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccessTokenController_Test", "test\NativeAccessControllerTest\AccessTokenController_Test.csproj", "{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai", "ai", "{D13691A9-04AE-4ABB-A694-8AD41D74CE23}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GxAI", "src\dotnetcore\Providers\AI\GxAI.csproj", "{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ws", "ws", "{B5C28D81-BCD9-4B29-9B68-EDD81D1018D5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F8959289-4ED7-430C-97B7-FAAA29829708}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GxSoapHandler", "src\extensions\ws\src\GxSoapHandler\GxSoapHandler.csproj", "{58C84EC7-A0B3-4C1B-BD78-989AEE87EA32}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Functions", "Functions", "{E59B3248-4C26-4DB0-96CB-67437319E22B}"
EndProject
Global
Expand Down Expand Up @@ -648,6 +653,10 @@ Global
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.Build.0 = Release|Any CPU
{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998}.Release|Any CPU.Build.0 = Release|Any CPU
{58C84EC7-A0B3-4C1B-BD78-989AEE87EA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58C84EC7-A0B3-4C1B-BD78-989AEE87EA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58C84EC7-A0B3-4C1B-BD78-989AEE87EA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -778,6 +787,8 @@ Global
{46DAAFD1-FAF5-4904-8EC5-406BE04E5538} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
{A1DBDCE0-4F09-445F-A202-9B260CDD46CF} = {46DAAFD1-FAF5-4904-8EC5-406BE04E5538}
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
{D13691A9-04AE-4ABB-A694-8AD41D74CE23} = {2261B65E-3757-4E5B-9DCD-EAE8D1E236A3}
{88FE3199-CFE3-42C4-AD6F-3EE49D7B5998} = {D13691A9-04AE-4ABB-A694-8AD41D74CE23}
{B5C28D81-BCD9-4B29-9B68-EDD81D1018D5} = {C6AFB6A3-FF0B-4970-B1F1-10BCD3D932B2}
{F8959289-4ED7-430C-97B7-FAAA29829708} = {B5C28D81-BCD9-4B29-9B68-EDD81D1018D5}
{58C84EC7-A0B3-4C1B-BD78-989AEE87EA32} = {F8959289-4ED7-430C-97B7-FAAA29829708}
Expand Down
93 changes: 93 additions & 0 deletions dotnet/src/dotnetcore/GxClasses/Domain/GxEmbedding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Threading.Tasks;
using GxClasses.Helpers;
namespace GeneXus.Utils
{
public class GxEmbedding
{

ReadOnlyMemory<float> _embedding;
public GxEmbedding()
{
}
public GxEmbedding(string model, int dimensions)
{
Model = model;
Dimensions = dimensions;
_embedding = new ReadOnlyMemory<float>(new float[dimensions]);
}
internal GxEmbedding(ReadOnlyMemory<float> embedding, string model, int dimensions) : this(model, dimensions)
{
_embedding = embedding;
}
internal GxEmbedding(float[] embedding)
{
_embedding = embedding;
}

internal static GxEmbedding Empty(string model, int dimensions)
{
return new GxEmbedding(model, dimensions);
}
public override string ToString()
{
return $"[{string.Join(",", _embedding.Span.ToArray())}]";
}
public static GxEmbedding GenerateEmbedding(GxEmbedding embeddingInfo, string text, GXBaseCollection<SdtMessages_Message> Messages)
{
try
{
ReadOnlyMemory<float> embedding = AIEmbeddingFactory.Instance.GenerateEmbeddingAsync(embeddingInfo.Model, embeddingInfo.Dimensions, text).GetAwaiter().GetResult();
return new GxEmbedding(embedding, embeddingInfo.Model, embeddingInfo.Dimensions);
}
catch (Exception ex)
{
GXUtil.ErrorToMessages("GenerateEmbedding Error", ex, Messages, false);
return embeddingInfo;
}
}
public string Model { get; set; }
public int Dimensions { get; set; }

internal ReadOnlyMemory<float> Data => _embedding;
}
internal interface IEmbeddingService
{
Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string model, int dimensions, string input);
}
internal class AIEmbeddingFactory
{
private static readonly IGXLogger log = GXLoggerFactory.GetLogger<AIEmbeddingFactory>();

private static volatile IEmbeddingService instance;
private static object syncRoot = new object();
private const string AI_PROVIDER = "GeneXus.AI.EmbeddingService, GxAI, Version=10.1.0.0, Culture=neutral, PublicKeyToken=null";
public static IEmbeddingService Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{

try
{
Type type = AssemblyLoader.GetType(AI_PROVIDER);
instance = (IEmbeddingService)Activator.CreateInstance(type);
}
catch (Exception e)
{
GXLogging.Error(log, "Couldn't create AI Provider", e);
throw e;
}
}
}
}
return instance;
}
}
}
}
5 changes: 4 additions & 1 deletion dotnet/src/dotnetcore/GxClasses/GxClasses.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
<Compile Include="..\..\dotnetframework\GxClasses\Data\GXDataDb2400.cs" Link="Data\GXDataDb2400.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Diagnostics\Log.cs" Link="Diagnostics\Log.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Diagnostics\GXDebugManager.cs" Link="Diagnostics\GXDebugManager.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\CallResult.cs" Link="Domain\CallResult.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\ChatMessage.cs" Link="Domain\ChatMessage.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\ChatResult.cs" Link="Domain\ChatResult.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GXLDAP.cs" Link="Domain\GXLDAP.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GxMessages.cs" Link="Domain\GxMessages.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GxMessaging.cs" Link="Domain\GxMessaging.cs" />
Expand Down Expand Up @@ -162,13 +165,13 @@
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.1.0" PrivateAssets="All" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" PrivateAssets="All" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" PrivateAssets="All" />
<PackageReference Include="Pgvector" Version="0.3.0" PrivateAssets="All" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Include="MySqlConnector" Version="2.2.3" PrivateAssets="All"/>
<PackageReference Include="NetTopologySuite" Version="2.0.0" />
<PackageReference Include="NodaTime" Version="3.1.9" />
<PackageReference Include="Novell.Directory.Ldap.NETStandard" Version="3.3.1" />
<PackageReference Include="Npgsql" Version="8.0.3" PrivateAssets="All"/>
<PackageReference Include="Sandwych.GeographicLib" Version="1.49.3" />
<PackageReference Include="Stubble.Core" Version="1.8.4" />
<PackageReference Include="System.DirectoryServices" Version="4.7.0" />
Expand Down
3 changes: 3 additions & 0 deletions dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@
[assembly: InternalsVisibleTo("DotNetCoreChunkedTest")]
[assembly: InternalsVisibleTo("DotNetCoreChunkedTest")]
[assembly: InternalsVisibleTo("GeneXus.OpenTelemetry.Diagnostics")]
[assembly: InternalsVisibleTo("ConsoleApp2")]
[assembly: InternalsVisibleTo("GxAI")]

15 changes: 15 additions & 0 deletions dotnet/src/dotnetcore/Providers/AI/GxAI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<PackageTags>Genexus AI</PackageTags>
<PackageId>GeneXus.AI.Core</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenAI" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\GxClasses\GxClasses.csproj" />
</ItemGroup>


</Project>
108 changes: 108 additions & 0 deletions dotnet/src/dotnetcore/Providers/AI/Model/GXAgent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using GeneXus.AI.Chat;
using GeneXus.Http.Client;
using GeneXus.Procedure;
using GeneXus.Utils;

namespace GeneXus.AI
{
public class GXAgent : GXProcedure
{
static readonly IGXLogger log = GXLoggerFactory.GetLogger<GXAgent>();

protected ChatResult ChatAgent(String agent, GXProperties properties, IList chatMessages, object result)
{
CallResult callResult = result as CallResult;
List<ChatMessage> chatMessagesList = chatMessages != null ? chatMessages.Cast<ChatMessage>().ToList() : null;
try
{
GXLogging.Debug(log, "Chatting Agent: ", agent);

GxHttpClient httpClient = AgentService.AgentHandlerInstance.ChatAgent(agent, chatMessagesList, properties, context);

return new ChatResult(this, agent, properties, chatMessagesList, callResult, httpClient);
}
catch (Exception ex)
{
callResult.AddMessage($"Error chatting Agent {agent}:" + ex.Message);
callResult.IsFail = true;
return new ChatResult(this, agent, properties, chatMessagesList, callResult, null);
}
}
protected string CallAgent(string assistant, GXProperties gxproperties, IList chatMessages, object result)
{
return CallAgent(assistant, gxproperties, chatMessages, result, false);
}
protected string CallAgent(string assistant, GXProperties gxproperties, IList chatMessages, object result, bool stream)
{
CallResult callResult = result as CallResult;
try
{
GXLogging.Debug(log, "Calling Agent: ", assistant);

List<ChatMessage> chatMessagesList = chatMessages!=null ? chatMessages.Cast<ChatMessage>().ToList() :null;
ChatCompletionResult chatCompletion = AgentService.AgentHandlerInstance.CallAgent(assistant, chatMessagesList, gxproperties, context).GetAwaiter().GetResult();

if (chatCompletion != null && chatCompletion.Choices != null)
{
foreach (Choice choice in chatCompletion.Choices)
{
switch (choice.FinishReason.ToLower())
{
case ChatCompletionResult.FINISH_REASON_STOP:
return choice.Message.Content;
case ChatCompletionResult.FINISH_REASON_TOOL_CALLS:
chatMessagesList.Add(choice.Message);
return ProcessChatResponse(choice, stream, assistant, gxproperties, chatMessagesList, result);
}
}
}
return string.Empty;
}
catch (Exception ex)
{
callResult.AddMessage($"Error calling Agent {assistant}:" + ex.Message);
callResult.IsFail = true;
return string.Empty;
}

}
internal override string ProcessChatResponse(Choice choice, bool stream, string assistant, GXProperties gxproperties, List<ChatMessage> chatMessagesList, object result)
{
foreach (ToolCall toolCall in choice.Message.ToolCalls)
ProcessToolCall(toolCall, chatMessagesList);
return CallAgent(assistant, gxproperties, chatMessagesList, result, stream);
}
private void ProcessToolCall(ToolCall toolCall, List<ChatMessage> messages)
{
string result = string.Empty;
string functionName = toolCall.Function.Name;
try
{
result = CallTool(functionName, toolCall.Function.Arguments);
}
catch (Exception ex)
{
GXLogging.Error(log, "Error calling tool ", functionName, ex);
result = $"Error calling tool {functionName}";
}
ChatMessage toolCallMessage = new ChatMessage
{
Role = "tool",
Content = result,
ToolCallId = toolCall.Id
};
messages.Add(toolCallMessage);
}
protected virtual string CallTool(string name, string arguments)
{
return string.Empty;
}


}
}
4 changes: 4 additions & 0 deletions dotnet/src/dotnetcore/Providers/AI/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("DotNetCoreUnitTest")]
[assembly: InternalsVisibleTo("ConsoleApp2")]
Loading
Loading