├── .github
└── workflows
│ ├── dotnet-build.yml
│ └── dotnet-publish.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── dotnet
├── .dockerignore
├── .gitignore
├── .idea
│ ├── .gitignore
│ ├── .idea.Codeblaze.SemanticKernel
│ │ └── .idea
│ │ │ ├── .gitignore
│ │ │ ├── .name
│ │ │ ├── encodings.xml
│ │ │ ├── indexLayout.xml
│ │ │ └── vcs.xml
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── Codeblaze.SemanticKernel.Api
│ ├── Codeblaze.SemanticKernel.Api.csproj
│ ├── Codeblaze.SemanticKernel.Api.http
│ ├── Dockerfile
│ ├── Program.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Codeblaze.SemanticKernel.Connectors.Memory.Neo4j
│ ├── Codeblaze.SemanticKernel.Connectors.Memory.Neo4j.csproj
│ ├── INeo4jQueryFactory.cs
│ ├── Neo4jMemoryBuilderExtension.cs
│ ├── Neo4jMemoryStore.cs
│ └── README.md
├── Codeblaze.SemanticKernel.Connectors.Ollama
│ ├── ChatCompletion
│ │ ├── OllamaChatCompletionService.cs
│ │ ├── OllamaChatRequestMessage.cs
│ │ └── OllamaChatResponseMessage.cs
│ ├── Codeblaze.SemanticKernel.Connectors.Ollama.csproj
│ ├── Codeblaze.SemanticKernel.Connectors.Ollama.csproj.DotSettings
│ ├── EmbeddingGeneration
│ │ └── OllamaTextEmbeddingGeneration.cs
│ ├── OllamaBase.cs
│ ├── OllamaKernelBuilderExtensions.cs
│ ├── OllamaMemoryBuilderExtensions.cs
│ ├── OllamaPromptExecutionSettings.cs
│ ├── OllamaResponseMessage.cs
│ ├── README.md
│ └── TextGenerationService
│ │ └── OllamaTextGenerationService.cs
├── Codeblaze.SemanticKernel.Console
│ ├── .gitignore
│ ├── Codeblaze.SemanticKernel.Console.csproj
│ ├── Dockerfile
│ ├── Program.cs
│ └── Services
│ │ ├── KernelService.cs
│ │ ├── NeoKernelService.cs
│ │ └── NeoMemoryService.cs
├── Codeblaze.SemanticKernel.Plugins.Neo4j
│ ├── Codeblaze.SemanticKernel.Plugins.Neo4j.csproj
│ ├── Neo4jCypherGenPlugin.cs
│ ├── Neo4jPluginBuilderExtension.cs
│ └── README.md
├── Codeblaze.SemanticKernel.sln
├── Codeblaze.SemanticKernel.sln.DotSettings
└── global.json
├── java
└── .gitkeep
└── python
└── .gitkeep
/.github/workflows/dotnet-build.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2 |
3 | name: dotnet-build
4 |
5 | on:
6 | workflow_dispatch: # Allow running the workflow manually from the GitHub UI
7 | pull_request:
8 | branches:
9 | - 'main'
10 | push:
11 | branches:
12 | - 'main' # Run the workflow when pushing to the main branch
13 |
14 | env:
15 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
16 | DOTNET_NOLOGO: true
17 | NuGetDirectory: ${{ github.workspace }}/dotnet/nuget
18 |
19 | defaults:
20 | run:
21 | working-directory: ./dotnet
22 | shell: pwsh
23 |
24 | jobs:
25 | create_nuget:
26 | runs-on: ubuntu-latest
27 | steps:
28 | - uses: actions/checkout@v3
29 | with:
30 | fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
31 |
32 | # Install the .NET SDK indicated in the global.json file
33 | - name: Setup .NET
34 | uses: actions/setup-dotnet@v3
35 |
36 | # Create the NuGet package in the folder from the environment variable NuGetDirectory
37 | - run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
38 |
39 | # Publish the NuGet package as an artifact, so they can be used in the following jobs
40 | - uses: actions/upload-artifact@v3
41 | with:
42 | name: nuget
43 | if-no-files-found: error
44 | retention-days: 7
45 | path: ${{ env.NuGetDirectory }}/*.nupkg
46 |
47 | validate_nuget:
48 | runs-on: ubuntu-latest
49 | needs: [ create_nuget ]
50 | steps:
51 | # Install the .NET SDK indicated in the global.json file
52 | - name: Setup .NET
53 | uses: actions/setup-dotnet@v3
54 |
55 | # Download the NuGet package created in the previous job
56 | - uses: actions/download-artifact@v3
57 | with:
58 | name: nuget
59 | path: ${{ env.NuGetDirectory }}
60 |
61 | - name: Install nuget validator
62 | run: dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global
63 |
64 | # Validate metadata and content of the NuGet package
65 | # https://www.nuget.org/packages/Meziantou.Framework.NuGetPackageValidation.Tool#readme-body-tab
66 | # If some rules are not applicable, you can disable them
67 | # using the --excluded-rules or --excluded-rule-ids option
68 | - name: Validate package
69 | run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg") --excluded-rules=IconMustBeSet,ProjectUrlMustBeSet,Symbols
70 |
71 | # run_test:
72 | # runs-on: ubuntu-latest
73 | # steps:
74 | # - uses: actions/checkout@v3
75 | # - name: Setup .NET
76 | # uses: actions/setup-dotnet@v3
77 | # - name: Run tests
78 | # run: dotnet test --configuration Release
--------------------------------------------------------------------------------
/.github/workflows/dotnet-publish.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2 |
3 | name: dotnet-publish
4 |
5 | on:
6 | push:
7 | tags:
8 | - "v*"
9 |
10 | env:
11 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
12 | DOTNET_NOLOGO: true
13 | NuGetDirectory: ${{ github.workspace }}/dotnet/nuget
14 |
15 | defaults:
16 | run:
17 | working-directory: ./dotnet
18 | shell: pwsh
19 |
20 | jobs:
21 | create_nuget:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v3
25 | with:
26 | fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
27 |
28 | # Install the .NET SDK indicated in the global.json file
29 | - name: Setup .NET
30 | uses: actions/setup-dotnet@v3
31 |
32 | # Create the NuGet package in the folder from the environment variable NuGetDirectory
33 | - run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
34 |
35 | # Publish the NuGet package as an artifact, so they can be used in the following jobs
36 | - uses: actions/upload-artifact@v3
37 | with:
38 | name: nuget
39 | if-no-files-found: error
40 | retention-days: 7
41 | path: ${{ env.NuGetDirectory }}/*.nupkg
42 |
43 | validate_nuget:
44 | runs-on: ubuntu-latest
45 | needs: [ create_nuget ]
46 | steps:
47 | # Install the .NET SDK indicated in the global.json file
48 | - name: Setup .NET
49 | uses: actions/setup-dotnet@v3
50 |
51 | # Download the NuGet package created in the previous job
52 | - uses: actions/download-artifact@v3
53 | with:
54 | name: nuget
55 | path: ${{ env.NuGetDirectory }}
56 |
57 | - name: Install nuget validator
58 | run: dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global
59 |
60 | # Validate metadata and content of the NuGet package
61 | # https://www.nuget.org/packages/Meziantou.Framework.NuGetPackageValidation.Tool#readme-body-tab
62 | # If some rules are not applicable, you can disable them
63 | # using the --excluded-rules or --excluded-rule-ids option
64 | - name: Validate package
65 | run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg") --excluded-rules=IconMustBeSet,ProjectUrlMustBeSet,Symbols
66 |
67 | # run_test:
68 | # runs-on: ubuntu-latest
69 | # steps:
70 | # - uses: actions/checkout@v3
71 | # - name: Setup .NET
72 | # uses: actions/setup-dotnet@v3
73 | # - name: Run tests
74 | # run: dotnet test --configuration Release
75 |
76 | deploy:
77 | # Publish only when a tag is pushed
78 | # https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
79 | # You can update this logic if you want to manage releases differently
80 | runs-on: ubuntu-latest
81 | needs: [ validate_nuget ] #run_test
82 | steps:
83 | # Download the NuGet package created in the previous job
84 | - uses: actions/download-artifact@v3
85 | with:
86 | name: nuget
87 | path: ${{ env.NuGetDirectory }}
88 |
89 | # Install the .NET SDK indicated in the global.json file
90 | - name: Setup .NET Core
91 | uses: actions/setup-dotnet@v3
92 |
93 | # Publish all NuGet packages to NuGet.org
94 | # Use --skip-duplicate to prevent errors if a package with the same version already exists.
95 | # If you retry a failed workflow, already published packages will be skipped without error.
96 | - name: Publish NuGet package
97 | run: |
98 | foreach($file in (Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg)) {
99 | dotnet nuget push $file --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate
100 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac desktop service store files
2 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Devashish Lal
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeBlaze's Semantic Kernel Plugins
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | | Plugin | Dotnet | Python | Java |
16 | |---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|------|
17 | | Ollama Connector |
| | |
18 | | Neo4J Memory |
| | |
19 | | Neo4j Cypher Plugin |
| | |
20 |
--------------------------------------------------------------------------------
/dotnet/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.dockerignore
2 | **/.env
3 | **/.git
4 | **/.gitignore
5 | **/.project
6 | **/.settings
7 | **/.toolstarget
8 | **/.vs
9 | **/.vscode
10 | **/.idea
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/dotnet/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 | .vs/
9 | *.VC.db
10 |
11 | # Build results
12 | [Aa]rtifacts/
13 | [Dd]ebug/
14 | [Rr]elease/
15 | x64/
16 | [Bb]in/
17 | [Oo]bj/
18 | .dotnet/
19 | .tools/
20 | src/Templates/**/ModifiedTemplates/
21 | .packages/
22 |
23 | # Per-user project properties
24 | launchSettings.json
25 |
26 | *_i.c
27 | *_p.c
28 | *.ilk
29 | *.meta
30 | *.obj
31 | *.pch
32 | *.pdb
33 | *.pgc
34 | *.pgd
35 | *.sbr
36 | *.tlb
37 | *.tli
38 | *.tlh
39 | *.tmp
40 | *.tmp_proj
41 | *.log
42 | *.wrn
43 | *.vspscc
44 | *.vssscc
45 | .builds
46 | *.pidb
47 | *.log
48 | *.scc
49 |
50 | # Visual C++ cache files
51 | ipch/
52 | *.aps
53 | *.ncb
54 | *.opensdf
55 | *.sdf
56 | *.cachefile
57 | *.VC.opendb
58 |
59 | # Visual Studio profiler
60 | *.psess
61 | *.vsp
62 | *.vspx
63 |
64 | # Guidance Automation Toolkit
65 | *.gpState
66 |
67 | # ReSharper is a .NET coding add-in
68 | _ReSharper*/
69 | *.[Rr]e[Ss]harper
70 |
71 | # TeamCity is a build add-in
72 | _TeamCity*
73 |
74 | # DotCover is a Code Coverage Tool
75 | *.dotCover
76 |
77 | # NCrunch
78 | *.ncrunch*
79 | .*crunch*.local.xml
80 |
81 | # Others
82 | sql/
83 | *.Cache
84 | ClientBin/
85 | [Ss]tyle[Cc]op.*
86 | ~$*
87 | *~
88 | *.dbmdl
89 | *.[Pp]ublish.xml
90 | *.pfx
91 | *.publishsettings
92 |
93 | # SQL Server files
94 | App_Data/*.mdf
95 | App_Data/*.ldf
96 |
97 | # =========================
98 | # Windows detritus
99 | # =========================
100 |
101 | # Windows image file caches
102 | Thumbs.db
103 | ehthumbs.db
104 |
105 | # Folder config file
106 | Desktop.ini
107 |
108 | # Recycle Bin used on file shares
109 | $RECYCLE.BIN/
110 |
111 | # Mac desktop service store files
112 | .DS_Store
--------------------------------------------------------------------------------
/dotnet/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /modules.xml
6 | /contentModel.xml
7 | /projectSettingsUpdater.xml
8 | /.idea.Codeblaze.SemanticKernel.iml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/dotnet/.idea/.idea.Codeblaze.SemanticKernel/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /projectSettingsUpdater.xml
6 | /modules.xml
7 | /.idea.Codeblaze.SemanticKernel.iml
8 | /contentModel.xml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/dotnet/.idea/.idea.Codeblaze.SemanticKernel/.idea/.name:
--------------------------------------------------------------------------------
1 | Codeblaze.SemanticKernel
--------------------------------------------------------------------------------
/dotnet/.idea/.idea.Codeblaze.SemanticKernel/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/dotnet/.idea/.idea.Codeblaze.SemanticKernel/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/dotnet/.idea/.idea.Codeblaze.SemanticKernel/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/dotnet/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/dotnet/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/dotnet/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/Codeblaze.SemanticKernel.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 | true
8 | Linux
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | .dockerignore
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/Codeblaze.SemanticKernel.Api.http:
--------------------------------------------------------------------------------
1 | @Codeblaze.SemanticKernel.Api_HostAddress = http://localhost:5144
2 |
3 | GET {{Codeblaze.SemanticKernel.Api_HostAddress}}/weatherforecast/
4 | Accept: application/json
5 |
6 | ###
7 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
2 | USER $APP_UID
3 | WORKDIR /app
4 | EXPOSE 8080
5 | EXPOSE 8081
6 |
7 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
8 | ARG BUILD_CONFIGURATION=Release
9 | WORKDIR /src
10 | COPY ["Codeblaze.SemanticKernel.Api/Codeblaze.SemanticKernel.Api.csproj", "Codeblaze.SemanticKernel.Api/"]
11 | RUN dotnet restore "Codeblaze.SemanticKernel.Api/Codeblaze.SemanticKernel.Api.csproj"
12 | COPY . .
13 | WORKDIR "/src/Codeblaze.SemanticKernel.Api"
14 | RUN dotnet build "Codeblaze.SemanticKernel.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
15 |
16 | FROM build AS publish
17 | ARG BUILD_CONFIGURATION=Release
18 | RUN dotnet publish "Codeblaze.SemanticKernel.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
19 |
20 | FROM base AS final
21 | WORKDIR /app
22 | COPY --from=publish /app/publish .
23 | ENTRYPOINT ["dotnet", "Codeblaze.SemanticKernel.Api.dll"]
24 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
5 | builder.Services.AddEndpointsApiExplorer();
6 | builder.Services.AddSwaggerGen();
7 |
8 | var app = builder.Build();
9 |
10 | // Configure the HTTP request pipeline.
11 | if (app.Environment.IsDevelopment())
12 | {
13 | app.UseSwagger();
14 | app.UseSwaggerUI();
15 | }
16 |
17 | app.UseHttpsRedirection();
18 |
19 | var summaries = new[]
20 | {
21 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
22 | };
23 |
24 | app.MapGet("/weatherforecast", () =>
25 | {
26 | var forecast = Enumerable.Range(1, 5).Select(index =>
27 | new WeatherForecast
28 | (
29 | DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
30 | Random.Shared.Next(-20, 55),
31 | summaries[Random.Shared.Next(summaries.Length)]
32 | ))
33 | .ToArray();
34 | return forecast;
35 | })
36 | .WithName("GetWeatherForecast")
37 | .WithOpenApi();
38 |
39 | app.Run();
40 |
41 | record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
42 | {
43 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
44 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | Latest
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 | all
20 |
21 |
22 |
23 |
24 |
25 | Codeblaze.SemanticKernel.Connectors.Memory.Neo4j
26 | Codeblaze (Devashish Lal)
27 | SemanticKernel;Neo4j;Memory;Embeddings;AI
28 |
29 | This package provides a Neo4j Memory store for semantic kernel capable of storing and retriving vector embeddings
30 |
31 | https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel
32 | git
33 | README.md
34 | LICENSE.md
35 | v
36 |
37 |
38 |
39 | true
40 | true
41 |
42 |
43 |
44 | $(NoWarn);1591
45 | bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j/INeo4jQueryFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel;
2 |
3 | namespace Codeblaze.SemanticKernel.Connectors.Memory.Neo4j;
4 |
5 | public interface INeo4jQueryFactory
6 | {
7 | public IDictionary DynamicProperties { get; }
8 | public string IndexName { get; }
9 | public string NodeName { get; }
10 | public string TextProperty { get; }
11 | public string IndexProperty { get; }
12 | public int Dimensions { get; }
13 | (string, object) ListIndexQuery();
14 | (string, object) CreateIndexQuery(string collectionName);
15 | (string, object) DropIndexQuery(string collectionName);
16 | (string, object) UpsertQuery(string collectionName, int key, ReadOnlyMemory embedding);
17 | (string, object) UpsertBatchQuery(string collectionName, IEnumerable keys,
18 | IEnumerable> embeddings);
19 | (string, object) GetQuery(string collectionName, int keys);
20 | (string, object) GetBatchQuery(string collectionName, IEnumerable keys);
21 | (string, object) RemoveQuery(string collectionName, int keys);
22 | (string, object) RemoveBatchQuery(string collectionName, IEnumerable keys);
23 | (string, object) GetNearestMatchQuery(string collectionName, ReadOnlyMemory embedding,
24 | double minRelevanceScore, int limit = 1);
25 | }
26 |
27 | public abstract class Neo4jVectorQueries
28 | {
29 | public const string ListIndexQuery = "SHOW VECTOR INDEXES YIELD name";
30 |
31 | public const string CreateIndexQuery = """
32 | CREATE VECTOR INDEX `$name`
33 | FOR (n:$node) ON (n.$indexProperty)
34 | OPTIONS {indexConfig: {
35 | `vector.dimensions`: $dimensions,
36 | `vector.similarity_function`: 'cosine'
37 | }
38 | """;
39 |
40 | public const string DropIndexQuery = "DROP INDEX $name";
41 |
42 | public const string GetNearestMatchQuery = """
43 | CALL db.index.vector.queryNodes($name, $limit, $embedding)
44 | YIELD node, score
45 | WHERE score >= $minRelevanceScore
46 | RETURN node.id AS id, score
47 | """;
48 |
49 | public const string UpsertQuery = """
50 | MATCH (n {id: $id})
51 | CALL db.create.setNodeVectorProperty(n, $indexProperty, $embedding)
52 | RETURN node.id AS id
53 | """;
54 |
55 | public const string UpsertBatchQuery = """
56 | UNWIND $updates AS update,
57 | MATCH (n {id: update.id})
58 | CALL db.create.setNodeVectorProperty(n, $indexProperty, update.embedding)
59 | RETURN node.id AS id
60 | """;
61 |
62 | public const string GetQuery = """
63 | MATCH (n {id: $id})
64 | RETURN n
65 | """;
66 |
67 | public const string GetBatchQuery = """
68 | UNWIND $ids AS id
69 | MATCH (n {id: id})
70 | RETURN n
71 | """;
72 |
73 | public const string RemoveQuery = """
74 | MATCH (n {id: $id})
75 | DELETE n
76 | """;
77 |
78 | public const string RemoveBatchQuery = """
79 | UNWIND $ids AS id
80 | MATCH (n {id: id})
81 | DELETE n
82 | """;
83 | }
84 |
85 | ///
86 | /// Neo4j 5.15 or above is supported by this query factory, vector functionality was introduced in an earlier version of neo4j
87 | /// If you are using an old version you may need to implement some of the queries below using old cypher, refer neo4j docs
88 | ///
89 | /// Index name
90 | /// Node on which index is created
91 | /// Property of the node on which index is created
92 | /// Vector index dimensions
93 | public class Neo4jVectorIndexQueryFactory(string name, string node, string indexProperty, string textProperty, int dimensions)
94 | : INeo4jQueryFactory
95 | {
96 | ///
97 | /// This can be updated at runtime to pass different values to the query factory
98 | /// To use dynamic properties the default query methods need to be overriden
99 | /// and the dynamic property must be returned along with the new query
100 | ///
101 | public IDictionary DynamicProperties { get; } = new Dictionary();
102 | public string IndexName => name;
103 | public string NodeName => node;
104 | public string TextProperty => textProperty;
105 | public string IndexProperty => indexProperty;
106 | public int Dimensions => dimensions;
107 |
108 | public virtual (string, object) ListIndexQuery()
109 | {
110 | return (Neo4jVectorQueries.ListIndexQuery, null);
111 | }
112 |
113 | public virtual (string, object) CreateIndexQuery(string collectionName)
114 | {
115 | if (name != collectionName)
116 | throw new KernelException(
117 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
118 |
119 | return (Neo4jVectorQueries.CreateIndexQuery, new
120 | {
121 | name, node, indexProperty, dimensions
122 | }
123 | );
124 | }
125 |
126 | public virtual (string, object) DropIndexQuery(string collectionName)
127 | {
128 | if (name != collectionName)
129 | throw new KernelException(
130 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
131 |
132 | return (Neo4jVectorQueries.DropIndexQuery, new { name });
133 | }
134 |
135 | public (string, object) UpsertQuery(string collectionName, int key, ReadOnlyMemory embedding)
136 | {
137 | if (name != collectionName)
138 | throw new KernelException(
139 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
140 |
141 | return (Neo4jVectorQueries.UpsertQuery, new { id = key, embedding });
142 | }
143 |
144 | public (string, object) UpsertBatchQuery(string collectionName, IEnumerable keys, IEnumerable> embeddings)
145 | {
146 | if (name != collectionName)
147 | throw new KernelException(
148 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
149 |
150 | var updates = keys.Zip(embeddings, (id, embedding) => new { id, embedding }).ToArray();
151 |
152 | return (Neo4jVectorQueries.UpsertBatchQuery, new { updates });
153 | }
154 |
155 | public virtual (string, object) GetQuery(string collectionName, int key)
156 | {
157 | if (name != collectionName)
158 | throw new KernelException(
159 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
160 |
161 | return (Neo4jVectorQueries.GetQuery, new { id = key });
162 | }
163 |
164 | public virtual (string, object) GetBatchQuery(string collectionName, IEnumerable keys)
165 | {
166 | if (name != collectionName)
167 | throw new KernelException(
168 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
169 |
170 | return (Neo4jVectorQueries.GetBatchQuery, new { ids = keys.ToArray() });
171 | }
172 |
173 | public virtual (string, object) RemoveQuery(string collectionName, int key)
174 | {
175 | if (name != collectionName)
176 | throw new KernelException(
177 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
178 |
179 | return (Neo4jVectorQueries.RemoveQuery, new { id = key });
180 | }
181 |
182 | public virtual (string, object) RemoveBatchQuery(string collectionName, IEnumerable keys)
183 | {
184 | if (name != collectionName)
185 | throw new KernelException(
186 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
187 |
188 | return (Neo4jVectorQueries.RemoveBatchQuery, new { ids = keys });
189 | }
190 |
191 | public virtual (string, object) GetNearestMatchQuery(string collectionName, ReadOnlyMemory embedding,
192 | double minRelevanceScore, int limit = 1)
193 | {
194 | if (name != collectionName)
195 | throw new KernelException(
196 | $"Kernel passed {collectionName} index but query factory is configured with {name} index");
197 |
198 | return (Neo4jVectorQueries.GetNearestMatchQuery, new
199 | {
200 | name,
201 | limit,
202 | embedding = embedding.ToArray(),
203 | minRelevanceScore
204 | });
205 | }
206 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j/Neo4jMemoryBuilderExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel.Memory;
2 |
3 | namespace Codeblaze.SemanticKernel.Connectors.Memory.Neo4j;
4 |
5 | #pragma warning disable SKEXP0003
6 | public static class Neo4jMemoryBuilderExtension
7 | {
8 | public static MemoryBuilder WithNeo4jMemoryStore(this MemoryBuilder builder, string url, string username, string password, INeo4jQueryFactory queryFactory)
9 | {
10 | builder.WithMemoryStore(_ => new Neo4jMemoryStore(url, username, password, queryFactory));
11 |
12 | return builder;
13 | }
14 | }
15 | #pragma warning enable SKEXP0003
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j/Neo4jMemoryStore.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel.Memory;
2 | using Neo4j.Driver;
3 |
4 | namespace Codeblaze.SemanticKernel.Connectors.Memory.Neo4j;
5 |
6 | ///
7 | /// Collection in Neo4j context refers to index
8 | ///
9 | #pragma warning disable SKEXP0003
10 | public class Neo4jMemoryStore : IMemoryStore, IDisposable
11 | {
12 | private readonly IDriver _driver;
13 | private readonly INeo4jQueryFactory _queryFactory;
14 |
15 | public Neo4jMemoryStore(string url, string username, string password, INeo4jQueryFactory queryFactory)
16 | {
17 | _driver = GraphDatabase.Driver(url, AuthTokens.Basic(username, password));
18 | _queryFactory = queryFactory;
19 | }
20 |
21 | public async Task CreateCollectionAsync(string collectionName,
22 | CancellationToken cancellationToken = new CancellationToken())
23 | {
24 | if (await DoesCollectionExistAsync(collectionName, cancellationToken)) return;
25 |
26 | var (query, props) = _queryFactory.CreateIndexQuery(collectionName);
27 |
28 | await using var session = _driver.AsyncSession();
29 |
30 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
31 |
32 | await cursor.ConsumeAsync().ConfigureAwait(false);
33 | }
34 |
35 | public async IAsyncEnumerable GetCollectionsAsync(
36 | CancellationToken cancellationToken = new CancellationToken())
37 | {
38 | var indexes = await GetIndexesAsync().ConfigureAwait(false);
39 |
40 | foreach (var record in indexes)
41 | {
42 | yield return record.As();
43 | }
44 | }
45 |
46 | public async Task DoesCollectionExistAsync(string collectionName,
47 | CancellationToken cancellationToken = new CancellationToken())
48 | {
49 | var indexes = await GetIndexesAsync().ConfigureAwait(false);
50 |
51 | return indexes.Contains(collectionName);
52 | }
53 |
54 | public async Task DeleteCollectionAsync(string collectionName,
55 | CancellationToken cancellationToken = new CancellationToken())
56 | {
57 | if (await DoesCollectionExistAsync(collectionName, cancellationToken)) return;
58 |
59 | var (query, props) = _queryFactory.DropIndexQuery(collectionName);
60 |
61 | await using var session = _driver.AsyncSession();
62 |
63 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
64 |
65 | await cursor.ConsumeAsync().ConfigureAwait(false);
66 | }
67 |
68 | public async Task UpsertAsync(string collectionName, MemoryRecord record,
69 | CancellationToken cancellationToken = new CancellationToken())
70 | {
71 | var (query, props) = _queryFactory.UpsertQuery(collectionName, int.Parse(record.Key), record.Embedding);
72 |
73 | await using var session = _driver.AsyncSession();
74 |
75 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
76 |
77 | var result = await cursor.SingleAsync().ConfigureAwait(false);
78 |
79 | return result["id"].As();
80 | }
81 |
82 | public async IAsyncEnumerable UpsertBatchAsync(string collectionName, IEnumerable records,
83 | CancellationToken cancellationToken = new CancellationToken())
84 | {
85 | var (query, props) = _queryFactory.UpsertBatchQuery(
86 | collectionName,
87 | records.Select(x => int.Parse(x.Key)),
88 | records.Select(x => x.Embedding)
89 | );
90 |
91 | await using var session = _driver.AsyncSession();
92 |
93 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
94 |
95 | var results = await cursor.ToListAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
96 |
97 | foreach (var result in results)
98 | {
99 | yield return result["id"].As();
100 | }
101 | }
102 |
103 | public async Task GetAsync(string collectionName, string key, bool withEmbedding = false,
104 | CancellationToken cancellationToken = new CancellationToken())
105 | {
106 | var (query, props) = _queryFactory.GetQuery(collectionName, int.Parse(key));
107 |
108 | await using var session = _driver.AsyncSession();
109 |
110 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
111 |
112 | var record = await cursor.SingleAsync().ConfigureAwait(false);
113 |
114 | var node = record["n"].As();
115 |
116 | var id = node["id"].As();
117 | var embedding = withEmbedding
118 | ? new ReadOnlyMemory(node[_queryFactory.IndexProperty].As())
119 | : ReadOnlyMemory.Empty;
120 |
121 | return new MemoryRecord(
122 | new MemoryRecordMetadata(
123 | true,
124 | id,
125 | node[_queryFactory.TextProperty].As(),
126 | "", "neo4j",
127 | ""
128 | ),
129 | embedding,
130 | id
131 | );
132 | }
133 |
134 | public async IAsyncEnumerable GetBatchAsync(string collectionName, IEnumerable keys,
135 | bool withEmbeddings = false,
136 | CancellationToken cancellationToken = new CancellationToken())
137 | {
138 | var (query, props) = _queryFactory.GetBatchQuery(collectionName, keys.Select(int.Parse));
139 |
140 | await using var session = _driver.AsyncSession();
141 |
142 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
143 |
144 | var result = await cursor.ToListAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
145 |
146 | foreach (var record in result)
147 | {
148 | var node = record["n"].As();
149 |
150 | var id = node["id"].As();
151 | var embedding = withEmbeddings
152 | ? new ReadOnlyMemory(node[_queryFactory.IndexProperty].As())
153 | : ReadOnlyMemory.Empty;
154 |
155 | yield return new MemoryRecord(
156 | new MemoryRecordMetadata(
157 | true,
158 | id,
159 | node[_queryFactory.TextProperty].As(),
160 | "", "neo4j",
161 | ""
162 | ),
163 | embedding,
164 | id
165 | );
166 | }
167 | }
168 |
169 | public async Task RemoveAsync(string collectionName, string key,
170 | CancellationToken cancellationToken = new CancellationToken())
171 | {
172 | var (query, props) = _queryFactory.RemoveQuery(collectionName, int.Parse(key));
173 |
174 | await using var session = _driver.AsyncSession();
175 |
176 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
177 |
178 | await cursor.ConsumeAsync();
179 | }
180 |
181 | public async Task RemoveBatchAsync(string collectionName, IEnumerable keys,
182 | CancellationToken cancellationToken = new CancellationToken())
183 | {
184 | var (query, props) = _queryFactory.RemoveBatchQuery(collectionName, keys.Select(int.Parse));
185 |
186 | await using var session = _driver.AsyncSession();
187 |
188 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
189 |
190 | await cursor.ConsumeAsync();
191 | }
192 |
193 | public async IAsyncEnumerable<(MemoryRecord, double)> GetNearestMatchesAsync(string collectionName,
194 | ReadOnlyMemory embedding, int limit,
195 | double minRelevanceScore = 0, bool withEmbeddings = false,
196 | CancellationToken cancellationToken = new CancellationToken())
197 | {
198 | var (query, props) = _queryFactory.GetNearestMatchQuery(collectionName, embedding, minRelevanceScore, limit);
199 |
200 | await using var session = _driver.AsyncSession();
201 |
202 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
203 |
204 | // Should use Async Linq and stream
205 | var result = await cursor.ToListAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
206 |
207 | foreach (var record in result)
208 | {
209 | var score = record["score"].As();
210 | var id = record["id"].As();
211 |
212 | yield return (
213 | new MemoryRecord(
214 | new MemoryRecordMetadata(true, id, "", "", "neo4j", ""), embedding, id
215 | ),
216 | score);
217 | }
218 | }
219 |
220 | public async Task<(MemoryRecord, double)?> GetNearestMatchAsync(string collectionName,
221 | ReadOnlyMemory embedding,
222 | double minRelevanceScore = 0,
223 | bool withEmbedding = false, CancellationToken cancellationToken = new CancellationToken())
224 | {
225 | var (query, props) = _queryFactory.GetNearestMatchQuery(collectionName, embedding, minRelevanceScore);
226 |
227 | await using var session = _driver.AsyncSession();
228 |
229 | var cursor = await session.RunAsync(query, props).ConfigureAwait(false);
230 |
231 | var result = await cursor.SingleAsync().ConfigureAwait(false);
232 |
233 | var score = result["score"].As();
234 | var id = result["id"].As();
235 |
236 | return (new MemoryRecord(
237 | new MemoryRecordMetadata(
238 | true, id, "", "", "neo4j", ""),
239 | embedding,
240 | id),
241 | score
242 | );
243 | }
244 |
245 | public void Dispose()
246 | {
247 | _driver.Dispose();
248 | }
249 |
250 | private async Task> GetIndexesAsync()
251 | {
252 | var (query, _) = _queryFactory.ListIndexQuery();
253 |
254 | await using var session = _driver.AsyncSession();
255 |
256 | var cursor = await session.RunAsync(query).ConfigureAwait(false);
257 |
258 | return await cursor.ToListAsync(x => x.As()).ConfigureAwait(false);
259 | }
260 | }
261 | #pragma warning enable SKEXP0003
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j/README.md:
--------------------------------------------------------------------------------
1 | # Neo4j Memory Store
2 | Supports
3 | - Customizable queries
4 | - Runtime properties
5 | - Vector embedding Update, Get, Remove and Search
6 | - TextMemoryPlugin support see [example 15](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/KernelSyntaxExamples/Example15_TextMemoryPlugin.cs) of Semantic Kernel
7 |
8 | > :warning: **Kernel Memory**: Is experimental in the semantic kernel.
9 |
10 | ### Quick Start
11 | - Install from [nuget](https://www.nuget.org/packages/Codeblaze.SemanticKernel.Connectors.Memory.Neo4j)
12 | ```
13 | dotnet add package Codeblaze.SemanticKernel.Connectors.Memory.Neo4j
14 | ```
15 | - Configure the memory store
16 | ```csharp
17 | var builder = new MemoryBuilder();
18 |
19 | builder.WithHttpClient(new HttpClient());
20 | builder.WithOllamaTextEmbeddingGeneration(config["Ollama:Model"], config["Ollama:BaseUrlEmbeddings"]);
21 | builder.WithNeo4jMemoryStore(config["Neo4j:Url"], config["Neo4j:Username"], config["Neo4j:Password"],
22 | new Neo4jVectorIndexQueryFactory(
23 | "",
24 | "",
25 | "",
26 | "",
27 | 384 // Dimensions
28 | )
29 | );
30 |
31 | memory = builder.Build();
32 | ```
33 | - Store embedding
34 | ```csharp
35 | memory.SaveReferenceAsync(
36 | collection: "",
37 | externalSourceName: "",
38 | externalId: "",
39 | description: "not used",
40 | text: ""
41 | );
42 | ```
43 | - Search embedding
44 | ```csharp
45 | var results = memory.SearchAsync("", "", limit: 3);
46 | ```
47 | - Retrieve node
48 | ```csharp
49 | var results = await memory.GetAsync("", "");
50 | ```
51 |
52 | ### Query Factory
53 | You can implement you own `INeo4jQueryFactory` or Extend `Neo4jVectorIndexQueryFactory` to modify
54 | any of the queries (Default queries found in `Neo4jVectorQueries`).
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/ChatCompletion/OllamaChatCompletionService.cs:
--------------------------------------------------------------------------------
1 | using Codeblaze.SemanticKernel.Connectors.Ollama.ChatCompletion;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.SemanticKernel;
4 | using Microsoft.SemanticKernel.ChatCompletion;
5 | using System.Net.Http.Json;
6 | using System.Runtime.CompilerServices;
7 | using System.Text.Json;
8 |
9 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
10 |
11 | public class OllamaChatCompletionService(
12 | string modelId,
13 | string baseUrl,
14 | HttpClient http,
15 | ILoggerFactory? loggerFactory)
16 | : OllamaBase(modelId, baseUrl, http, loggerFactory), IChatCompletionService
17 | {
18 | public async Task> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null,
19 | Kernel? kernel = null, CancellationToken cancellationToken = new())
20 | {
21 | var chatExecutionSettings = OllamaPromptExecutionSettings.FromExecutionSettings(executionSettings);
22 |
23 | var data = new
24 | {
25 | model = Attributes["model_id"] as string,
26 | messages = GetChatMessages(chatHistory),
27 | stream = false,
28 | options = chatExecutionSettings
29 | };
30 |
31 | var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/chat", data, cancellationToken).ConfigureAwait(false);
32 |
33 | ValidateOllamaResponse(response);
34 | string jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
35 |
36 | var chatResponseMessage = JsonSerializer.Deserialize(jsonResponse);
37 |
38 | return new List { chatResponseMessage!.ToChatMessageContent() };
39 | }
40 |
41 | public async IAsyncEnumerable GetStreamingChatMessageContentsAsync(ChatHistory chatHistory,
42 | PromptExecutionSettings? executionSettings = null, Kernel? kernel = null,
43 | [EnumeratorCancellation] CancellationToken cancellationToken = new())
44 | {
45 | var chatExecutionSettings = OllamaPromptExecutionSettings.FromExecutionSettings(executionSettings);
46 |
47 | var data = new
48 | {
49 | model = Attributes["model_id"] as string,
50 | messages = GetChatMessages(chatHistory),
51 | stream = true,
52 | options = chatExecutionSettings
53 | };
54 |
55 | var request = new HttpRequestMessage(HttpMethod.Post, $"{Attributes["base_url"]}/api/chat");
56 | request.Content = JsonContent.Create(data);
57 | using var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
58 |
59 | ValidateOllamaResponse(response);
60 |
61 | using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
62 |
63 | using var reader = new StreamReader(stream);
64 |
65 | var done = false;
66 |
67 | while (!done)
68 | {
69 | string jsonResponse = await reader.ReadLineAsync();
70 |
71 | var chatResponseMessage = JsonSerializer.Deserialize(jsonResponse);
72 | done = chatResponseMessage!.Done;
73 |
74 | yield return chatResponseMessage!.ToStreamingChatMessageContent();
75 | }
76 | }
77 |
78 | private IEnumerable GetChatMessages(ChatHistory chat)
79 | {
80 | foreach (var item in chat)
81 | {
82 | if (item.Role == AuthorRole.System)
83 | yield return new OllamaChatRequestSystemMessage(item.Content!);
84 | else if (item.Role == AuthorRole.User)
85 | yield return new OllamaChatRequestUserMessage(item.Content!);
86 | else if (item.Role == AuthorRole.Assistant)
87 | yield return new OllamaChatRequestAssistantMessage(item.Content!);
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/ChatCompletion/OllamaChatRequestMessage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel;
2 | using Microsoft.SemanticKernel.ChatCompletion;
3 | using System.Text.Json.Serialization;
4 |
5 | namespace Codeblaze.SemanticKernel.Connectors.Ollama.ChatCompletion
6 | {
7 | internal abstract class OllamaChatRequestMessage
8 | {
9 | ///
10 | /// The role of the author of the message either "system", "user", or "assistant".
11 | ///
12 | [JsonPropertyName("role")]
13 | public string Role { get; protected set; } = null!;
14 |
15 | ///
16 | ///The content of the message
17 | ///
18 | [JsonPropertyName("content")]
19 | public string Content { get; set; } = null!;
20 |
21 | internal ChatMessageContent ToChatMessageContent(string modelId = null!)
22 | {
23 | return new ChatMessageContent(new AuthorRole(Role), Content, modelId: modelId);
24 | }
25 | }
26 |
27 | internal sealed class OllamaChatRequestSystemMessage : OllamaChatRequestMessage
28 | {
29 | public OllamaChatRequestSystemMessage(string content)
30 | {
31 | Role = "system";
32 | Content = content;
33 | }
34 | }
35 |
36 | internal sealed class OllamaChatRequestUserMessage : OllamaChatRequestMessage
37 | {
38 | public OllamaChatRequestUserMessage(string content)
39 | {
40 | Role = "user";
41 | Content = content;
42 | }
43 | }
44 |
45 | internal sealed class OllamaChatRequestAssistantMessage : OllamaChatRequestMessage
46 | {
47 | public OllamaChatRequestAssistantMessage(string content)
48 | {
49 | Role = "assistant";
50 | Content = content;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/ChatCompletion/OllamaChatResponseMessage.cs:
--------------------------------------------------------------------------------
1 | using Azure.AI.OpenAI;
2 | using Microsoft.SemanticKernel;
3 | using Microsoft.SemanticKernel.ChatCompletion;
4 | using System.Text.Json.Serialization;
5 |
6 | namespace Codeblaze.SemanticKernel.Connectors.Ollama.ChatCompletion
7 | {
8 | internal class OllamaChatResponseMessageContent
9 | {
10 | ///
11 | /// The role of the author of the message either "system", "user", or "assistant".
12 | ///
13 | [JsonPropertyName("role")]
14 | public string Role { get; set; } = null!;
15 |
16 | ///
17 | /// The message content
18 | ///
19 | [JsonPropertyName("content")]
20 | public string Content { get; set; } = null!;
21 |
22 | }
23 | internal class OllamaChatResponseMessage : OllamaResponseMessage
24 | {
25 | ///
26 | /// The message generated by the chat model.
27 | ///
28 | [JsonPropertyName("message")]
29 | public OllamaChatResponseMessageContent Message { get; set; } = null!;
30 |
31 | internal ChatMessageContent ToChatMessageContent()
32 | {
33 | var metadata = new Dictionary() {
34 | { "total_duration", TotalDuration },
35 | { "load_duration", LoadDuration },
36 | { "prompt_eval_count", PromptEvalCount },
37 | { "prompt_eval_duration", PromptEvalDuration },
38 | { "eval_count", EvalCount },
39 | { "eval_duration", EvalDuration}
40 | };
41 |
42 | return new ChatMessageContent(
43 | role: new AuthorRole(Message.Role),
44 | content: Message.Content,
45 | modelId: Model,
46 | metadata: metadata!);
47 | }
48 |
49 | internal StreamingChatMessageContent ToStreamingChatMessageContent()
50 | {
51 | var metadata = new Dictionary() {
52 | { "total_duration", TotalDuration },
53 | { "load_duration", LoadDuration },
54 | { "prompt_eval_count", PromptEvalCount },
55 | { "prompt_eval_duration", PromptEvalDuration },
56 | { "eval_count", EvalCount },
57 | { "eval_duration", EvalDuration}
58 | };
59 |
60 | return new StreamingChatMessageContent(
61 | role: new AuthorRole(Message.Role),
62 | content: Message.Content,
63 | modelId: Model,
64 | metadata: metadata!);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/Codeblaze.SemanticKernel.Connectors.Ollama.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | Latest
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 | all
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Codeblaze.SemanticKernel.Connectors.Ollama
27 | Codeblaze (Devashish Lal)
28 | SemanticKernel;Ollama;Chat;Embeddings;AI
29 |
30 | This package provides a Ollama AI connector for semantic kernel capable of text generation, chat completion and embedding generation with streaming support
31 |
32 | https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel
33 | git
34 | README.md
35 | LICENSE.md
36 | v
37 |
38 |
39 |
40 | true
41 | true
42 |
43 |
44 |
45 | $(NoWarn);1591
46 | bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/Codeblaze.SemanticKernel.Connectors.Ollama.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/EmbeddingGeneration/OllamaTextEmbeddingGeneration.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using System.Text.Json;
3 | using System.Text.Json.Nodes;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.SemanticKernel;
6 | using Microsoft.SemanticKernel.Embeddings;
7 |
8 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
9 |
10 | #pragma warning disable SKEXP0001
11 | public class OllamaTextEmbeddingGeneration(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory)
12 | : OllamaBase(modelId, baseUrl, http, loggerFactory),
13 | ITextEmbeddingGenerationService
14 | #pragma warning restore SKEXP0001
15 | {
16 | public async Task>> GenerateEmbeddingsAsync(IList data, Kernel? kernel = null,
17 | CancellationToken cancellationToken = new())
18 | {
19 | var result = new List>(data.Count);
20 |
21 | foreach (var text in data)
22 | {
23 | var request = new
24 | {
25 | model = Attributes["model_id"],
26 | prompt = text
27 | };
28 |
29 | var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/embeddings", request, cancellationToken).ConfigureAwait(false);
30 |
31 | ValidateOllamaResponse(response);
32 |
33 | var json = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
34 |
35 | var embedding = new ReadOnlyMemory(json!["embedding"]?.AsArray().GetValues().ToArray());
36 |
37 | result.Add(embedding);
38 | }
39 |
40 | return result;
41 | }
42 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/OllamaBase.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Logging.Abstractions;
4 |
5 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
6 |
7 | public interface IOllamaBase
8 | {
9 | Task PingOllamaAsync(CancellationToken cancellationToken = new());
10 | }
11 |
12 | public abstract class OllamaBase : IOllamaBase where T : OllamaBase
13 | {
14 | public IReadOnlyDictionary Attributes => _attributes;
15 |
16 | private readonly Dictionary _attributes = new();
17 |
18 | protected readonly HttpClient Http;
19 | protected readonly ILogger Logger;
20 |
21 | protected OllamaBase(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory)
22 | {
23 | _attributes.Add("model_id", modelId);
24 | _attributes.Add("base_url", baseUrl);
25 |
26 | Http = http;
27 | Logger = loggerFactory is not null ? loggerFactory.CreateLogger() : NullLogger.Instance;
28 | }
29 |
30 | ///
31 | /// Ping Ollama instance to check if the required llm model is available at the instance
32 | ///
33 | ///
34 | public async Task PingOllamaAsync(CancellationToken cancellationToken = new())
35 | {
36 | var data = new
37 | {
38 | name = Attributes["model_id"]
39 | };
40 |
41 | var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/show", data, cancellationToken).ConfigureAwait(false);
42 |
43 | ValidateOllamaResponse(response);
44 |
45 | Logger.LogInformation("Connected to Ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);
46 | }
47 |
48 | protected void ValidateOllamaResponse(HttpResponseMessage? response)
49 | {
50 | try
51 | {
52 | response.EnsureSuccessStatusCode();
53 | }
54 | catch (HttpRequestException)
55 | {
56 | Logger.LogError("Unable to connect to ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/OllamaKernelBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 |
4 | using Microsoft.SemanticKernel;
5 | using Microsoft.SemanticKernel.ChatCompletion;
6 | using Microsoft.SemanticKernel.Embeddings;
7 | using Microsoft.SemanticKernel.TextGeneration;
8 |
9 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
10 |
11 | public static class OllamaKernelBuilderExtensions
12 | {
13 | ///
14 | /// Adds Ollama as the text generation llm backend for semantic kernel
15 | ///
16 | /// kernel builder
17 | /// Ollama model ID to use
18 | /// Ollama base url
19 | ///
20 | ///
21 | public static IKernelBuilder AddOllamaTextGeneration(
22 | this IKernelBuilder builder,
23 | string modelId,
24 | string baseUrl,
25 | string? serviceId = null
26 | )
27 | {
28 | var factory = (IServiceProvider provider, object? _) => new OllamaTextGenerationService(
29 | modelId,
30 | baseUrl,
31 | provider.GetRequiredService(),
32 | provider.GetService()
33 | );
34 |
35 | builder.Services.AddKeyedSingleton(serviceId, factory);
36 |
37 | return builder;
38 | }
39 |
40 | ///
41 | /// Adds Ollama as the text generation llm backend for semantic kernel
42 | ///
43 | /// kernel builder
44 | /// Ollama model ID to use
45 | /// Ollama base url
46 | ///
47 | ///
48 | public static IKernelBuilder AddOllamaTextGeneration(
49 | this IKernelBuilder builder,
50 | string modelId,
51 | Uri baseUrl,
52 | string? serviceId = null
53 | )
54 | {
55 | var factory = (IServiceProvider provider, object? _) => new OllamaTextGenerationService(
56 | modelId,
57 | baseUrl.AbsoluteUri,
58 | provider.GetRequiredService(),
59 | provider.GetService()
60 | );
61 |
62 | builder.Services.AddKeyedSingleton(serviceId, factory);
63 |
64 | return builder;
65 | }
66 |
67 | ///
68 | /// Adds Ollama as the chat completion llm backend for semantic kernel
69 | ///
70 | /// kernel builder
71 | /// Ollama model ID to use
72 | /// Ollama base url
73 | ///
74 | ///
75 | public static IKernelBuilder AddOllamaChatCompletion(
76 | this IKernelBuilder builder,
77 | string modelId,
78 | string baseUrl,
79 | string? serviceId = null
80 | )
81 | {
82 | var factory = (IServiceProvider provider, object? _) => new OllamaChatCompletionService(
83 | modelId,
84 | baseUrl,
85 | provider.GetRequiredService(),
86 | provider.GetService()
87 | );
88 |
89 | builder.Services.AddKeyedSingleton(serviceId, factory);
90 |
91 | return builder;
92 | }
93 |
94 | ///
95 | /// Adds Ollama as the chat completion llm backend for semantic kernel
96 | ///
97 | /// kernel builder
98 | /// Ollama model ID to use
99 | /// Ollama base url
100 | ///
101 | ///
102 | public static IKernelBuilder AddOllamaChatCompletion(
103 | this IKernelBuilder builder,
104 | string modelId,
105 | Uri baseUrl,
106 | string? serviceId = null
107 | )
108 | {
109 | var factory = (IServiceProvider provider, object? _) => new OllamaChatCompletionService(
110 | modelId,
111 | baseUrl.AbsoluteUri,
112 | provider.GetRequiredService(),
113 | provider.GetService()
114 | );
115 |
116 | builder.Services.AddKeyedSingleton(serviceId, factory);
117 |
118 | return builder;
119 | }
120 |
121 | ///
122 | /// Adds Ollama as the text embedding generation backend for semantic kernel
123 | ///
124 | /// kernel builder
125 | /// Ollama model ID to use
126 | /// Ollama base url
127 | ///
128 | ///
129 | public static IKernelBuilder AddOllamaTextEmbeddingGeneration(
130 | this IKernelBuilder builder,
131 | string modelId,
132 | string baseUrl,
133 | string? serviceId = null
134 | )
135 | {
136 | var factory = (IServiceProvider provider, object? _) => new OllamaTextEmbeddingGeneration(
137 | modelId,
138 | baseUrl,
139 | provider.GetRequiredService(),
140 | provider.GetService()
141 | );
142 |
143 | #pragma warning disable SKEXP0001
144 | builder.Services.AddKeyedSingleton>(serviceId, factory);
145 | #pragma warning restore SKEXP0001
146 | return builder;
147 | }
148 |
149 | ///
150 | /// Adds Ollama as the text embedding generation backend for semantic kernel
151 | ///
152 | /// kernel builder
153 | /// Ollama model ID to use
154 | /// Ollama base url
155 | ///
156 | ///
157 | public static IKernelBuilder AddOllamaTextEmbeddingGeneration(
158 | this IKernelBuilder builder,
159 | string modelId,
160 | Uri baseUrl,
161 | string? serviceId = null
162 | )
163 | {
164 | var factory = (IServiceProvider provider, object? _) => new OllamaTextEmbeddingGeneration(
165 | modelId,
166 | baseUrl.AbsoluteUri,
167 | provider.GetRequiredService(),
168 | provider.GetService()
169 | );
170 |
171 | #pragma warning disable SKEXP0001
172 | builder.Services.AddKeyedSingleton>(serviceId, factory);
173 | #pragma warning restore SKEXP0001
174 | return builder;
175 | }
176 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/OllamaMemoryBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel.Memory;
2 |
3 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
4 |
5 | #pragma warning disable SKEXP0001
6 | public static class OllamaMemoryBuilderExtensions
7 | {
8 | ///
9 | /// Adds Ollama as the text embedding generation backend for semantic memory
10 | ///
11 | /// kernel builder
12 | /// Ollama model ID to use
13 | /// Ollama base url
14 | ///
15 | public static MemoryBuilder WithOllamaTextEmbeddingGeneration(
16 | this MemoryBuilder builder,
17 | string modelId,
18 | string baseUrl
19 | )
20 | {
21 | builder.WithTextEmbeddingGeneration((logger, http) => new OllamaTextEmbeddingGeneration(
22 | modelId,
23 | baseUrl,
24 | http,
25 | logger
26 | ));
27 |
28 | return builder;
29 | }
30 |
31 | ///
32 | /// Adds Ollama as the text embedding generation backend for semantic memory
33 | ///
34 | /// kernel builder
35 | /// Ollama model ID to use
36 | /// Ollama base url
37 | ///
38 | public static MemoryBuilder WithOllamaTextEmbeddingGeneration(
39 | this MemoryBuilder builder,
40 | string modelId,
41 | Uri baseUrl
42 | )
43 | {
44 | builder.WithTextEmbeddingGeneration((logger, http) => new OllamaTextEmbeddingGeneration(
45 | modelId,
46 | baseUrl.AbsoluteUri,
47 | http,
48 | logger
49 | ));
50 |
51 | return builder;
52 | }
53 | }
54 | #pragma warning enable SKEXP0001
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/OllamaPromptExecutionSettings.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel;
2 | using System.Text.Json;
3 | using System.Text.Json.Serialization;
4 |
5 | namespace Codeblaze.SemanticKernel.Connectors.Ollama
6 | {
7 | [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
8 | public sealed class OllamaPromptExecutionSettings
9 | {
10 | ///
11 | /// Temperature controls the randomness of the completion.
12 | /// The higher the temperature, the more random the completion.
13 | /// Default is 1.0.
14 | ///
15 | [JsonPropertyName("temperature")]
16 | public double Temperature { get; set; } = .8;
17 |
18 | ///
19 | /// Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text.
20 | /// Default: 0.9
21 | ///
22 | [JsonPropertyName("top_p")]
23 | public double TopP { get; set; } = .9;
24 |
25 | ///
26 | /// Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.
27 | /// Default: 40
28 | ///
29 | [JsonPropertyName("top_k")]
30 | public int TopK { get; set; } = 40;
31 |
32 | ///
33 | /// Maximum number of tokens to predict when generating text. (Default: 128, -1 = infinite generation, -2 = fill context)
34 | ///
35 | [JsonPropertyName("num_predict")]
36 | public int? MaxTokens { get; set; }
37 |
38 |
39 | internal static OllamaPromptExecutionSettings FromExecutionSettings(PromptExecutionSettings? executionSettings, int? defaultMaxTokens = null)
40 | {
41 | if (executionSettings is null)
42 | {
43 | return new OllamaPromptExecutionSettings()
44 | {
45 | MaxTokens = defaultMaxTokens
46 | };
47 | }
48 |
49 | var json = JsonSerializer.Serialize(executionSettings);
50 |
51 | var ollamaExecutionSettings = JsonSerializer.Deserialize(json, new JsonSerializerOptions
52 | {
53 | AllowTrailingCommas = true,
54 | PropertyNameCaseInsensitive = true,
55 | ReadCommentHandling = JsonCommentHandling.Skip
56 | });
57 |
58 | if (ollamaExecutionSettings is not null)
59 | {
60 | return ollamaExecutionSettings;
61 | }
62 |
63 | throw new ArgumentException($"Invalid execution settings, cannot convert to {nameof(OllamaPromptExecutionSettings)}", nameof(executionSettings));
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/OllamaResponseMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace Codeblaze.SemanticKernel.Connectors.Ollama
4 | {
5 | internal class OllamaResponseMessage
6 | {
7 | ///
8 | /// The model used to generate the response.
9 | ///
10 | [JsonPropertyName("model")]
11 | public string Model { get; set; } = null!;
12 |
13 | ///
14 | /// The message created date.
15 | ///
16 | [JsonPropertyName("created_at")]
17 | public DateTime CreatedAt { get; set; }
18 |
19 | ///
20 | /// Value indicating whether the message is done.
21 | ///
22 | [JsonPropertyName("done")]
23 | public bool Done { get; set; } = false!;
24 |
25 | ///
26 | /// The time spent generating the response.
27 | ///
28 | [JsonPropertyName("total_duration")]
29 | public UInt64 TotalDuration { get; set; } = 0;
30 |
31 | ///
32 | /// The time spent in nanoseconds loading the model.
33 | ///
34 | [JsonPropertyName("load_duration")]
35 | public UInt64 LoadDuration { get; set; } = 0;
36 |
37 | ///
38 | /// The number of tokens in the prompt.
39 | ///
40 | [JsonPropertyName("generate_duration")]
41 | public int PromptEvalCount { get; set; } = 0;
42 |
43 | ///
44 | /// The time spent in nanoseconds evaluating the prompt.
45 | ///
46 | [JsonPropertyName("prompt_eval_count")]
47 | public UInt64 PromptEvalDuration { get; set; } = 0;
48 |
49 | ///
50 | /// The number of tokens the response.
51 | ///
52 | [JsonPropertyName("eval_count")]
53 | public int EvalCount { get; set; } = 0;
54 |
55 | ///
56 | /// The time in nanoseconds spent generating the response.
57 | ///
58 | [JsonPropertyName("eval_duration")]
59 | public UInt64 EvalDuration { get; set; }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/README.md:
--------------------------------------------------------------------------------
1 | # Ollama Connector
2 | Supports
3 | - text generation
4 | - chat completion
5 | - embedding generation
6 |
7 | > :warning: **Embedding generation**: Is experimental in the semantic kernel.
8 |
9 | ### Quick Start
10 | - Install from [nuget](https://www.nuget.org/packages/Codeblaze.SemanticKernel.Connectors.Ollama)
11 | ```
12 | dotnet add package Codeblaze.SemanticKernel.Connectors.Ollama
13 | ```
14 | - Text Generation
15 |
16 | Configure the kernel
17 | ```csharp
18 | var builder = Kernel.CreateBuilder();
19 |
20 | // provide the HTTP client used to interact with Ollama API
21 | builder.Services.AddTransient();
22 |
23 | builder.AddOllamaTextGeneration(
24 | config["Ollama:Model"], // Ollama model Id
25 | config["Ollama:BaseUrlGeneration"] // Ollama endpoint
26 | );
27 |
28 | var kernel = builder.Build();
29 | ```
30 |
31 | Usage
32 | ```csharp
33 | const string prompt = """
34 | Bot: How can I help you?
35 | User: {{$input}}
36 |
37 | ---------------------------------------------
38 |
39 | The intent of the user in 5 words or less:
40 | """;
41 |
42 | var result = await kernel.InvokePromptAsync(prompt, new KernelArguments
43 | {
44 | {"input", input}
45 | });
46 |
47 | System.Console.WriteLine(result.GetValue());
48 | ```
49 |
50 | - Chat Completion
51 |
52 | Configure the kernel
53 | ```csharp
54 | var builder = new KernelBuilder();
55 |
56 | // provide the HTTP client used to interact with Ollama API
57 | builder.Services.AddTransient();
58 |
59 | builder.AddOllamaChatCompletion(
60 | config["Ollama:Model"], // Ollama model Id
61 | config["Ollama:BaseUrlGeneration"] // Ollama endpoint
62 | );
63 |
64 | var kernel = builder.Build();
65 | ```
66 |
67 | Usage
68 | ```csharp
69 | var chat = _Kernel.GetRequiredService();
70 |
71 | var history = new ChatHistory();
72 |
73 | // add messages to current chat history as required
74 | history.AddSystemMessage("...");
75 | history.AddAssistantMessage("...");
76 | history.AddUserMessage(input);
77 |
78 | // result is a list of all chat messages
79 | // including the output of current prompt
80 | var result = await chat.GetChatMessageContentsAsync(history);
81 |
82 | // Print the last message
83 | System.Console.WriteLine(result[^1].Content);
84 | ```
85 |
86 | - Embedding Generation (Experimental)
87 |
88 | Configure the kernel
89 | ```csharp
90 | var builder = new KernelBuilder();
91 |
92 | // provide the HTTP client used to interact with Ollama API
93 | builder.Services.AddTransient();
94 |
95 | builder.AddOllamaTextEmbeddingGeneration(
96 | config["Ollama:Model"], // Ollama model Id
97 | config["Ollama:BaseUrlGeneration"] // Ollama endpoint
98 | );
99 |
100 | // Configure memory backend (e.g Azure Cognitive Search)
101 |
102 | var kernel = builder.Build();
103 | ```
104 |
105 | Usage
106 | ```csharp
107 | var memory = _Kernel.GetRequiredService();
108 |
109 | // This will internally call Ollama embedding service to generate embeddings
110 | memory.SaveReferenceAsync(
111 | collection: "collection",
112 | externalSourceName: "ext-collection",
113 | externalId: id, // reference id (database entity id)
114 | description: input,
115 | text: input
116 | );
117 | ```
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama/TextGenerationService/OllamaTextGenerationService.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using System.Runtime.CompilerServices;
3 | using System.Text.Json;
4 | using System.Text.Json.Nodes;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.SemanticKernel;
7 | using Microsoft.SemanticKernel.TextGeneration;
8 |
9 | namespace Codeblaze.SemanticKernel.Connectors.Ollama;
10 |
11 | public class OllamaTextGenerationService(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory)
12 | : OllamaBase(modelId, baseUrl, http, loggerFactory), ITextGenerationService
13 | {
14 | public async Task> GetTextContentsAsync(string prompt,
15 | PromptExecutionSettings? executionSettings = null, Kernel? kernel = null,
16 | CancellationToken cancellationToken = new())
17 | {
18 | var data = new
19 | {
20 | model = Attributes["model_id"],
21 | prompt,
22 | stream = false,
23 | options = executionSettings?.ExtensionData,
24 | };
25 |
26 | var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/generate", data, cancellationToken).ConfigureAwait(false);
27 |
28 | ValidateOllamaResponse(response);
29 |
30 | var json = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
31 |
32 | return new List { new(json!["response"]!.GetValue()) };
33 | }
34 |
35 | public async IAsyncEnumerable GetStreamingTextContentsAsync(string prompt,
36 | PromptExecutionSettings? executionSettings = null,
37 | Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = new())
38 | {
39 | var data = new
40 | {
41 | model = Attributes["model_id"],
42 | prompt,
43 | stream = true,
44 | options = executionSettings?.ExtensionData,
45 | };
46 |
47 | var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/generate", data, cancellationToken).ConfigureAwait(false);
48 |
49 | ValidateOllamaResponse(response);
50 |
51 | using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
52 |
53 | using var reader = new StreamReader(stream);
54 |
55 | var done = false;
56 |
57 | while (!done)
58 | {
59 | var json = JsonSerializer.Deserialize(
60 | await response.Content.ReadAsStringAsync().ConfigureAwait(false)
61 | );
62 |
63 | done = json!["done"]!.GetValue();
64 |
65 | yield return new StreamingTextContent(json["response"]!.GetValue());
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/.gitignore:
--------------------------------------------------------------------------------
1 | appsettings.json
2 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Codeblaze.SemanticKernel.Console.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | Linux
9 | false
10 |
11 |
12 |
13 |
14 | .dockerignore
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
2 | USER $APP_UID
3 | WORKDIR /app
4 |
5 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
6 | ARG BUILD_CONFIGURATION=Release
7 | WORKDIR /src
8 | COPY ["Codeblaze.SemanticKernel.Console/Codeblaze.SemanticKernel.Console.csproj", "Codeblaze.SemanticKernel.Console/"]
9 | RUN dotnet restore "Codeblaze.SemanticKernel.Console/Codeblaze.SemanticKernel.Console.csproj"
10 | COPY . .
11 | WORKDIR "/src/Codeblaze.SemanticKernel.Console"
12 | RUN dotnet build "Codeblaze.SemanticKernel.Console.csproj" -c $BUILD_CONFIGURATION -o /app/build
13 |
14 | FROM build AS publish
15 | ARG BUILD_CONFIGURATION=Release
16 | RUN dotnet publish "Codeblaze.SemanticKernel.Console.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
17 |
18 | FROM base AS final
19 | WORKDIR /app
20 | COPY --from=publish /app/publish .
21 | ENTRYPOINT ["dotnet", "Codeblaze.SemanticKernel.Console.dll"]
22 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using Codeblaze.SemanticKernel.Console.Services;
3 | using Codeblaze.SemanticKernel.Plugins.Neo4j;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.SemanticKernel.Memory;
6 | using Spectre.Console;
7 | using Spectre.Console.Json;
8 |
9 | var config = new ConfigurationBuilder()
10 | .AddJsonFile("appsettings.json")
11 | .Build();
12 |
13 | AnsiConsole.Write(new FigletText($"{config["Name"]!}").Color(Color.Green));
14 | AnsiConsole.WriteLine("");
15 |
16 | const string prompt = "1.\tPrompt kernel";
17 | const string memory = "2.\tMemory search";
18 | const string exit = "2.\tExit";
19 |
20 | Run();
21 |
22 | return;
23 |
24 | void Run()
25 | {
26 | while (true)
27 | {
28 | var option = AnsiConsole.Prompt(
29 | new SelectionPrompt()
30 | .Title("Select an option")
31 | .PageSize(10)
32 | .MoreChoicesText("[grey](Move up and down to reveal more options)[/]")
33 | .AddChoices(prompt, memory, exit)
34 | );
35 |
36 | switch (option)
37 | {
38 | case prompt:
39 | Prompt().GetAwaiter().GetResult();
40 | break;
41 | case memory:
42 | Memory().GetAwaiter().GetResult();
43 | break;
44 | case exit:
45 | return;
46 | }
47 | }
48 | }
49 |
50 | async Task Prompt()
51 | {
52 | KernelService kernel = null;
53 |
54 | AnsiConsole.Status().Start("Initializing...", ctx =>
55 | {
56 | ctx.Spinner(Spinner.Known.Star);
57 | ctx.SpinnerStyle(Style.Parse("green"));
58 |
59 | kernel = new KernelService(config);
60 |
61 | ctx.Status("Initialized");
62 | });
63 |
64 | var prompt = AnsiConsole.Prompt(new TextPrompt("What are you looking to do today?\n").PromptStyle("teal"));
65 |
66 | string result = null;
67 |
68 | await AnsiConsole.Status().StartAsync("Processing...", async ctx =>
69 | {
70 | ctx.Spinner(Spinner.Known.Star);
71 | ctx.SpinnerStyle(Style.Parse("green"));
72 |
73 | ctx.Status($"Processing input");
74 | result = await kernel.BasicPrompt(prompt);
75 | });
76 |
77 | AnsiConsole.Write(new Rule("[cyan][/]") { Justification = Justify.Center });
78 | AnsiConsole.WriteLine($"Result: {result}");
79 | AnsiConsole.Write(new Rule("[cyan][/]") { Justification = Justify.Center });
80 | }
81 |
82 | #pragma warning disable SKEXP0003
83 | async Task Memory()
84 | {
85 | NeoMemoryService memory = null;
86 |
87 | AnsiConsole.Status().Start("Initializing...", ctx =>
88 | {
89 | ctx.Spinner(Spinner.Known.Star);
90 | ctx.SpinnerStyle(Style.Parse("green"));
91 |
92 | memory = new NeoMemoryService(config);
93 |
94 | ctx.Status("Initialized");
95 | });
96 |
97 | var prompt = AnsiConsole.Prompt(new TextPrompt("What are you looking to do today?\n").PromptStyle("teal"));
98 |
99 | #pragma warning disable SKEXP0001
100 | IAsyncEnumerable result = null;
101 | #pragma warning enable SKEXP0001
102 | await AnsiConsole.Status().StartAsync("Processing...", async ctx =>
103 | {
104 | ctx.Spinner(Spinner.Known.Star);
105 | ctx.SpinnerStyle(Style.Parse("green"));
106 |
107 | ctx.Status($"Processing input to generate cypher");
108 | result = memory.Run(prompt);
109 | });
110 |
111 | await foreach (var record in result)
112 | {
113 | AnsiConsole.Write(new Rule("[cyan][/]") { Justification = Justify.Center });
114 | AnsiConsole.WriteLine($"Relevance : {record.Relevance}");
115 | AnsiConsole.WriteLine($"Node ID: {record.Metadata.Id}");
116 | AnsiConsole.WriteLine($"Node text: {record.Metadata.Text}");
117 | }
118 |
119 | AnsiConsole.Write(new Rule("[cyan][/]") { Justification = Justify.Center });
120 | }
121 | #pragma warning enable SKEXP0003
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Services/KernelService.cs:
--------------------------------------------------------------------------------
1 | using Codeblaze.SemanticKernel.Connectors.Ollama;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.SemanticKernel;
5 | using Microsoft.SemanticKernel.ChatCompletion;
6 |
7 | namespace Codeblaze.SemanticKernel.Console.Services;
8 |
9 | public class KernelService
10 | {
11 | private readonly Kernel _Kernel;
12 |
13 | public KernelService(IConfiguration config)
14 | {
15 | var builder = Kernel.CreateBuilder();
16 |
17 | builder.Services.AddTransient();
18 |
19 | // builder.AddOllamaChatCompletion(config["Ollama:Model"], config["Ollama:BaseUrlGeneration"]);
20 | builder.AddOllamaTextGeneration(config["Ollama:Model"], config["Ollama:BaseUrlGeneration"]);
21 |
22 | _Kernel = builder.Build();
23 | }
24 |
25 | public async Task BasicPrompt(string input)
26 | {
27 | const string prompt = """
28 | Bot: How can I help you?
29 | User: {{$input}}
30 |
31 | ---------------------------------------------
32 |
33 | The intent of the user in 5 words or less:
34 | """;
35 |
36 | var result = await _Kernel.InvokePromptAsync(prompt, new KernelArguments
37 | {
38 | {"input", input}
39 | });
40 |
41 | return result.GetValue();
42 | }
43 |
44 | public async Task BasicChat(string input)
45 | {
46 | var chat = _Kernel.GetRequiredService();
47 |
48 | var history = new ChatHistory();
49 |
50 | history.AddSystemMessage("...");
51 | history.AddAssistantMessage("...");
52 | history.AddUserMessage(input);
53 |
54 | var result = await chat.GetChatMessageContentsAsync(history);
55 |
56 | return result[^1].Content;
57 | }
58 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Services/NeoKernelService.cs:
--------------------------------------------------------------------------------
1 | using Codeblaze.SemanticKernel.Plugins.Neo4j;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.SemanticKernel;
4 |
5 | namespace Codeblaze.SemanticKernel.Console.Services;
6 |
7 | public class NeoKernelService
8 | {
9 | private readonly Kernel _Kernel;
10 |
11 | public NeoKernelService(IConfiguration config)
12 | {
13 | var builder = Kernel.CreateBuilder();
14 |
15 | // builder.Services.AddTransient();
16 |
17 | builder.AddOpenAIChatCompletion(config["OpenAI:Model"], config["OpenAI:Key"]);
18 | // builder.AddOllamaChatCompletion(config["Ollama:Model"], config["Ollama:BaseUrlGeneration"]);
19 |
20 | _Kernel = builder.Build();
21 |
22 | _Kernel.AddNeo4jCypherGenPlugin(config["Neo4j:Url"], config["Neo4j:Username"], config["Neo4j:Password"]);
23 | }
24 |
25 | public Task Run(string prompt)
26 | {
27 | return _Kernel.InvokeAsync(
28 | nameof(Neo4jCypherGenPlugin), "Query",
29 | new KernelArguments
30 | {
31 | { "prompt", prompt }
32 | }
33 | );
34 | }
35 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Console/Services/NeoMemoryService.cs:
--------------------------------------------------------------------------------
1 | using Codeblaze.SemanticKernel.Connectors.Memory.Neo4j;
2 | using Codeblaze.SemanticKernel.Connectors.Ollama;
3 | using Microsoft.Extensions.Configuration;
4 | using Microsoft.SemanticKernel.Memory;
5 |
6 | namespace Codeblaze.SemanticKernel.Console.Services;
7 |
8 | #pragma warning disable SKEXP0001
9 | public class NeoMemoryService
10 | {
11 | private readonly ISemanticTextMemory _memory;
12 |
13 | public NeoMemoryService(IConfiguration config)
14 | {
15 | var builder = new MemoryBuilder();
16 |
17 | builder.WithHttpClient(new HttpClient());
18 | builder.WithOllamaTextEmbeddingGeneration(config["Ollama:Model"], config["Ollama:BaseUrlEmbeddings"]);
19 | builder.WithNeo4jMemoryStore(config["Neo4j:Url"], config["Neo4j:Username"], config["Neo4j:Password"],
20 | new Neo4jVectorIndexQueryFactory(
21 | "top_questions",
22 | "Question",
23 | "embedding",
24 | "title",
25 | 384
26 | )
27 | );
28 |
29 | _memory = builder.Build();
30 | }
31 |
32 | public async IAsyncEnumerable Run(string prompt)
33 | {
34 | var results = _memory.SearchAsync("top_questions", prompt, limit: 3);
35 |
36 | await foreach (var result in results)
37 | {
38 | yield return new MemoryQueryResult(
39 | (await _memory.GetAsync("top_questions", result.Metadata.Id)).Metadata,
40 | result.Relevance,
41 | result.Embedding
42 | );
43 | }
44 | }
45 | }
46 | #pragma warning enable SKEXP0001
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Plugins.Neo4j/Codeblaze.SemanticKernel.Plugins.Neo4j.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | Latest
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 | all
20 |
21 |
22 |
23 |
24 |
25 | Codeblaze.SemanticKernel.Plugins.Neo4j
26 | Codeblaze (Devashish Lal)
27 | SemanticKernel;Neo4j;Cypher;Codegen;Knowledge Graphs
28 |
29 | This package provides semantic kernel plugin for Neo4j cyher codegen support, Enabling talking to knowledge graphs
30 |
31 | https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel
32 | git
33 | README.md
34 | LICENSE.md
35 | v
36 |
37 |
38 |
39 | true
40 | true
41 |
42 |
43 |
44 | $(NoWarn);1591
45 | bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Plugins.Neo4j/Neo4jCypherGenPlugin.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.Json;
3 | using Microsoft.SemanticKernel;
4 | using Microsoft.SemanticKernel.ChatCompletion;
5 | using Neo4j.Driver;
6 |
7 | namespace Codeblaze.SemanticKernel.Plugins.Neo4j;
8 |
9 | ///
10 | /// Cypher gen query execution result
11 | ///
12 | public class Neo4jResult
13 | {
14 | public bool Success { get; set; }
15 | public string? Cypher { get; set; }
16 | public List? Result { get; set; }
17 | }
18 |
19 | ///
20 | /// Cypher code gen plugin
21 | ///
22 | public class Neo4jCypherGenPlugin : IDisposable
23 | {
24 | private readonly IDriver _driver;
25 | private readonly IChatCompletionService _chat;
26 |
27 | ///
28 | /// Text bases representation of schema for the current database
29 | ///
30 | public string Schema { get; }
31 |
32 | private const string NODE_PROPS_QUERY = """
33 | CALL apoc.meta.data()
34 | YIELD label, other, elementType, type, property
35 | WHERE NOT type = "RELATIONSHIP" AND elementType = "node"
36 | WITH label AS nodeLabels, collect(property) AS properties
37 | RETURN {labels: nodeLabels, properties: properties} AS output
38 | """;
39 |
40 | private const string REL_PROPS_QUERY = """
41 | CALL apoc.meta.data()
42 | YIELD label, other, elementType, type, property
43 | WHERE NOT type = "RELATIONSHIP" AND elementType = "relationship"
44 | WITH label AS nodeLabels, collect(property) AS properties
45 | RETURN {type: nodeLabels, properties: properties} AS output
46 | """;
47 |
48 | private const string REL_QUERY = """
49 | CALL apoc.meta.data()
50 | YIELD label, other, elementType, type, property
51 | WHERE type = "RELATIONSHIP" AND elementType = "node"
52 | RETURN {source: label, relationship: property, target: other} AS output
53 | """;
54 |
55 | ///
56 | /// Creates a neo4j cypher gen plugin instance
57 | ///
58 | /// Chat service from semantic kernel to be used as generation backend
59 | /// Neo4j url, used by the neo4j driver
60 | /// Neo4j database username, used by the neo4j driver
61 | /// Neo4j database password, used by the neo4j driver
62 | public Neo4jCypherGenPlugin(IChatCompletionService chat, string url, string username, string password)
63 | {
64 | _driver = GraphDatabase.Driver(url, AuthTokens.Basic(username, password));
65 | _chat = chat;
66 |
67 | Schema = GetSchema().GetAwaiter().GetResult();
68 | }
69 |
70 | ///
71 | /// Creates a neo4j cypher gen plugin instance
72 | ///
73 | /// Chat service from semantic kernel to be used as generation backend
74 | /// Neo4j driver to be used for executing cypher
75 | public Neo4jCypherGenPlugin(IChatCompletionService chat, IDriver driver)
76 | {
77 | _driver = driver;
78 | _chat = chat;
79 |
80 | Schema = GetSchema().GetAwaiter().GetResult();
81 | }
82 |
83 | ///
84 | /// SK Function to generate cypher, execute it and return the result
85 | ///
86 | /// prompt against which cypher is to be generated
87 | /// Result containing, cypher and cypher execution result
88 | [KernelFunction, Description("Generates cypher code based on prompt and queries the database")]
89 | public async Task Query(string prompt)
90 | {
91 | var cypher = await GenerateCypher(prompt);
92 |
93 | try
94 | {
95 | var result = await NeoQuery(cypher);
96 |
97 | return new Neo4jResult
98 | {
99 | Success = true,
100 | Cypher = cypher,
101 | Result = result
102 | };
103 | }
104 | catch
105 | {
106 | return new Neo4jResult { Success = false, Cypher = cypher };
107 | }
108 | }
109 |
110 | ///
111 | /// SK Function to generate cypher based on the prompt
112 | ///
113 | /// prompt against which cypher is to be generated
114 | /// Generated cypher
115 | [KernelFunction, Description("Generates cypher code based on prompt")]
116 | public async Task GenerateCypher(string prompt)
117 | {
118 | var system = $"""
119 | Task: Generate Cypher queries to query a Neo4j graph database based on the provided schema definition.
120 | Instructions:
121 | Use only the provided relationship types and properties.
122 | Do not use any other relationship types or properties that are not provided.
123 | If you cannot generate a Cypher statement based on the provided schema, explain the reason to the user.
124 | Schema:
125 | {Schema}
126 |
127 | Note: Do not include any explanations or apologies in your responses.
128 | """;
129 |
130 | var history = new ChatHistory
131 | {
132 | new(AuthorRole.System, system),
133 | new(AuthorRole.User, prompt)
134 | };
135 |
136 | var result = await _chat.GetChatMessageContentsAsync(history);
137 |
138 | return result[0].Content;
139 | }
140 |
141 | private async Task GetSchema()
142 | {
143 | var nodeProps = JsonSerializer.Serialize((await NeoQuery(NODE_PROPS_QUERY)).Select(x => x.Values["output"]).ToList());
144 | var relationProps = JsonSerializer.Serialize((await NeoQuery(REL_PROPS_QUERY)).Select(x => x.Values["output"]).ToList());
145 | var relations = JsonSerializer.Serialize((await NeoQuery(REL_QUERY)).Select(x => x.Values["output"]).ToList());
146 |
147 | return $"""
148 | This is the schema representation of the Neo4j database.
149 | Node properties are the following:
150 | {nodeProps}
151 | Relationship properties are the following:
152 | {relationProps}
153 | Relationship point from source to target nodes
154 | {relations}
155 | Make sure to respect relationship types and directions
156 | """;
157 | }
158 |
159 | private async Task> NeoQuery(string query)
160 | {
161 | await using var session = _driver.AsyncSession(o => o.WithDatabase("neo4j"));
162 |
163 | return await session.ExecuteReadAsync(async transaction =>
164 | {
165 | var cursor = await transaction.RunAsync(query);
166 |
167 | return await cursor.ToListAsync();
168 | });
169 | }
170 |
171 | public async void Dispose()
172 | {
173 | await _driver.DisposeAsync();
174 | }
175 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Plugins.Neo4j/Neo4jPluginBuilderExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.SemanticKernel;
2 | using Microsoft.SemanticKernel.ChatCompletion;
3 | using Neo4j.Driver;
4 |
5 | namespace Codeblaze.SemanticKernel.Plugins.Neo4j;
6 |
7 | public static class Neo4jPluginBuilderExtension
8 | {
9 | public static void AddNeo4jCypherGenPlugin(this Kernel kernel, string url, string username, string password)
10 | {
11 | var chat = kernel.GetRequiredService();
12 |
13 | var plugin = new Neo4jCypherGenPlugin(chat, url, username, password);
14 |
15 | kernel.ImportPluginFromObject(plugin, nameof(Neo4jCypherGenPlugin));
16 | }
17 |
18 | public static void AddNeo4jCypherGenPlugin(this Kernel kernel, IDriver driver)
19 | {
20 | var chat = kernel.GetRequiredService();
21 |
22 | var plugin = new Neo4jCypherGenPlugin(chat, driver);
23 |
24 | kernel.ImportPluginFromObject(plugin, nameof(Neo4jCypherGenPlugin));
25 | }
26 | }
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.Plugins.Neo4j/README.md:
--------------------------------------------------------------------------------
1 | # Neo4j Cypher Codegen
2 | This package provides semantic kernel plugin for Neo4j cyher codegen support, Enabling talking to knowledge graphs respecting it's schema
3 |
4 | ### Important
5 | - Plugin has been tested with gpt-3.5-turbo, other models may require tweaks to the prompts
6 | - Make sure your neo4j instance has the [apoc plugin](https://neo4j.com/docs/apoc/current/)
7 | - On initialization, the plugin queries the database to generate a text representation of schema
8 |
9 | ### Quick Start
10 | - Install from [nuget](https://www.nuget.org/packages/Codeblaze.SemanticKernel.Plugins.Neo4j)
11 | ```
12 | dotnet add package Codeblaze.SemanticKernel.Plugins.Neo4j
13 | ```
14 | - Configure the kernel
15 | ```csharp
16 | var builder = Kernel.CreateBuilder();
17 |
18 | builder.AddOpenAIChatCompletion(
19 | config["OpenAI:Model"],
20 | config["OpenAI:Key"]
21 | );
22 |
23 | var kernel = builder.Build();
24 |
25 | kernel.AddNeo4jCypherGenPlugin(
26 | config["Neo4j:Url"],
27 | config["Neo4j:Username"],
28 | config["Neo4j:Password"]
29 | );
30 | ```
31 | - Query the database using prompts
32 | ```csharp
33 | var prompt = "Which movies came out in 1990?";
34 |
35 | var result = await _Kernel.InvokeAsync(
36 | nameof(Neo4jCypherGenPlugin), "Query",
37 | new KernelArguments
38 | {
39 | { "prompt", prompt }
40 | }
41 | );
42 |
43 | result.Cypher; // Generated cypher (string)
44 | result.Result; // Neo4j query execution result (List)
45 | ```
46 |
47 | ### Semantic Kernel Functions
48 | - Query
49 | - **description**
50 |
51 | Generates cypher code based on the provided prompt, executes it against the configured neo4j instance
52 | returns both cypher and the prompt
53 | - **usage**
54 | ```csharp
55 | _Kernel.InvokeAsync(
56 | nameof(Neo4jCypherGenPlugin), "Query",
57 | new KernelArguments
58 | {
59 | { "prompt", prompt }
60 | }
61 | );
62 | ```
63 |
64 | - GenerateCypher
65 | - **description**
66 |
67 | Generates cypher code based on the provided prompt
68 | - **usage**
69 | ```csharp
70 | _Kernel.InvokeAsync(
71 | nameof(Neo4jCypherGenPlugin), "GenerateCypher",
72 | new KernelArguments
73 | {
74 | { "prompt", prompt }
75 | }
76 | );
77 | ```
78 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codeblaze.SemanticKernel.Connectors.Ollama", "Codeblaze.SemanticKernel.Connectors.Ollama\Codeblaze.SemanticKernel.Connectors.Ollama.csproj", "{D9D1DB9F-F4FF-494C-A470-7E29BA5CCC49}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codeblaze.SemanticKernel.Api", "Codeblaze.SemanticKernel.Api\Codeblaze.SemanticKernel.Api.csproj", "{51E5DA79-8F4E-4D8D-95ED-96C724741E6F}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codeblaze.SemanticKernel.Console", "Codeblaze.SemanticKernel.Console\Codeblaze.SemanticKernel.Console.csproj", "{AC32C115-684E-408C-9320-8D915FF7E3A1}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codeblaze.SemanticKernel.Plugins.Neo4j", "Codeblaze.SemanticKernel.Plugins.Neo4j\Codeblaze.SemanticKernel.Plugins.Neo4j.csproj", "{59813D42-7792-4750-AD89-0548812BAD9E}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codeblaze.SemanticKernel.Connectors.Memory.Neo4j", "Codeblaze.SemanticKernel.Connectors.Memory.Neo4j\Codeblaze.SemanticKernel.Connectors.Memory.Neo4j.csproj", "{3EAC6B51-3F7E-47CD-98B3-02915B18CE39}"
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {D9D1DB9F-F4FF-494C-A470-7E29BA5CCC49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {D9D1DB9F-F4FF-494C-A470-7E29BA5CCC49}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {D9D1DB9F-F4FF-494C-A470-7E29BA5CCC49}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {D9D1DB9F-F4FF-494C-A470-7E29BA5CCC49}.Release|Any CPU.Build.0 = Release|Any CPU
23 | {51E5DA79-8F4E-4D8D-95ED-96C724741E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {51E5DA79-8F4E-4D8D-95ED-96C724741E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {51E5DA79-8F4E-4D8D-95ED-96C724741E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {51E5DA79-8F4E-4D8D-95ED-96C724741E6F}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {AC32C115-684E-408C-9320-8D915FF7E3A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {AC32C115-684E-408C-9320-8D915FF7E3A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {AC32C115-684E-408C-9320-8D915FF7E3A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {AC32C115-684E-408C-9320-8D915FF7E3A1}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {59813D42-7792-4750-AD89-0548812BAD9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {59813D42-7792-4750-AD89-0548812BAD9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {59813D42-7792-4750-AD89-0548812BAD9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {59813D42-7792-4750-AD89-0548812BAD9E}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {3EAC6B51-3F7E-47CD-98B3-02915B18CE39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {3EAC6B51-3F7E-47CD-98B3-02915B18CE39}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {3EAC6B51-3F7E-47CD-98B3-02915B18CE39}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {3EAC6B51-3F7E-47CD-98B3-02915B18CE39}.Release|Any CPU.Build.0 = Release|Any CPU
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/dotnet/Codeblaze.SemanticKernel.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
--------------------------------------------------------------------------------
/dotnet/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "rollForward": "feature",
4 | "version": "8.0.100"
5 | }
6 | }
--------------------------------------------------------------------------------
/java/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BLaZeKiLL/Codeblaze.SemanticKernel/aa77487ef6753bd2937f90050493ce48b948436c/java/.gitkeep
--------------------------------------------------------------------------------
/python/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BLaZeKiLL/Codeblaze.SemanticKernel/aa77487ef6753bd2937f90050493ce48b948436c/python/.gitkeep
--------------------------------------------------------------------------------