-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
234 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
Codeblaze.SemanticKernel.Console/Services/NeoKernelService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using Azure.AI.OpenAI; | ||
using Codeblaze.SemanticKernel.Connectors.AI.Ollama; | ||
using Codeblaze.SemanticKernel.Plugins.Neo4j; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.SemanticKernel; | ||
|
||
namespace Codeblaze.SemanticKernel.Console.Services; | ||
|
||
public class NeoKernelService | ||
{ | ||
private readonly Kernel _Kernel; | ||
private readonly Neo4jPlugin _plugin; | ||
|
||
public NeoKernelService(IConfiguration config) | ||
{ | ||
var builder = new KernelBuilder(); | ||
|
||
builder.AddOpenAIChatCompletion(config["OpenAI:Model"], config["OpenAI:Key"]); | ||
|
||
_Kernel = builder.Build(); | ||
|
||
_plugin = new Neo4jPlugin(_Kernel, config["Neo4j:Url"], config["Neo4j:Username"], config["Neo4j:Password"]); | ||
} | ||
|
||
public string GetSchema() | ||
{ | ||
return _plugin.Schema; | ||
} | ||
|
||
public Task<string> GenerateCypher(string prompt) | ||
{ | ||
return _plugin.GenerateCypher(prompt); | ||
} | ||
|
||
public Task<NeoResult> Run(string prompt) | ||
{ | ||
return _plugin.Run(prompt); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
Codeblaze.SemanticKernel.Plugins.Neo4j/Codeblaze.SemanticKernel.Plugins.Neo4j.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.0.0-rc3" /> | ||
<PackageReference Include="Neo4j.Driver" Version="5.15.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
using System.Text.Json; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.AI.ChatCompletion; | ||
using Neo4j.Driver; | ||
|
||
namespace Codeblaze.SemanticKernel.Plugins.Neo4j; | ||
|
||
public class NeoResult | ||
{ | ||
public bool Success { get; set; } | ||
public string? Cypher { get; set; } | ||
public List<IRecord>? Result { get; set; } | ||
} | ||
|
||
public class Neo4jPlugin | ||
{ | ||
private readonly IDriver _driver; | ||
private readonly IChatCompletionService _chat; | ||
|
||
public string Schema { get; } | ||
|
||
private const string NODE_PROPS_QUERY = """ | ||
CALL apoc.meta.data() | ||
YIELD label, other, elementType, type, property | ||
WHERE NOT type = "RELATIONSHIP" AND elementType = "node" | ||
WITH label AS nodeLabels, collect(property) AS properties | ||
RETURN {labels: nodeLabels, properties: properties} AS output | ||
"""; | ||
|
||
private const string REL_PROPS_QUERY = """ | ||
CALL apoc.meta.data() | ||
YIELD label, other, elementType, type, property | ||
WHERE NOT type = "RELATIONSHIP" AND elementType = "relationship" | ||
WITH label AS nodeLabels, collect(property) AS properties | ||
RETURN {type: nodeLabels, properties: properties} AS output | ||
"""; | ||
|
||
private const string REL_QUERY = """ | ||
CALL apoc.meta.data() | ||
YIELD label, other, elementType, type, property | ||
WHERE type = "RELATIONSHIP" AND elementType = "node" | ||
RETURN {source: label, relationship: property, target: other} AS output | ||
"""; | ||
|
||
public Neo4jPlugin(Kernel kernel, string url, string username, string password) | ||
{ | ||
_driver = GraphDatabase.Driver(url, AuthTokens.Basic(username, password)); | ||
_chat = kernel.GetRequiredService<IChatCompletionService>(); | ||
|
||
Schema = GetSchema().GetAwaiter().GetResult(); | ||
} | ||
|
||
private async Task<string> GetSchema() | ||
{ | ||
|
||
var node_props = JsonSerializer.Serialize((await Query(NODE_PROPS_QUERY)).Select(x => x.Values["output"]).ToList()); | ||
var rel_props = JsonSerializer.Serialize((await Query(REL_PROPS_QUERY)).Select(x => x.Values["output"]).ToList()); | ||
var rels = JsonSerializer.Serialize((await Query(REL_QUERY)).Select(x => x.Values["output"]).ToList()); | ||
|
||
return $""" | ||
This is the schema representation of the Neo4j database. | ||
Node properties are the following: | ||
{node_props} | ||
Relationship properties are the following: | ||
{rel_props} | ||
Relationship point from source to target nodes | ||
{rels} | ||
Make sure to respect relationship types and directions | ||
"""; | ||
} | ||
|
||
public async Task<string> GenerateCypher(string prompt) | ||
{ | ||
var system = $""" | ||
Task: Generate Cypher queries to query a Neo4j graph database based on the provided schema definition. | ||
Instructions: | ||
Use only the provided relationship types and properties. | ||
Do not use any other relationship types or properties that are not provided. | ||
If you cannot generate a Cypher statement based on the provided schema, explain the reason to the user. | ||
Schema: | ||
{Schema} | ||
|
||
Note: Do not include any explanations or apologies in your responses. | ||
"""; | ||
|
||
var history = new ChatHistory | ||
{ | ||
new(AuthorRole.System, system), | ||
new(AuthorRole.User, prompt) | ||
}; | ||
|
||
var result = await _chat.GetChatMessageContentsAsync(history); | ||
|
||
return result[0].Content; | ||
} | ||
|
||
public async Task<NeoResult> Run(string prompt) | ||
{ | ||
var cypher = await GenerateCypher(prompt); | ||
|
||
try | ||
{ | ||
var result = await Query(cypher); | ||
|
||
return new NeoResult | ||
{ | ||
Success = true, | ||
Cypher = cypher, | ||
Result = result | ||
}; | ||
} | ||
catch | ||
{ | ||
return new NeoResult { Success = false, Cypher = cypher }; | ||
} | ||
} | ||
|
||
private async Task<List<IRecord>> Query(string query) | ||
{ | ||
await using var session = _driver.AsyncSession(o => o.WithDatabase("neo4j")); | ||
|
||
return await session.ExecuteReadAsync(async transaction => | ||
{ | ||
var cursor = await transaction.RunAsync(query); | ||
return await cursor.ToListAsync(); | ||
}); | ||
} | ||
|
||
|
||
} |
11 changes: 11 additions & 0 deletions
11
Codeblaze.SemanticKernel.Plugins.Neo4j/Neo4jPluginBuilderExtension.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.SemanticKernel; | ||
|
||
namespace Codeblaze.SemanticKernel.Plugins.Neo4j; | ||
|
||
public static class Neo4jPluginBuilderExtension | ||
{ | ||
public static void AddNeo4jPlugin(this IServiceCollection services, string url, string username, string password) | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters