Merge branch 'master' of https://github.com/SciSharp/BotSharp
This commit is contained in:
commit
15a30f2670
|
|
@ -61,4 +61,6 @@ public interface IConversationService
|
|||
Task<Conversation> GetConversationRecordOrCreateNew(string agentId);
|
||||
|
||||
bool IsConversationMode();
|
||||
|
||||
void SaveStates();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using BotSharp.Abstraction.Plugins.Models;
|
|||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Roles.Models;
|
||||
using BotSharp.Abstraction.Shared;
|
||||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
using BotSharp.Abstraction.Statistics.Models;
|
||||
using BotSharp.Abstraction.Tasks.Models;
|
||||
using BotSharp.Abstraction.Translation.Models;
|
||||
|
|
@ -120,8 +121,10 @@ public interface IBotSharpRepository : IHaveServiceProvider
|
|||
#endregion
|
||||
|
||||
#region Statistics
|
||||
BotSharpStats? GetGlobalStats(string category, string group, DateTime recordTime) => throw new NotImplementedException();
|
||||
bool SaveGlobalStats(BotSharpStats body) => throw new NotImplementedException();
|
||||
BotSharpStats? GetGlobalStats(string metric, string dimension, DateTime recordTime, StatsInterval interval)
|
||||
=> throw new NotImplementedException();
|
||||
bool SaveGlobalStats(BotSharpStats body)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace BotSharp.Abstraction.Statistics.Enums;
|
||||
|
||||
public enum StatsInterval
|
||||
{
|
||||
Hour = 1,
|
||||
Day = 2,
|
||||
Week = 3,
|
||||
Month = 4
|
||||
}
|
||||
|
|
@ -1,34 +1,80 @@
|
|||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
|
||||
namespace BotSharp.Abstraction.Statistics.Models;
|
||||
|
||||
public class BotSharpStats
|
||||
{
|
||||
[JsonPropertyName("category")]
|
||||
public string Category { get; set; } = null!;
|
||||
[JsonPropertyName("metric")]
|
||||
public string Metric { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("group")]
|
||||
public string Group { get; set; } = null!;
|
||||
[JsonPropertyName("dimension")]
|
||||
public string Dimension { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public IDictionary<string, double> Data { get; set; } = new Dictionary<string, double>();
|
||||
|
||||
private DateTime innerRecordTime;
|
||||
|
||||
[JsonPropertyName("record_time")]
|
||||
public DateTime RecordTime
|
||||
public DateTime RecordTime { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[JsonIgnore]
|
||||
public StatsInterval IntervalType { get; set; }
|
||||
|
||||
[JsonPropertyName("interval")]
|
||||
public string Interval
|
||||
{
|
||||
get
|
||||
{
|
||||
return innerRecordTime;
|
||||
}
|
||||
return IntervalType.ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
var date = new DateTime(value.Year, value.Month, value.Day, value.Hour, 0, 0);
|
||||
innerRecordTime = DateTime.SpecifyKind(date, DateTimeKind.Utc);
|
||||
if (Enum.TryParse(value, out StatsInterval type))
|
||||
{
|
||||
IntervalType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonPropertyName("start_time")]
|
||||
public DateTime StartTime { get; set; }
|
||||
|
||||
[JsonPropertyName("end_time")]
|
||||
public DateTime EndTime { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Category}-{Group}: {Data?.Count ?? 0} ({RecordTime})";
|
||||
return $"{Metric}-{Dimension} ({Interval}): {Data?.Count ?? 0}";
|
||||
}
|
||||
|
||||
public static (DateTime, DateTime) BuildTimeInterval(DateTime recordTime, StatsInterval interval)
|
||||
{
|
||||
DateTime startTime = recordTime;
|
||||
DateTime endTime = DateTime.UtcNow;
|
||||
|
||||
switch (interval)
|
||||
{
|
||||
case StatsInterval.Hour:
|
||||
startTime = new DateTime(recordTime.Year, recordTime.Month, recordTime.Day, recordTime.Hour, 0, 0);
|
||||
endTime = startTime.AddHours(1);
|
||||
break;
|
||||
case StatsInterval.Week:
|
||||
var dayOfWeek = startTime.DayOfWeek;
|
||||
var firstDayOfWeek = startTime.AddDays(-(int)dayOfWeek);
|
||||
startTime = new DateTime(firstDayOfWeek.Year, firstDayOfWeek.Month, firstDayOfWeek.Day, 0, 0, 0);
|
||||
endTime = startTime.AddDays(7);
|
||||
break;
|
||||
case StatsInterval.Month:
|
||||
startTime = new DateTime(recordTime.Year, recordTime.Month, 1);
|
||||
endTime = startTime.AddMonths(1);
|
||||
break;
|
||||
default:
|
||||
startTime = new DateTime(recordTime.Year, recordTime.Month, recordTime.Day, 0, 0, 0);
|
||||
endTime = startTime.AddDays(1);
|
||||
break;
|
||||
}
|
||||
|
||||
startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc);
|
||||
endTime = DateTime.SpecifyKind(endTime, DateTimeKind.Utc);
|
||||
return (startTime, endTime);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
|
||||
namespace BotSharp.Abstraction.Statistics.Models;
|
||||
|
||||
public class BotSharpStatsInput
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public string Group { get; set; }
|
||||
public string Metric { get; set; }
|
||||
public string Dimension { get; set; }
|
||||
public List<StatsKeyValuePair> Data { get; set; } = [];
|
||||
public DateTime RecordTime { get; set; }
|
||||
public DateTime RecordTime { get; set; } = DateTime.UtcNow;
|
||||
public StatsInterval IntervalType { get; set; } = StatsInterval.Day;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using BotSharp.Abstraction.Infrastructures.Events;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BotSharp.Core.Crontab.Services;
|
||||
|
||||
|
|
@ -22,6 +21,7 @@ public class CrontabEventSubscription : BackgroundService
|
|||
|
||||
using (var scope = _services.CreateScope())
|
||||
{
|
||||
var publisher = scope.ServiceProvider.GetRequiredService<IEventPublisher>();
|
||||
var subscriber = scope.ServiceProvider.GetRequiredService<IEventSubscriber>();
|
||||
var cron = scope.ServiceProvider.GetRequiredService<ICrontabService>();
|
||||
var crons = await cron.GetCrontable();
|
||||
|
|
@ -29,15 +29,20 @@ public class CrontabEventSubscription : BackgroundService
|
|||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
// Clean unhandled messages
|
||||
await publisher.RemoveAsync($"Crontab:{item.Title}", count: 100);
|
||||
|
||||
await subscriber.SubscribeAsync($"Crontab:{item.Title}",
|
||||
"Crontab",
|
||||
port: 0,
|
||||
priorityEnabled: false, async (sender, args) =>
|
||||
priorityEnabled: false,
|
||||
async (sender, args) =>
|
||||
{
|
||||
var scope = _services.CreateScope();
|
||||
cron = scope.ServiceProvider.GetRequiredService<ICrontabService>();
|
||||
await cron.ScheduledTimeArrived(item);
|
||||
}, stoppingToken: stoppingToken);
|
||||
},
|
||||
stoppingToken: stoppingToken);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Core.Rules.Engines;
|
||||
|
||||
public interface IRuleEngine
|
||||
{
|
||||
Task Triggered(IRuleTrigger trigger, string data);
|
||||
Task Triggered(IRuleTrigger trigger, string data, List<MessageState>? states = null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class RuleEngine : IRuleEngine
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Triggered(IRuleTrigger trigger, string data)
|
||||
public async Task Triggered(IRuleTrigger trigger, string data, List<MessageState>? states = null)
|
||||
{
|
||||
// Pull all user defined rules
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
|
|
@ -36,10 +36,11 @@ public class RuleEngine : IRuleEngine
|
|||
|
||||
// Trigger the agents
|
||||
var instructService = _services.GetRequiredService<IInstructService>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
|
||||
|
||||
foreach (var agent in preFilteredAgents)
|
||||
{
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var conv = await convService.NewConversation(new Conversation
|
||||
{
|
||||
Channel = trigger.Channel,
|
||||
|
|
@ -49,18 +50,25 @@ public class RuleEngine : IRuleEngine
|
|||
|
||||
var message = new RoleDialogModel(AgentRole.User, data);
|
||||
|
||||
var states = new List<MessageState>
|
||||
var allStates = new List<MessageState>
|
||||
{
|
||||
new("channel", trigger.Channel),
|
||||
new("channel_id", trigger.EntityId)
|
||||
new("channel", trigger.Channel)
|
||||
};
|
||||
convService.SetConversationId(conv.Id, states);
|
||||
|
||||
if (states != null)
|
||||
{
|
||||
allStates.AddRange(states);
|
||||
}
|
||||
|
||||
convService.SetConversationId(conv.Id, allStates);
|
||||
|
||||
await convService.SendMessage(agent.Id,
|
||||
message,
|
||||
null,
|
||||
msg => Task.CompletedTask);
|
||||
|
||||
convService.SaveStates();
|
||||
|
||||
/*foreach (var rule in agent.Rules)
|
||||
{
|
||||
var userSay = $"===Input data with Before and After values===\r\n{data}\r\n\r\n===Trigger Criteria===\r\n{rule.Criteria}\r\n\r\nJust output 1 or 0 without explanation: ";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
namespace BotSharp.Core.Conversations.Services;
|
||||
|
||||
public partial class ConversationService : IConversationService
|
||||
public partial class ConversationService
|
||||
{
|
||||
public async Task<bool> TruncateConversation(string conversationId, string messageId, string? newMessageId = null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using BotSharp.Abstraction.Infrastructures.Enums;
|
|||
|
||||
namespace BotSharp.Core.Conversations.Services;
|
||||
|
||||
public partial class ConversationService : IConversationService
|
||||
public partial class ConversationService
|
||||
{
|
||||
public async Task UpdateBreakpoint(bool resetStates = false, string? reason = null, params string[] excludedStates)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -216,4 +216,9 @@ public partial class ConversationService : IConversationService
|
|||
var agent = db.GetAgent(routingCtx.EntryAgentId, basicsOnly: true);
|
||||
return agent?.MaxMessageCount;
|
||||
}
|
||||
|
||||
public void SaveStates()
|
||||
{
|
||||
_state.Save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,11 +211,11 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
{
|
||||
if (_conversationId == null)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
var states = new List<StateKeyValue>();
|
||||
|
||||
foreach (var pair in _curStates)
|
||||
{
|
||||
var key = pair.Key;
|
||||
|
|
@ -244,6 +244,7 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
}
|
||||
|
||||
_db.UpdateConversationStates(_conversationId, states);
|
||||
Reset();
|
||||
_logger.LogInformation($"Saved states of conversation {_conversationId}");
|
||||
}
|
||||
|
||||
|
|
@ -421,4 +422,10 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
{
|
||||
_curStates.Clear();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_curStates.Clear();
|
||||
_historyStates.Clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,9 +62,10 @@ public class TokenStatistics : ITokenStatistics
|
|||
var globalStats = _services.GetRequiredService<IBotSharpStatsService>();
|
||||
var body = new BotSharpStatsInput
|
||||
{
|
||||
Category = StatsCategory.AgentLlmCost,
|
||||
Group = message.CurrentAgentId,
|
||||
Metric = StatsCategory.AgentLlmCost,
|
||||
Dimension = message.CurrentAgentId,
|
||||
RecordTime = DateTime.UtcNow,
|
||||
IntervalType = StatsInterval.Day,
|
||||
Data = [
|
||||
new StatsKeyValuePair("prompt_token_count_total", stats.PromptCount),
|
||||
new StatsKeyValuePair("completion_token_count_total", stats.CompletionCount),
|
||||
|
|
|
|||
|
|
@ -182,7 +182,10 @@ public class RedisPublisher : IEventPublisher
|
|||
var db = _redis.GetDatabase();
|
||||
|
||||
var entries = await db.StreamRangeAsync(channel, "-", "+", count: count, messageOrder: Order.Ascending);
|
||||
var deletedCount = await db.StreamDeleteAsync(channel, entries.Select(x => x.Id).ToArray());
|
||||
_logger.LogWarning($"Deleted {deletedCount} messages from Redis stream {channel}");
|
||||
if (entries.Length > 0)
|
||||
{
|
||||
var deletedCount = await db.StreamDeleteAsync(channel, entries.Select(x => x.Id).ToArray());
|
||||
_logger.LogWarning($"Deleted {deletedCount} messages from Redis stream {channel}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,28 +4,34 @@ namespace BotSharp.Core.Repository;
|
|||
|
||||
public partial class FileRepository
|
||||
{
|
||||
public BotSharpStats? GetGlobalStats(string category, string group, DateTime recordTime)
|
||||
public BotSharpStats? GetGlobalStats(string metric, string dimension, DateTime recordTime, StatsInterval interval)
|
||||
{
|
||||
var baseDir = Path.Combine(_dbSettings.FileRepository, STATS_FOLDER);
|
||||
var dir = Path.Combine(baseDir, category, recordTime.Year.ToString(), recordTime.Month.ToString("D2"));
|
||||
var (startTime, endTime) = BotSharpStats.BuildTimeInterval(recordTime, interval);
|
||||
var dir = Path.Combine(baseDir, metric, startTime.Year.ToString(), startTime.Month.ToString("D2"));
|
||||
if (!Directory.Exists(dir)) return null;
|
||||
|
||||
var file = Directory.GetFiles(dir).FirstOrDefault(x => Path.GetFileName(x) == STATS_FILE);
|
||||
if (file == null) return null;
|
||||
|
||||
var time = BuildRecordTime(recordTime);
|
||||
var text = File.ReadAllText(file);
|
||||
var list = JsonSerializer.Deserialize<List<BotSharpStats>>(text, _options);
|
||||
var found = list?.FirstOrDefault(x => x.Category.IsEqualTo(category)
|
||||
&& x.Group.IsEqualTo(group)
|
||||
&& x.RecordTime == time);
|
||||
var found = list?.FirstOrDefault(x => x.Metric.IsEqualTo(metric)
|
||||
&& x.Dimension.IsEqualTo(dimension)
|
||||
&& x.StartTime == startTime
|
||||
&& x.EndTime == endTime);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public bool SaveGlobalStats(BotSharpStats body)
|
||||
{
|
||||
var baseDir = Path.Combine(_dbSettings.FileRepository, STATS_FOLDER);
|
||||
var dir = Path.Combine(baseDir, body.Category, body.RecordTime.Year.ToString(), body.RecordTime.Month.ToString("D2"));
|
||||
var (startTime, endTime) = BotSharpStats.BuildTimeInterval(body.RecordTime, body.IntervalType);
|
||||
body.StartTime = startTime;
|
||||
body.EndTime = endTime;
|
||||
|
||||
var dir = Path.Combine(baseDir, body.Metric, startTime.Year.ToString(), startTime.Month.ToString("D2"));
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
|
|
@ -39,19 +45,22 @@ public partial class FileRepository
|
|||
}
|
||||
else
|
||||
{
|
||||
var time = BuildRecordTime(body.RecordTime);
|
||||
var text = File.ReadAllText(file);
|
||||
var list = JsonSerializer.Deserialize<List<BotSharpStats>>(text, _options);
|
||||
var found = list?.FirstOrDefault(x => x.Category.IsEqualTo(body.Category)
|
||||
&& x.Group.IsEqualTo(body.Group)
|
||||
&& x.RecordTime == time);
|
||||
var found = list?.FirstOrDefault(x => x.Metric.IsEqualTo(body.Metric)
|
||||
&& x.Dimension.IsEqualTo(body.Dimension)
|
||||
&& x.StartTime == startTime
|
||||
&& x.EndTime == endTime);
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
found.Category = body.Category;
|
||||
found.Group = body.Group;
|
||||
found.Metric = body.Metric;
|
||||
found.Dimension = body.Dimension;
|
||||
found.Data = body.Data;
|
||||
found.RecordTime = body.RecordTime;
|
||||
found.StartTime = body.StartTime;
|
||||
found.EndTime = body.EndTime;
|
||||
found.Interval = body.Interval;
|
||||
}
|
||||
else if (list != null)
|
||||
{
|
||||
|
|
@ -67,12 +76,4 @@ public partial class FileRepository
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
private DateTime BuildRecordTime(DateTime date)
|
||||
{
|
||||
var recordDate = new DateTime(date.Year, date.Month, date.Day, date.Hour, 0, 0);
|
||||
return DateTime.SpecifyKind(recordDate, DateTimeKind.Utc);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ public class BotSharpStatsService : IBotSharpStatsService
|
|||
if (!_settings.Enabled
|
||||
|| string.IsNullOrEmpty(resourceKey)
|
||||
|| input == null
|
||||
|| string.IsNullOrEmpty(input.Category)
|
||||
|| string.IsNullOrEmpty(input.Group))
|
||||
|| string.IsNullOrEmpty(input.Metric)
|
||||
|| string.IsNullOrEmpty(input.Dimension)
|
||||
|| input.Data.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -39,14 +40,15 @@ public class BotSharpStatsService : IBotSharpStatsService
|
|||
var res = locker.Lock(resourceKey, () =>
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var body = db.GetGlobalStats(input.Category, input.Group, input.RecordTime);
|
||||
var body = db.GetGlobalStats(input.Metric, input.Dimension, input.RecordTime, input.IntervalType);
|
||||
if (body == null)
|
||||
{
|
||||
var stats = new BotSharpStats
|
||||
{
|
||||
Category = input.Category,
|
||||
Group = input.Group,
|
||||
Metric = input.Metric,
|
||||
Dimension = input.Dimension,
|
||||
RecordTime = input.RecordTime,
|
||||
IntervalType = input.IntervalType,
|
||||
Data = input.Data.ToDictionary(x => x.Key, x => x.Value)
|
||||
};
|
||||
db.SaveGlobalStats(stats);
|
||||
|
|
@ -85,7 +87,7 @@ public class BotSharpStatsService : IBotSharpStatsService
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error when updating global stats {input.Category}-{input.Group}. {ex.Message}\r\n{ex.InnerException}");
|
||||
_logger.LogError($"Error when updating global stats {input.Metric}-{input.Dimension}. {ex.Message}\r\n{ex.InnerException}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,12 +31,13 @@ public class GlobalStatsConversationHook : ConversationHookBase
|
|||
|
||||
var body = new BotSharpStatsInput
|
||||
{
|
||||
Category = StatsCategory.AgentCall,
|
||||
Group = message.CurrentAgentId,
|
||||
Metric = StatsCategory.AgentCall,
|
||||
Dimension = message.CurrentAgentId,
|
||||
RecordTime = DateTime.UtcNow,
|
||||
IntervalType = StatsInterval.Day,
|
||||
Data = [
|
||||
new StatsKeyValuePair("agent_call_count", 1)
|
||||
],
|
||||
RecordTime = DateTime.UtcNow
|
||||
]
|
||||
};
|
||||
globalStats.UpdateStats("global-agent-call", body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Collections;
|
||||
|
||||
public class GlobalStatisticsDocument : MongoBase
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public string Group { get; set; }
|
||||
public string Metric { get; set; }
|
||||
public string Dimension { get; set; }
|
||||
public IDictionary<string, double> Data { get; set; } = new Dictionary<string, double>();
|
||||
public DateTime RecordTime { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public DateTime EndTime { get; set; }
|
||||
public string Interval { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
using BotSharp.Abstraction.Statistics.Models;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Repository;
|
||||
|
||||
public partial class MongoRepository
|
||||
{
|
||||
public BotSharpStats? GetGlobalStats(string category, string group, DateTime recordTime)
|
||||
public BotSharpStats? GetGlobalStats(string metric, string dimension, DateTime recordTime, StatsInterval interval)
|
||||
{
|
||||
var time = BuildRecordTime(recordTime);
|
||||
var (startTime, endTime) = BotSharpStats.BuildTimeInterval(recordTime, interval);
|
||||
|
||||
var builder = Builders<GlobalStatisticsDocument>.Filter;
|
||||
var filters = new List<FilterDefinition<GlobalStatisticsDocument>>()
|
||||
{
|
||||
builder.Eq(x => x.Category, category),
|
||||
builder.Eq(x => x.Group, group),
|
||||
builder.Eq(x => x.RecordTime, time)
|
||||
builder.Eq(x => x.Metric, metric),
|
||||
builder.Eq(x => x.Dimension, dimension),
|
||||
builder.Eq(x => x.StartTime, startTime),
|
||||
builder.Eq(x => x.EndTime, endTime)
|
||||
};
|
||||
|
||||
var filterDef = builder.And(filters);
|
||||
|
|
@ -22,41 +24,44 @@ public partial class MongoRepository
|
|||
|
||||
return new BotSharpStats
|
||||
{
|
||||
Category = found.Category,
|
||||
Group = found.Group,
|
||||
Metric = found.Metric,
|
||||
Dimension = found.Dimension,
|
||||
Data = found.Data,
|
||||
RecordTime = found.RecordTime
|
||||
RecordTime = found.RecordTime,
|
||||
StartTime = startTime,
|
||||
EndTime = endTime,
|
||||
Interval = interval.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
public bool SaveGlobalStats(BotSharpStats body)
|
||||
{
|
||||
var time = BuildRecordTime(body.RecordTime);
|
||||
var (startTime, endTime) = BotSharpStats.BuildTimeInterval(body.RecordTime, body.IntervalType);
|
||||
body.RecordTime = DateTime.SpecifyKind(body.RecordTime, DateTimeKind.Utc);
|
||||
body.StartTime = startTime;
|
||||
body.EndTime = endTime;
|
||||
|
||||
var builder = Builders<GlobalStatisticsDocument>.Filter;
|
||||
var filters = new List<FilterDefinition<GlobalStatisticsDocument>>()
|
||||
{
|
||||
builder.Eq(x => x.Category, body.Category),
|
||||
builder.Eq(x => x.Group, body.Group),
|
||||
builder.Eq(x => x.RecordTime, time)
|
||||
builder.Eq(x => x.Metric, body.Metric),
|
||||
builder.Eq(x => x.Dimension, body.Dimension),
|
||||
builder.Eq(x => x.StartTime, startTime),
|
||||
builder.Eq(x => x.EndTime, endTime)
|
||||
};
|
||||
|
||||
var filterDef = builder.And(filters);
|
||||
var updateDef = Builders<GlobalStatisticsDocument>.Update
|
||||
.SetOnInsert(x => x.Id, Guid.NewGuid().ToString())
|
||||
.Set(x => x.Category, body.Category)
|
||||
.Set(x => x.Group, body.Group)
|
||||
.Set(x => x.Metric, body.Metric)
|
||||
.Set(x => x.Dimension, body.Dimension)
|
||||
.Set(x => x.Data, body.Data)
|
||||
.Set(x => x.RecordTime, time);
|
||||
.Set(x => x.StartTime, body.StartTime)
|
||||
.Set(x => x.EndTime, body.EndTime)
|
||||
.Set(x => x.Interval, body.Interval)
|
||||
.Set(x => x.RecordTime, body.RecordTime);
|
||||
|
||||
_dc.GlobalStatistics.UpdateOne(filterDef, updateDef, _options);
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
private DateTime BuildRecordTime(DateTime date)
|
||||
{
|
||||
var recordDate = new DateTime(date.Year, date.Month, date.Day, date.Hour, 0, 0);
|
||||
return DateTime.SpecifyKind(recordDate, DateTimeKind.Utc);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue