Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/mythz/pvq.app
Browse files Browse the repository at this point in the history
  • Loading branch information
mythz committed Mar 28, 2024
2 parents 6f09171 + f8fe5b0 commit 6606b10
Show file tree
Hide file tree
Showing 3 changed files with 317 additions and 2 deletions.
174 changes: 174 additions & 0 deletions MyApp.ServiceInterface/LeaderboardServices.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
using MyApp.ServiceModel;
using ServiceStack;
using ServiceStack.OrmLite;

namespace MyApp.ServiceInterface;

public class LeaderboardServices : Service
{
/// <summary>
/// Leader board stats
/// - Most liked models by human votes
/// - Most liked models by LLM votes
/// - Answerer win rate
/// - Human vs LLM win rate by human votes
/// - Human vs LLM win rate by LLM votes
/// - Model win rate by tag
/// - Model total score
/// - Model total score by tag
/// </summary>
/// <param name="request"></param>
public async Task<object> Any(CalculateLeaderBoard request)
{
var statTotals = await Db.SelectAsync<StatTotals>();
// filter to answers only
var answers = statTotals.Where(x => x.Id.Contains('-')).ToList();
// Sum up votes by model, first group by UserName
var statsByUser = answers.GroupBy(x => x.Id.SplitOnFirst('-')[1]).Select(x => new StatTotals
{
Id = x.Key,
UpVotes = x.Sum(y => y.UpVotes),
DownVotes = x.Sum(y => y.DownVotes),
StartingUpVotes = x.Sum(y => y.StartingUpVotes),
FavoriteCount = x.Sum(y => y.FavoriteCount)
}).ToList();

var statQuestions = statTotals.Where(x => !x.Id.Contains('-')).ToList();

var overallWinRates = statsByUser.GroupBy(x => x.Id).Select(y =>
{
var res = new LeaderBoardWinRate
{
Id = y.Key,
WinRate = CalculateWinRate(answers, y.Key, statQuestions.Count)
};
return res;
}).ToList();

var modelScale = 1 / overallWinRates.Where(x => IsHuman(x.Id) == false)
.Sum(y => y.WinRate);


var leaderBoard = new CalculateLeaderboardResponse
{
MostLikedModels = statsByUser.Where(x => IsHuman(x.Id) == false)
.OrderByDescending(x => x.GetScore())
.Select(x => new ModelTotalScore
{
Id = x.Id,
TotalScore = x.GetScore()
}).ToList(),
MostLikedModelsByLlm = statsByUser.Where(x => IsHuman(x.Id) == false)
.OrderByDescending(x => x.StartingUpVotes)
.Select(x => new ModelTotalStartUpVotes
{
Id = x.Id,
StartingUpVotes = x.GetScore()
})
.ToList(),
AnswererWinRate = overallWinRates,
ModelWinRate = overallWinRates.Where(x => IsHuman(x.Id) == false)
.Select(x => new ModelWinRate
{
Id = x.Id,
WinRate = x.WinRate * modelScale * 100
}).ToList(),
ModelTotalScore = statsByUser.GroupBy(x => x.Id)
.Select(x => new ModelTotalScore
{
Id = x.Key,
TotalScore = x.Sum(y => y.GetScore())
}).ToList()
};

return leaderBoard;
}

bool IsHuman(string id)
{
return id == "accepted" || id == "most-voted";
}


/// <summary>
/// Take all answers, group by PostId derived user, select the answer with the highest score
/// all divided by the total question count
/// </summary>
/// <param name="statTotalsList"></param>
/// <param name="name"></param>
/// <param name="questionCount"></param>
/// <returns></returns>
double CalculateWinRate(List<StatTotals> statTotalsList, string name, int questionCount)
{
return ((double)statTotalsList
.GroupBy(a => a.PostId
).Select(aq => aq
.MaxBy(b => b.GetScore()))
.Count(winner =>
winner != null && winner.Id.Contains("-") && winner.Id.SplitOnFirst('-')[1] == name)
/ questionCount) * 100;
}
}

public class CalculateLeaderboardResponse
{
public List<ModelTotalScore> MostLikedModels { get; set; }
public List<ModelTotalStartUpVotes> MostLikedModelsByLlm { get; set; }
public List<LeaderBoardWinRate> AnswererWinRate { get; set; }
public List<LeaderBoardWinRate> HumanVsLlmWinRateByHumanVotes { get; set; }
public List<LeaderBoardWinRate> HumanVsLlmWinRateByLlmVotes { get; set; }
public List<ModelWinRateByTag> ModelWinRateByTag { get; set; }
public List<ModelTotalScore> ModelTotalScore { get; set; }
public List<ModelTotalScoreByTag> ModelTotalScoreByTag { get; set; }
public List<ModelWinRate> ModelWinRate { get; set; }
}

public class ModelTotalScoreByTag
{
public string Id { get; set; }
public string Tag { get; set; }
public int TotalScore { get; set; }
}

public class ModelTotalScore
{
public string Id { get; set; }
public int TotalScore { get; set; }
}

public class ModelTotalStartUpVotes
{
public string Id { get; set; }
public int StartingUpVotes { get; set; }
}

public class ModelWinRateByTag
{
public string Id { get; set; }
public string Tag { get; set; }
public double WinRate { get; set; }
}

public class ModelWinRate
{
public string Id { get; set; }
public double WinRate { get; set; }
}

