Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion StabilityMatrix.Avalonia/Languages/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions StabilityMatrix.Avalonia/Languages/Resources.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1137,9 +1137,6 @@ Konto-Tokens sind nach dem Speichern nicht mehr einsehbar. Bitte notiere sie, we
<data name="Label_PromptAmplifierRateLimitTitle" xml:space="preserve">
<value>Nutzungslimit erreicht</value>
</data>
<data name="Label_PromptAmplifierRateLimitMessage" xml:space="preserve">
<value>Du hast diesen Monat keine Prompt-Amplifier-Nutzung mehr übrig. Die Nutzung wird am 1. jedes Monats zurückgesetzt. (noch {0} Tage)</value>
</data>
<data name="Label_PromptAmplifierError" xml:space="preserve">
<value>Prompt-Amplifier-Fehler</value>
</data>
Expand Down
3 changes: 0 additions & 3 deletions StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1229,9 +1229,6 @@ Les jetons de compte ne seront plus visibles après l'enregistrement. Veuillez e
<data name="Label_PromptAmplifierRateLimitTitle" xml:space="preserve">
<value>Limite d'utilisation atteinte</value>
</data>
<data name="Label_PromptAmplifierRateLimitMessage" xml:space="preserve">
<value>Vous n'avez plus d'utilisation Prompt Amplifier ce mois-ci. L'utilisation est réinitialisée le 1er de chaque mois. ({0} jours restants)</value>
</data>
<data name="Label_PromptAmplifierError" xml:space="preserve">
<value>Erreur Prompt Amplifier</value>
</data>
Expand Down
3 changes: 0 additions & 3 deletions StabilityMatrix.Avalonia/Languages/Resources.ja-JP.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1550,9 +1550,6 @@ Sparkは兆レベルのパラメータを持つ基盤モデルで、膨大なパ
<data name="Label_PromptAmplifierRateLimitTitle" xml:space="preserve">
<value>利用上限に達しました</value>
</data>
<data name="Label_PromptAmplifierRateLimitMessage" xml:space="preserve">
<value>今月のプロンプトアンプリファイアの利用回数がなくなりました。利用回数は毎月1日にリセットされます。(残り{0}日)</value>
</data>
<data name="Label_PromptAmplifierError" xml:space="preserve">
<value>プロンプトアンプリファイアエラー</value>
</data>
Expand Down
3 changes: 0 additions & 3 deletions StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1376,9 +1376,6 @@
<data name="Label_PromptAmplifierRateLimitTitle" xml:space="preserve">
<value>사용 한도 도달</value>
</data>
<data name="Label_PromptAmplifierRateLimitMessage" xml:space="preserve">
<value>이번 달 프롬프트 증폭기 사용량이 모두 소진되었습니다. 사용량은 매월 1일에 초기화됩니다. ({0}일 남음)</value>
</data>
<data name="Label_PromptAmplifierError" xml:space="preserve">
<value>프롬프트 증폭기 오류</value>
</data>
Expand Down
4 changes: 2 additions & 2 deletions StabilityMatrix.Avalonia/Languages/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1687,8 +1687,8 @@ Account tokens will not be viewable after saving, please make a note of them if
<value>Rate Limit Reached</value>
</data>
<data name="Label_PromptAmplifierRateLimitMessage" xml:space="preserve">
<value>You have no Prompt Amplifier usage left this month. Usage resets on the 1st of each month. ({0} days left)</value>
<comment>{0} = days remaining until next month</comment>
<value>You have no Prompt Amplifier usage left this week. Usage resets every Monday at 00:00 UTC (in {0}).</value>
<comment>{0} = time left until the weekly reset, already formatted in English, e.g. "3 days" or "5 hours"</comment>
</data>
<data name="Label_PromptAmplifierError" xml:space="preserve">
<value>Prompt Amplifier Error</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public partial class PromptCardViewModel
public bool ShowLowTokenWarning => TokensRemaining <= LowTokenThreshold && TokensRemaining >= 0;

public string LowTokenWarningText =>
$"{TokensRemaining} amplification{(TokensRemaining == 1 ? "" : "s")} remaining (resets in {Utilities.GetNumDaysTilBeginningOfNextMonth()} days)";
$"{TokensRemaining} amplification{(TokensRemaining == 1 ? "" : "s")} remaining (resets in {Utilities.FormatTimeUntilNextWeeklyReset()})";

