Skip to content
Draft
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,10 @@ export const de: Record<TKey, string> = {
"logs.col.status": "Status",
"logs.col.tokens": "Tokens",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "Decode-Tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "Ausgabe-Tokens pro Sekunde über die gesamte Anfragedauer",
"logs.metric.decodeTokPerSecTitle": "Geschätzte Ausgabe-Tokens pro Sekunde nach TTFT; Stream-Abschluss und Netzwerkpausen können weiterhin enthalten sein",
"logs.metric.estimatedCostTitle": "API-Listenpreis-Äquivalent, keine tatsächliche Belastung; bei fehlendem Preisabgleich nicht verfügbar",
"usage.cost.total": "API-Listenpreis-Äquivalent (dieser Zeitraum)",
"usage.cost.disclaimer": "Kein Abrechnungsbeleg. Stattdessen können Abonnementnutzung oder Anbieter-Guthaben gelten.",
Expand Down Expand Up @@ -793,6 +795,7 @@ export const de: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "Dieser Anbieter meldet keine Nutzung.",
"logs.detail.reason.output_missing": "Es wurden keine positiven Ausgabe-Tokens gemeldet.",
"logs.detail.reason.invalid_duration": "Die Anfragedauer ist ungültig.",
"logs.detail.reason.ttft_missing": "Für diese Anfrage wurde keine TTFT erfasst.",
"logs.detail.reason.price_unmatched": "Kein passender Preis gefunden.",
"logs.detail.reason.invalid_cache_breakdown": "Cache-Token-Details widersprechen den Eingabe-Tokens.",
"logs.detail.reason.invalid_usage": "Die Nutzung enthält einen ungültigen Token-Wert.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,8 +793,10 @@ export const en = {
"logs.col.status": "Status",
"logs.col.tokens": "Tokens",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "decode tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "Output tokens per second over the full request duration",
"logs.metric.decodeTokPerSecTitle": "Estimated output tokens per second after TTFT; stream finalization and network pauses may still be included",
"logs.metric.estimatedCostTitle": "API list-price equivalent, not an actual charge; unmatched pricing is unavailable",
"usage.cost.total": "API list-price equivalent (this range)",
"usage.cost.disclaimer": "Not a billing receipt. Subscription usage or provider credits may apply instead.",
Expand Down Expand Up @@ -840,6 +842,7 @@ export const en = {
"logs.detail.reason.usage_unsupported": "This provider does not report usage.",
"logs.detail.reason.output_missing": "No positive output token count was reported.",
"logs.detail.reason.invalid_duration": "The request duration is not valid.",
"logs.detail.reason.ttft_missing": "TTFT was not recorded for this request.",
"logs.detail.reason.price_unmatched": "No matching price was found.",
"logs.detail.reason.invalid_cache_breakdown": "Cache token details conflict with total input tokens.",
"logs.detail.reason.invalid_usage": "Usage contains an invalid token value.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,8 +774,10 @@ export const fr: Record<TKey, string> = {
"logs.col.status": "État",
"logs.col.tokens": "Jetons",
"logs.col.tokPerSec": "jetons/s",
"logs.col.decodeTokPerSec": "jetons/s (décodage)",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "Jetons de sortie par seconde sur toute la durée de la requête",
"logs.metric.decodeTokPerSecTitle": "Estimation des jetons de sortie par seconde après le TTFT ; la finalisation du flux et les pauses réseau peuvent rester incluses",
"logs.metric.estimatedCostTitle": "Équivalent au tarif catalogue de l’API, et non montant réellement facturé ; aucun tarif n’est disponible en l’absence de correspondance",
"usage.cost.total": "Équivalent au tarif catalogue de l’API (cette période)",
"usage.cost.disclaimer": "Ceci n’est pas un reçu de facturation. L’utilisation d’un abonnement ou les crédits du fournisseur peuvent s’appliquer à la place.",
Expand Down Expand Up @@ -821,6 +823,7 @@ export const fr: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "Ce fournisseur ne communique pas l’utilisation.",
"logs.detail.reason.output_missing": "Aucun nombre positif de jetons de sortie n’a été communiqué.",
"logs.detail.reason.invalid_duration": "La durée de la requête n’est pas valide.",
"logs.detail.reason.ttft_missing": "Le TTFT n’a pas été enregistré pour cette requête.",
"logs.detail.reason.price_unmatched": "Aucun tarif correspondant n’a été trouvé.",
"logs.detail.reason.invalid_cache_breakdown": "Le détail des jetons du cache est incompatible avec le nombre total de jetons d’entrée.",
"logs.detail.reason.invalid_usage": "Les données d’utilisation contiennent une valeur de jetons non valide.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,10 @@ export const ja: Record<TKey, string> = {
"logs.col.status": "状態",
"logs.col.tokens": "トークン",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "decode tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "リクエスト全体の所要時間あたりの出力トークン数",
"logs.metric.decodeTokPerSecTitle": "TTFT 後の推定出力 tok/s(ストリーム終了処理やネットワーク待機を含む場合があります)",
"logs.metric.estimatedCostTitle": "API 定価相当額(実際の請求ではありません); 未対応の価格は利用できません",
"usage.cost.total": "API 定価相当額(この期間)",
"usage.cost.disclaimer": "請求明細ではありません。サブスクリプション利用量やプロバイダークレジットが代わりに適用される場合があります。",
Expand Down Expand Up @@ -755,6 +757,7 @@ export const ja: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "このプロバイダーは使用量を報告しません。",
"logs.detail.reason.output_missing": "正の出力トークン数が報告されませんでした。",
"logs.detail.reason.invalid_duration": "リクエストの所要時間が有効ではありません。",
"logs.detail.reason.ttft_missing": "このリクエストでは TTFT が記録されていません。",
"logs.detail.reason.price_unmatched": "一致する価格が見つかりませんでした。",
"logs.detail.reason.invalid_cache_breakdown": "キャッシュトークンの詳細が合計入力トークンと矛盾しています。",
"logs.detail.reason.invalid_usage": "使用量に無効なトークン値が含まれています。",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,10 @@ export const ko: Record<TKey, string> = {
"logs.col.status": "상태",
"logs.col.tokens": "토큰",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "decode tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "전체 요청 시간 기준 초당 출력 토큰",
"logs.metric.decodeTokPerSecTitle": "TTFT 이후 추정 초당 출력 토큰이며 스트림 종료 처리와 네트워크 지연이 포함될 수 있습니다",
"logs.metric.estimatedCostTitle": "API 정가 환산치이며 실제 청구액이 아닙니다. 가격 미매칭은 표시하지 않습니다.",
"usage.cost.total": "API 정가 환산치 (이 기간)",
"usage.cost.disclaimer": "결제 영수증이 아닙니다. 구독 사용량 또는 프로바이더 크레딧이 대신 적용될 수 있습니다.",
Expand Down Expand Up @@ -824,6 +826,7 @@ export const ko: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "이 프로바이더는 usage 보고를 지원하지 않습니다.",
"logs.detail.reason.output_missing": "양수 출력 토큰 수가 보고되지 않았습니다.",
"logs.detail.reason.invalid_duration": "요청 소요 시간이 유효하지 않습니다.",
"logs.detail.reason.ttft_missing": "이 요청에는 TTFT가 기록되지 않았습니다.",
"logs.detail.reason.price_unmatched": "매칭되는 가격을 찾지 못했습니다.",
"logs.detail.reason.invalid_cache_breakdown": "캐시 토큰 상세가 전체 입력 토큰과 모순됩니다.",
"logs.detail.reason.invalid_usage": "usage에 유효하지 않은 토큰 값이 있습니다.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,10 @@ export const ru: Record<TKey, string> = {
"logs.col.status": "Статус",
"logs.col.tokens": "Токены",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "декодирование tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "Выходные токены в секунду за полную длительность запроса",
"logs.metric.decodeTokPerSecTitle": "Оценка выходных токенов в секунду после TTFT; измеренный интервал всё ещё включает завершение потока и сетевые паузы",
"logs.metric.estimatedCostTitle": "Эквивалент стоимости по прайс-листу API, а не фактическое списание; если цену не удалось сопоставить, значение недоступно",
"usage.cost.total": "Эквивалент стоимости по прайс-листу API (за этот период)",
"usage.cost.disclaimer": "Не является счётом. Расходы могут покрываться подпиской или кредитами провайдера.",
Expand Down Expand Up @@ -810,6 +812,7 @@ export const ru: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "Этот провайдер не сообщает данные об использовании.",
"logs.detail.reason.output_missing": "Положительное число выходных токенов не было сообщено.",
"logs.detail.reason.invalid_duration": "Длительность запроса некорректна.",
"logs.detail.reason.ttft_missing": "Для этого запроса TTFT не был записан.",
"logs.detail.reason.price_unmatched": "Подходящая цена не найдена.",
"logs.detail.reason.invalid_cache_breakdown": "Детализация кэш-токенов противоречит общему числу входных токенов.",
"logs.detail.reason.invalid_usage": "В данных использования есть некорректное значение токенов.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,10 @@ export const tr: Record<TKey, string> = {
"logs.col.status": "Durum",
"logs.col.tokens": "Jetonlar",
"logs.col.tokPerSec": "jeton/sn",
"logs.col.decodeTokPerSec": "çözümleme jeton/sn",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "Tam istek süresince saniye başına çıktı jetonu",
"logs.metric.decodeTokPerSecTitle": "TTFT sonrasında saniye başına tahmini çıktı jetonu; akış sonlandırma ve ağ beklemeleri hâlâ dahil olabilir",
"logs.metric.estimatedCostTitle": "Tahmini API liste fiyatı",
"usage.cost.total": "API liste fiyatı eşdeğeri",
"usage.cost.disclaimer": "Fatura makbuzu değildir.",
Expand Down Expand Up @@ -829,6 +831,7 @@ export const tr: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "Bu sağlayıcı kullanım bildirmeyebilir.",
"logs.detail.reason.output_missing": "Çıktı jeton sayısı bildirilmedi.",
"logs.detail.reason.invalid_duration": "İstek süresi geçersiz.",
"logs.detail.reason.ttft_missing": "Bu istek için TTFT kaydedilmedi.",
"logs.detail.reason.price_unmatched": "Eşleşen fiyat bulunamadı.",
"logs.detail.reason.invalid_cache_breakdown": "Önbellek detayları çakışıyor.",
"logs.detail.reason.invalid_usage": "Kullanım geçersiz bir jeton değeri içeriyor.",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,10 @@ export const zhTW: Record<TKey, string> = {
"logs.col.status": "狀態",
"logs.col.tokens": "Token 數",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "解碼 tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "按完整請求耗時計算的每秒輸出 token",
"logs.metric.decodeTokPerSecTitle": "扣除 TTFT 後的估算每秒輸出 token;仍可能包含串流收尾與網路停頓",
"logs.metric.estimatedCostTitle": "按 API 標價估算,並非實際扣費;價格無法符合時不顯示",
"usage.cost.total": "API 標價折算(當前範圍)",
"usage.cost.disclaimer": "這不是帳單或扣費憑證。實際可能計入訂閱用量或消耗服務商額度。",
Expand Down Expand Up @@ -643,6 +645,7 @@ export const zhTW: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "該供應商不支援上報 usage。",
"logs.detail.reason.output_missing": "未上報正數輸出 token。",
"logs.detail.reason.invalid_duration": "請求耗時無效。",
"logs.detail.reason.ttft_missing": "此請求未記錄 TTFT。",
"logs.detail.reason.price_unmatched": "未找到符合的 jawcode 價格。",
"logs.detail.reason.invalid_cache_breakdown": "快取 token 明細與輸入 token 總數衝突。",
"logs.detail.reason.invalid_usage": "Usage 包含無效的 token 值。",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,8 +758,10 @@ export const zh: Record<TKey, string> = {
"logs.col.status": "状态",
"logs.col.tokens": "Token 数",
"logs.col.tokPerSec": "tok/s",
"logs.col.decodeTokPerSec": "解码 tok/s",
"logs.col.estimatedCost": "~$",
"logs.metric.tokPerSecTitle": "按完整请求耗时计算的每秒输出 token",
"logs.metric.decodeTokPerSecTitle": "扣除 TTFT 后的估算每秒输出 token;仍可能包含流式收尾和网络停顿",
"logs.metric.estimatedCostTitle": "按 API 标价估算,并非实际扣费;价格无法匹配时不显示",
"usage.cost.total": "API 标价折算(当前范围)",
"usage.cost.disclaimer": "这不是账单或扣费凭证。实际可能计入订阅用量或消耗服务商额度。",
Expand Down Expand Up @@ -805,6 +807,7 @@ export const zh: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "该提供方不支持上报 usage。",
"logs.detail.reason.output_missing": "未上报正数输出 token。",
"logs.detail.reason.invalid_duration": "请求耗时无效。",
"logs.detail.reason.ttft_missing": "该请求未记录 TTFT。",
"logs.detail.reason.price_unmatched": "未找到匹配的价格。",
"logs.detail.reason.invalid_cache_breakdown": "缓存 token 明细与输入 token 总数冲突。",
"logs.detail.reason.invalid_usage": "Usage 包含无效的 token 值。",
Expand Down
29 changes: 27 additions & 2 deletions gui/src/pages/Logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type LogUsageStatus = "reported" | "unreported" | "unsupported" | "estimated";

type MetricUnavailableReason =
| "usage_missing" | "usage_unsupported" | "output_missing" | "invalid_duration"
| "ttft_missing"
| "price_unmatched" | "invalid_cache_breakdown"
| "invalid_usage" | "combo_attempt_unavailable";

Expand Down Expand Up @@ -92,6 +93,7 @@ type CostResult =

interface LogDisplayMetrics {
tokPerSecond: TokPerSecondResult;
decodeTokPerSecond: TokPerSecondResult;
cost: CostResult;
}

Expand Down Expand Up @@ -272,6 +274,7 @@ const METRIC_REASON_KEYS = {
usage_unsupported: "logs.detail.reason.usage_unsupported",
output_missing: "logs.detail.reason.output_missing",
invalid_duration: "logs.detail.reason.invalid_duration",
ttft_missing: "logs.detail.reason.ttft_missing",
price_unmatched: "logs.detail.reason.price_unmatched",
invalid_cache_breakdown: "logs.detail.reason.invalid_cache_breakdown",
invalid_usage: "logs.detail.reason.invalid_usage",
Expand Down Expand Up @@ -752,7 +755,14 @@ export default function Logs({ apiBase }: { apiBase: string }) {
<tr>
<th>{t("logs.col.time")}</th>
<th className="num log-col-tokens">{t("logs.col.tokens")}</th>
<th className="num log-col-rate" title={t("logs.metric.tokPerSecTitle")}>{t("logs.col.tokPerSec")}</th>
<th className="num log-col-rate">
<span className="logs-stack-end">
<span title={t("logs.metric.tokPerSecTitle")}>{t("logs.col.tokPerSec")}</span>
<span className="muted text-caption leading-tight" title={t("logs.metric.decodeTokPerSecTitle")}>
{t("logs.col.decodeTokPerSec")}
</span>
</span>
</th>
<th className="num log-col-cost" title={t("logs.metric.estimatedCostTitle")}>{t("logs.col.estimatedCost")}</th>
<th className="log-col-model">{t("logs.col.model")}</th>
<th>{t("logs.col.effort")}</th>
Expand Down Expand Up @@ -813,7 +823,12 @@ export default function Logs({ apiBase }: { apiBase: string }) {
})()}
</td>
<td className="num mono log-col-rate">
{formatTokPerSecond(log.displayMetrics?.tokPerSecond, localeTag)}
<span className="logs-stack-end">
<span>{formatTokPerSecond(log.displayMetrics?.tokPerSecond, localeTag)}</span>
<span className="muted text-caption leading-tight" title={t("logs.metric.decodeTokPerSecTitle")}>
{formatTokPerSecond(log.displayMetrics?.decodeTokPerSecond, localeTag)}
</span>
</span>
</td>
<td className="num mono log-col-cost">
{formatEstimatedUsd(log.displayMetrics?.cost, t, localeTag)}
Expand Down Expand Up @@ -1033,13 +1048,21 @@ function LogDetailDialog({
<div className="log-detail-grid">
<span className="muted">{t("logs.col.duration")}</span><span className="mono">{detail.durationMs}ms</span>
<span className="muted">{t("logs.col.tokPerSec")}</span><span className="mono">{formatTokPerSecond(detail.displayMetrics?.tokPerSecond, localeTag)}</span>
<span className="muted" title={t("logs.metric.decodeTokPerSecTitle")}>{t("logs.col.decodeTokPerSec")}</span>
<span className="mono">{formatTokPerSecond(detail.displayMetrics?.decodeTokPerSecond, localeTag)}</span>
{detail.firstOutputMs !== undefined && (
<><span className="muted">{t("logs.detail.ttft")}</span><span className="mono">{detail.firstOutputMs}ms</span></>
)}
</div>
{detail.displayMetrics?.tokPerSecond.kind === "unavailable" && (
<p className="log-detail-notes-line muted">{t(metricReasonKey(detail.displayMetrics.tokPerSecond.reason))}</p>
)}
{detail.displayMetrics?.tokPerSecond.kind === "value"
&& detail.displayMetrics.decodeTokPerSecond?.kind === "unavailable" && (
<p className="log-detail-notes-line muted">
{t("logs.col.decodeTokPerSec")}: {t(metricReasonKey(detail.displayMetrics.decodeTokPerSecond.reason))}
</p>
)}
</section>

<section className="log-detail-section" aria-labelledby="log-detail-cost">
Expand Down Expand Up @@ -1088,6 +1111,7 @@ function LogDetailDialog({
<th>{t("logs.detail.attempt.target")}</th>
<th className="num">{t("logs.col.duration")}</th>
<th className="num">{t("logs.col.tokPerSec")}</th>
<th className="num" title={t("logs.metric.decodeTokPerSecTitle")}>{t("logs.col.decodeTokPerSec")}</th>
<th className="num">{t("logs.col.estimatedCost")}</th>
<th>{t("logs.detail.attempt.reason")}</th>
</tr></thead>
Expand Down Expand Up @@ -1125,6 +1149,7 @@ function LogDetailDialog({
</td>
<td className="num mono">{attempt.durationMs}ms</td>
<td className="num mono">{formatTokPerSecond(attempt.displayMetrics?.tokPerSecond, localeTag)}</td>
<td className="num mono">{formatTokPerSecond(attempt.displayMetrics?.decodeTokPerSecond, localeTag)}</td>
<td className="num mono">{formatEstimatedUsd(attemptCost, t, localeTag)}</td>
<td className="log-detail-break">{reason}</td>
</tr>
Expand Down
Loading
Loading