public class LeaderBoardWinRate
{
public string Id { get; set; }
public double WinRate { get; set; }
}

public class LeaderBoardWinRateByTag
{
public string Id { get; set; }
public string Tag { get; set; }
public double WinRate { get; set; }
}

public class CalculateLeaderBoard : IReturn<CalculateLeaderboardResponse>, IGet
{

}
28 changes: 26 additions & 2 deletions MyApp/Components/Pages/Leaderboard.razor
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
@page "/leaderboard"
@using MyApp.ServiceInterface
@inherits AppComponentBase

<PageTitle>Leaderboard</PageTitle>

<div class="mt-8 mb-20 mx-auto max-w-fit">
<Heading1>Counter</Heading1>
<Heading1>Leaderboard</Heading1>

<div data-component="pages/Counter.mjs"></div>
<div class="mt-8">
@if (data != null)
{
<LeaderboardView LeaderBoardData="@data"/>
}
</div>

</div>

@code {

CalculateLeaderboardResponse? data;

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
var api = await ApiAsync(new CalculateLeaderBoard());
if (api.Succeeded)
data = api.Response;
else
Console.WriteLine(api.Error?.Message);

}

}
117 changes: 117 additions & 0 deletions MyApp/Components/Shared/LeaderboardView.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
@using MyApp.ServiceInterface

<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div class="bg-blue-500 text-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-bold mb-4">Most Liked Models</h2>
<div class="space-y-4">
@foreach (var model in LeaderBoardData.MostLikedModelsByLlm.OrderByDescending(x => x.StartingUpVotes))
{
<div class="flex items-center">
<img src="@GetAvatarUrl(model.Id)" alt="Avatar" class="w-12 h-12 rounded-full mr-4" />
<div class="flex-1">
<h3 class="text-lg font-semibold">@GetModelName(model.Id)</h3>
<div class="text-sm text-green-200">@model.StartingUpVotes votes</div>
</div>
</div>
}
</div>
</div>

<div class="bg-blue-500 text-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-bold mb-4">Total Votes</h2>
<div class="space-y-4">
@foreach (var model in LeaderBoardData.ModelTotalScore.OrderByDescending(x => x.TotalScore))
{
<div class="flex items-center">
<img src="@GetAvatarUrl(model.Id)" alt="Avatar" class="w-12 h-12 rounded-full mr-4" />
<div class="flex-1">
<h3 class="text-lg font-semibold">@GetModelName(model.Id)</h3>
<div class="text-sm text-green-200">@model.TotalScore votes</div>
</div>
</div>
}
</div>
</div>

<div class="bg-blue-500 text-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-bold mb-4">Overall Win Rate</h2>
<div class="space-y-4">
@foreach (var model in LeaderBoardData.AnswererWinRate.OrderByDescending(x => x.WinRate))
{
<div class="flex items-center">
<img src="@GetAvatarUrl(model.Id)" alt="Avatar" class="w-12 h-12 rounded-full mr-4" />
<div class="flex-1">
<h3 class="text-lg font-semibold">@GetModelName(model.Id)</h3>
<div class="text-sm text-green-200">@(Math.Round(model.WinRate,2)) %</div>
</div>
</div>
}
</div>
</div>

<div class="bg-blue-500 text-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-bold mb-4">Win Rate By Models</h2>
<div class="space-y-4">
@foreach (var model in LeaderBoardData.ModelWinRate.OrderByDescending(x => x.WinRate))
{
<div class="flex items-center">
<img src="@GetAvatarUrl(model.Id)" alt="Avatar" class="w-12 h-12 rounded-full mr-4" />
<div class="flex-1">
<h3 class="text-lg font-semibold">@GetModelName(model.Id)</h3>
<div class="text-sm text-green-200">@(Math.Round(model.WinRate,2)) %</div>
</div>
</div>
}
</div>
</div>

</div>

@code {
[Parameter]
public CalculateLeaderboardResponse LeaderBoardData { get; set; }

private string GetModelName(string modelId)
{
if (modelAliases.TryGetValue(modelId, out var alias))
{
return alias;
}
return modelId;
}

private string GetAvatarUrl(string modelId)
{
var userName = modelUserMapping.TryGetValue(modelId, out var value) ? value : modelId;
return $"/avatar/{userName}";
}

Dictionary<string, string> modelUserMapping = new()
{
{ "mistral", "mistral" },
{ "mixtral", "mixtral" },
{ "mixtral-8x7b", "mixtral" },
{ "mixtral-8x7b-32768", "mixtral"},
{ "codellama", "codellama" },
{ "deepseek-coder:6.7b", "deepseek-coder" },
{ "deepseek-coder-6", "deepseek-coder"},
{ "gemma-2b", "gemma-2b" },
{ "gemma", "gemma" },
{ "gemma-7b", "gemma" },
{ "phi", "phi" }
};

Dictionary<string, string> modelAliases = new()
{
{ "mistral", "Mistral 7B" },
{ "mixtral", "Mixtral 8x7B" },
{ "codellama", "Codellama" },
{ "deepseek-coder:6.7b", "Deepseek Coder 6.7B" },
{ "deepseek-coder-6", "Deepseek Coder 6.7B" },
{ "gemma-2b", "Gemma 2B" },
{ "gemma", "Gemma 7B" },
{ "gemma-7b", "Gemma 7B" },
{ "phi", "Phi" }
};

}

0 comments on commit 6606b10

Please sign in to comment.