< Summary

Information
Class: Intentum.Analytics.IntentProfileService
Assembly: Intentum.Analytics
File(s): /home/runner/work/Intentum/Intentum/src/Intentum.Analytics/IntentProfileService.cs
Line coverage
91%
Covered lines: 53
Uncovered lines: 5
Coverable lines: 58
Total lines: 87
Line coverage: 91.3%
Branch coverage
71%
Covered branches: 20
Total branches: 28
Branch coverage: 71.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)50%22100%
GetProfileAsync()73.07%262690.19%

File(s)

/home/runner/work/Intentum/Intentum/src/Intentum.Analytics/IntentProfileService.cs

#LineLine coverage
 1using Intentum.Analytics.Models;
 2
 3namespace Intentum.Analytics;
 4
 5/// <summary>
 6/// Builds an intent-based profile for an entity from timeline data (aggregate intent names, confidence distribution → l
 7/// </summary>
 8public sealed class IntentProfileService : IIntentProfileService
 9{
 10    private readonly IIntentAnalytics _analytics;
 11
 212    public IntentProfileService(IIntentAnalytics analytics)
 213    {
 214        _analytics = analytics ?? throw new ArgumentNullException(nameof(analytics));
 215    }
 16
 17    /// <inheritdoc />
 18    public async Task<IntentProfile> GetProfileAsync(
 19        string entityId,
 20        DateTimeOffset start,
 21        DateTimeOffset end,
 22        CancellationToken cancellationToken = default)
 223    {
 224        var timeline = await _analytics.GetIntentTimelineAsync(entityId, start, end, cancellationToken);
 225        var points = timeline.Points;
 26
 227        if (points.Count == 0)
 128        {
 129            return new IntentProfile(
 130                entityId,
 131                start,
 132                end,
 133                [],
 134                new Dictionary<string, int>(),
 135                0,
 136                0,
 137                0);
 38        }
 39
 140        var intentCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
 141        var totalScore = 0.0;
 142        var highCount = 0;
 43
 744        foreach (var p in points)
 245        {
 246            intentCounts[p.IntentName] = intentCounts.GetValueOrDefault(p.IntentName, 0) + 1;
 247            totalScore += p.ConfidenceScore;
 248            if (p.ConfidenceLevel is "High" or "Certain")
 149                highCount++;
 250        }
 51
 152        var avgScore = totalScore / points.Count;
 153        var highPct = 100.0 * highCount / points.Count;
 54
 155        var topIntents = intentCounts
 156            .OrderByDescending(kv => kv.Value)
 157            .Take(10)
 358            .ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase);
 59
 160        var labels = new List<string>();
 61
 162        if (points.Count >= 5)
 063            labels.Add("active");
 164        if (avgScore >= 0.7)
 165            labels.Add("high_confidence");
 066        else if (avgScore < 0.4)
 067            labels.Add("low_confidence");
 168        if (highPct >= 70)
 069            labels.Add("quick_decider");
 170        if (intentCounts.Count >= 3 && points.Count >= 5)
 071            labels.Add("diverse_intents");
 72
 273        var topIntentName = intentCounts.OrderByDescending(kv => kv.Value).FirstOrDefault().Key;
 174        if (!string.IsNullOrEmpty(topIntentName) && intentCounts[topIntentName] >= Math.Max(2, points.Count / 2))
 175            labels.Add($"frequent_{topIntentName.ToLowerInvariant().Replace(" ", "_")}");
 76
 177        return new IntentProfile(
 178            entityId,
 179            start,
 180            end,
 181            labels,
 182            topIntents,
 183            avgScore,
 184            highPct,
 185            points.Count);
 286    }
 87}