/// <inheritdoc />
public PromptCardViewModel(
Expand Down Expand Up @@ -661,7 +661,7 @@ private async Task AmplifyPrompt()
var dialog = DialogHelper.CreateMarkdownDialog(
string.Format(
Resources.Label_PromptAmplifierRateLimitMessage,
Utilities.GetNumDaysTilBeginningOfNextMonth()
Utilities.FormatTimeUntilNextWeeklyReset()
),
Resources.Label_PromptAmplifierRateLimitTitle
);
Expand Down
41 changes: 36 additions & 5 deletions StabilityMatrix.Core/Helper/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,43 @@ public static async Task<string> WhichAsync(string arg)
return await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
}

public static int GetNumDaysTilBeginningOfNextMonth()
/// <summary>
/// Day the Lykos weekly credit allowance resets for everyone, at 00:00 UTC.
/// </summary>
public const DayOfWeek WeeklyResetDay = DayOfWeek.Monday;

/// <summary>
/// Time left until the next Lykos weekly credit reset (<see cref="WeeklyResetDay"/>, 00:00 UTC).
/// Exactly at the reset instant, the next one is a full week away.
/// </summary>
public static TimeSpan GetTimeUntilNextWeeklyReset(DateTimeOffset? now = null)
{
var utcNow = (now ?? DateTimeOffset.UtcNow).ToUniversalTime();
var daysAhead = ((int)WeeklyResetDay - (int)utcNow.DayOfWeek + 7) % 7;
var nextReset = new DateTimeOffset(utcNow.Date, TimeSpan.Zero).AddDays(daysAhead);
if (nextReset <= utcNow)
nextReset = nextReset.AddDays(7);
return nextReset - utcNow;
}

/// <summary>
/// "3 days", "1 day", "5 hours", "1 hour" or "less than an hour" until the next weekly reset,
/// for "resets in …" copy.
/// </summary>
public static string FormatTimeUntilNextWeeklyReset(DateTimeOffset? now = null)
{
var now = DateTimeOffset.UtcNow;
var firstDayOfNextMonth = new DateTime(now.Year, now.Month, 1).AddMonths(1);
var daysUntilNextMonth = (firstDayOfNextMonth - now).Days;
return daysUntilNextMonth;
var left = GetTimeUntilNextWeeklyReset(now);
if (left.TotalDays >= 1)
{
var days = (int)left.TotalDays;
return days == 1 ? "1 day" : $"{days} days";
}
if (left.TotalHours >= 1)
{
var hours = (int)left.TotalHours;
return hours == 1 ? "1 hour" : $"{hours} hours";
}
return "less than an hour";
}

public static string RemoveHtml(string? stringWithHtml)
Expand Down
34 changes: 34 additions & 0 deletions StabilityMatrix.Tests/Helper/WeeklyResetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using StabilityMatrix.Core.Helper;

namespace StabilityMatrix.Tests.Helper;

[TestClass]
public class WeeklyResetTests
{
// 2026-10-14 is a Wednesday.
[DataTestMethod]
[DataRow("2026-10-14T12:00:00Z", "4 days")]
[DataRow("2026-10-18T12:00:00Z", "12 hours")]
[DataRow("2026-10-18T23:30:00Z", "less than an hour")]
[DataRow("2026-10-18T22:30:00Z", "1 hour")]
[DataRow("2026-10-18T00:00:00Z", "1 day")]
[DataRow("2026-10-19T00:00:00Z", "7 days")]
[DataRow("2026-10-19T00:00:01Z", "6 days")]
public void FormatTimeUntilNextWeeklyReset_CountsToMondayMidnightUtc(string now, string expected)
{
var result = Utilities.FormatTimeUntilNextWeeklyReset(DateTimeOffset.Parse(now));

Assert.AreEqual(expected, result);
}

[TestMethod]
public void GetTimeUntilNextWeeklyReset_UsesUtcRegardlessOfOffset()
{
// Sunday 20:00 at -05:00 is Monday 01:00 UTC, just after a reset.
var now = new DateTimeOffset(2026, 10, 18, 20, 0, 0, TimeSpan.FromHours(-5));

var result = Utilities.GetTimeUntilNextWeeklyReset(now);

Assert.AreEqual(TimeSpan.FromDays(7) - TimeSpan.FromHours(1), result);
}
}
Loading