♻️ Refactored the thought Solar Network related plugins
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using DysonNetwork.Insight.Thought;
|
||||
using Quartz;
|
||||
|
||||
namespace DysonNetwork.Insight.Startup;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Insight.Thought;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Registry;
|
||||
using Microsoft.SemanticKernel;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.SystemTextJson;
|
||||
@@ -63,17 +64,13 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
public static IServiceCollection AddThinkingServices(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// Add gRPC clients for ThoughtService
|
||||
services.AddSphereService();
|
||||
services.AddAccountService();
|
||||
|
||||
services.AddSingleton<ThoughtProvider>();
|
||||
services.AddScoped<ThoughtService>();
|
||||
|
||||
// Add gRPC clients for ThoughtService
|
||||
services.AddGrpcClient<Shared.Proto.PaymentService.PaymentServiceClient>(o => o.Address = new Uri("https://_grpc.pass"))
|
||||
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
|
||||
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true });
|
||||
services.AddGrpcClient<Shared.Proto.WalletService.WalletServiceClient>(o => o.Address = new Uri("https://_grpc.pass"))
|
||||
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
|
||||
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true });
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SemanticKernel;
|
||||
|
||||
namespace DysonNetwork.Insight.Thought.Plugins;
|
||||
|
||||
public class SnAccountKernelPlugin(
|
||||
AccountService.AccountServiceClient accountClient
|
||||
)
|
||||
{
|
||||
[KernelFunction("get_account")]
|
||||
public async Task<SnAccount?> GetAccount(string userId)
|
||||
{
|
||||
var request = new GetAccountRequest { Id = userId };
|
||||
var response = await accountClient.GetAccountAsync(request);
|
||||
if (response is null) return null;
|
||||
return SnAccount.FromProtoValue(response);
|
||||
}
|
||||
|
||||
[KernelFunction("get_account_by_name")]
|
||||
public async Task<SnAccount?> GetAccountByName(string username)
|
||||
{
|
||||
var request = new LookupAccountBatchRequest();
|
||||
request.Names.Add(username);
|
||||
var response = await accountClient.LookupAccountBatchAsync(request);
|
||||
return response.Accounts.IsNullOrEmpty() ? null : SnAccount.FromProtoValue(response.Accounts[0]);
|
||||
}
|
||||
}
|
||||
98
DysonNetwork.Insight/Thought/Plugins/SnPostKernelPlugin.cs
Normal file
98
DysonNetwork.Insight/Thought/Plugins/SnPostKernelPlugin.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System.ComponentModel;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using Microsoft.SemanticKernel;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.Protobuf;
|
||||
using NodaTime.Text;
|
||||
|
||||
namespace DysonNetwork.Insight.Thought.Plugins;
|
||||
|
||||
public class SnPostKernelPlugin(
|
||||
PostService.PostServiceClient postClient
|
||||
)
|
||||
{
|
||||
[KernelFunction("get_post")]
|
||||
public async Task<SnPost?> GetPost(string postId)
|
||||
{
|
||||
var request = new GetPostRequest { Id = postId };
|
||||
var response = await postClient.GetPostAsync(request);
|
||||
return response is null ? null : SnPost.FromProtoValue(response);
|
||||
}
|
||||
|
||||
[KernelFunction("search_posts")]
|
||||
[Description("Perform a full-text search in all Solar Network posts.")]
|
||||
public async Task<List<SnPost>> SearchPostsContent(string contentQuery, int pageSize = 10, int page = 1)
|
||||
{
|
||||
var request = new SearchPostsRequest
|
||||
{
|
||||
Query = contentQuery,
|
||||
PageSize = pageSize,
|
||||
PageToken = ((page - 1) * pageSize).ToString()
|
||||
};
|
||||
var response = await postClient.SearchPostsAsync(request);
|
||||
return response.Posts.Select(SnPost.FromProtoValue).ToList();
|
||||
}
|
||||
|
||||
public class KernelPostListResult
|
||||
{
|
||||
public List<SnPost> Posts { get; set; } = [];
|
||||
public int TotalCount { get; set; }
|
||||
}
|
||||
|
||||
[KernelFunction("list_posts")]
|
||||
[Description("List all posts on the Solar Network without filters, orderBy can be date or popularity")]
|
||||
public async Task<KernelPostListResult> ListPosts(
|
||||
string orderBy = "date",
|
||||
bool orderDesc = true,
|
||||
int pageSize = 10,
|
||||
int page = 1
|
||||
)
|
||||
{
|
||||
var request = new ListPostsRequest
|
||||
{
|
||||
OrderBy = orderBy,
|
||||
OrderDesc = orderDesc,
|
||||
PageSize = pageSize,
|
||||
PageToken = ((page - 1) * pageSize).ToString()
|
||||
};
|
||||
var response = await postClient.ListPostsAsync(request);
|
||||
return new KernelPostListResult
|
||||
{
|
||||
Posts = response.Posts.Select(SnPost.FromProtoValue).ToList(),
|
||||
TotalCount = response.TotalSize,
|
||||
};
|
||||
}
|
||||
|
||||
[KernelFunction("list_posts_within_time")]
|
||||
[Description(
|
||||
"List posts in a period of time, the time requires ISO-8601 format, one of the start and end must be provided.")]
|
||||
public async Task<KernelPostListResult> ListPostsWithinTime(
|
||||
string? beforeTime,
|
||||
string? afterTime,
|
||||
int pageSize = 10,
|
||||
int page = 1
|
||||
)
|
||||
{
|
||||
var pattern = InstantPattern.General;
|
||||
Instant? before = !string.IsNullOrWhiteSpace(beforeTime)
|
||||
? pattern.Parse(beforeTime).TryGetValue(default, out var beforeValue) ? beforeValue : null
|
||||
: null;
|
||||
Instant? after = !string.IsNullOrWhiteSpace(afterTime)
|
||||
? pattern.Parse(afterTime).TryGetValue(default, out var afterValue) ? afterValue : null
|
||||
: null;
|
||||
var request = new ListPostsRequest
|
||||
{
|
||||
After = after?.ToTimestamp(),
|
||||
Before = before?.ToTimestamp(),
|
||||
PageSize = pageSize,
|
||||
PageToken = ((page - 1) * pageSize).ToString()
|
||||
};
|
||||
var response = await postClient.ListPostsAsync(request);
|
||||
return new KernelPostListResult
|
||||
{
|
||||
Posts = response.Posts.Select(SnPost.FromProtoValue).ToList(),
|
||||
TotalCount = response.TotalSize,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.ClientModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Insight.Thought.Plugins;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using Microsoft.SemanticKernel;
|
||||
@@ -71,81 +72,15 @@ public class ThoughtProvider
|
||||
throw new IndexOutOfRangeException("Unknown thinking provider: " + ModelProviderType);
|
||||
}
|
||||
|
||||
builder.Plugins.AddFromType<SnAccountKernelPlugin>();
|
||||
builder.Plugins.AddFromType<SnPostKernelPlugin>();
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
[Experimental("SKEXP0050")]
|
||||
private void InitializeHelperFunctions()
|
||||
{
|
||||
// Add Solar Network tools plugin
|
||||
Kernel.ImportPluginFromFunctions("solar_network", [
|
||||
KernelFunctionFactory.CreateFromMethod(async (string userId) =>
|
||||
{
|
||||
var request = new GetAccountRequest { Id = userId };
|
||||
var response = await _accountClient.GetAccountAsync(request);
|
||||
return JsonSerializer.Serialize(response, GrpcTypeHelper.SerializerOptions);
|
||||
}, "get_user", "Get a user profile from the Solar Network."),
|
||||
KernelFunctionFactory.CreateFromMethod(async (string postId) =>
|
||||
{
|
||||
var request = new GetPostRequest { Id = postId };
|
||||
var response = await _postClient.GetPostAsync(request);
|
||||
return JsonSerializer.Serialize(response, GrpcTypeHelper.SerializerOptions);
|
||||
}, "get_post", "Get a single post by ID from the Solar Network."),
|
||||
KernelFunctionFactory.CreateFromMethod(async (string query) =>
|
||||
{
|
||||
var request = new SearchPostsRequest { Query = query, PageSize = 10 };
|
||||
var response = await _postClient.SearchPostsAsync(request);
|
||||
return JsonSerializer.Serialize(response.Posts, GrpcTypeHelper.SerializerOptions);
|
||||
}, "search_posts",
|
||||
"Search posts by query from the Solar Network. The input query is will be used to search with title, description and body content"),
|
||||
KernelFunctionFactory.CreateFromMethod(async (
|
||||
string? orderBy = null,
|
||||
string? afterIso = null,
|
||||
string? beforeIso = null
|
||||
) =>
|
||||
{
|
||||
_logger.LogInformation("Begin building request to list post from sphere...");
|
||||
|
||||
var request = new ListPostsRequest
|
||||
{
|
||||
PageSize = 20,
|
||||
OrderBy = orderBy,
|
||||
};
|
||||
if (!string.IsNullOrEmpty(afterIso))
|
||||
try
|
||||
{
|
||||
request.After = InstantPattern.General.Parse(afterIso).Value.ToTimestamp();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.LogWarning("Invalid afterIso format: {AfterIso}", afterIso);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(beforeIso))
|
||||
try
|
||||
{
|
||||
request.Before = InstantPattern.General.Parse(beforeIso).Value.ToTimestamp();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.LogWarning("Invalid beforeIso format: {BeforeIso}", beforeIso);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Request built, {Request}", request);
|
||||
|
||||
var response = await _postClient.ListPostsAsync(request);
|
||||
|
||||
var data = response.Posts.Select(SnPost.FromProtoValue);
|
||||
_logger.LogInformation("Sphere service returned posts: {Posts}", data);
|
||||
return JsonSerializer.Serialize(data, GrpcTypeHelper.SerializerOptions);
|
||||
}, "list_posts",
|
||||
"Get posts from the Solar Network.\n" +
|
||||
"Parameters:\n" +
|
||||
"orderBy (optional, string: order by published date, accept asc or desc)\n" +
|
||||
"afterIso (optional, string: ISO date for posts after this date)\n" +
|
||||
"beforeIso (optional, string: ISO date for posts before this date)"
|
||||
)
|
||||
]);
|
||||
|
||||
// Add web search plugins if configured
|
||||
var bingApiKey = _configuration.GetValue<string>("Thinking:BingApiKey");
|
||||
if (!string.IsNullOrEmpty(bingApiKey))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using DysonNetwork.Insight.Thought;
|
||||
using Quartz;
|
||||
|
||||
namespace DysonNetwork.Insight.Startup;
|
||||
namespace DysonNetwork.Insight.Thought;
|
||||
|
||||
public class TokenBillingJob(ThoughtService thoughtService, ILogger<TokenBillingJob> logger) : IJob
|
||||
{
|
||||
Reference in New Issue
Block a user