ai-speedometer-headless 2.1.6 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-speedometer-headless +61 -26
- package/package.json +1 -1
|
@@ -542,7 +542,7 @@ var getAllAvailableProviders = async (includeAllProviders = false) => {
|
|
|
542
542
|
var TEST_PROMPT = `make a 300 word story`;
|
|
543
543
|
|
|
544
544
|
// ../core/src/benchmark.ts
|
|
545
|
-
async function benchmarkSingleModelRest(model) {
|
|
545
|
+
async function benchmarkSingleModelRest(model, logger) {
|
|
546
546
|
try {
|
|
547
547
|
if (!model.providerConfig || !model.providerConfig.apiKey) {
|
|
548
548
|
throw new Error(`Missing API key for provider ${model.providerName}`);
|
|
@@ -559,6 +559,7 @@ async function benchmarkSingleModelRest(model) {
|
|
|
559
559
|
actualModelId = model.name;
|
|
560
560
|
}
|
|
561
561
|
actualModelId = actualModelId.trim();
|
|
562
|
+
await logger?.logHeader(model.name, model.providerName, model.providerConfig.apiKey);
|
|
562
563
|
const startTime = Date.now();
|
|
563
564
|
let firstTokenTime = null;
|
|
564
565
|
let streamedText = "";
|
|
@@ -631,33 +632,36 @@ async function benchmarkSingleModelRest(model) {
|
|
|
631
632
|
const reader = response.body.getReader();
|
|
632
633
|
const decoder = new TextDecoder;
|
|
633
634
|
let buffer = "";
|
|
634
|
-
let
|
|
635
|
+
let firstParsedTokenTime = null;
|
|
635
636
|
while (true) {
|
|
636
637
|
const { done, value } = await reader.read();
|
|
637
638
|
if (done)
|
|
638
639
|
break;
|
|
639
|
-
if (
|
|
640
|
+
if (!firstTokenTime)
|
|
640
641
|
firstTokenTime = Date.now();
|
|
641
|
-
isFirstChunk = false;
|
|
642
|
-
}
|
|
643
642
|
buffer += decoder.decode(value, { stream: true });
|
|
644
643
|
const lines = buffer.split(`
|
|
645
644
|
`);
|
|
646
645
|
buffer = lines.pop() || "";
|
|
647
646
|
for (const line of lines) {
|
|
648
647
|
const trimmedLine = line.trim();
|
|
648
|
+
if (trimmedLine)
|
|
649
|
+
await logger?.logRaw(trimmedLine);
|
|
649
650
|
if (!trimmedLine)
|
|
650
651
|
continue;
|
|
651
652
|
try {
|
|
652
653
|
if (model.providerType === "anthropic") {
|
|
653
|
-
|
|
654
|
-
|
|
654
|
+
const anthropicDataPrefix = trimmedLine.startsWith("data: ") ? 6 : trimmedLine.startsWith("data:") ? 5 : -1;
|
|
655
|
+
if (anthropicDataPrefix !== -1) {
|
|
656
|
+
const jsonStr = trimmedLine.slice(anthropicDataPrefix);
|
|
655
657
|
if (jsonStr === "[DONE]")
|
|
656
658
|
continue;
|
|
657
659
|
const chunk = JSON.parse(jsonStr);
|
|
658
660
|
const chunkTyped = chunk;
|
|
659
|
-
if (chunkTyped.type === "content_block_delta" && chunkTyped.delta?.text) {
|
|
660
|
-
|
|
661
|
+
if (chunkTyped.type === "content_block_delta" && (chunkTyped.delta?.text || chunkTyped.delta?.thinking)) {
|
|
662
|
+
if (!firstParsedTokenTime)
|
|
663
|
+
firstParsedTokenTime = Date.now();
|
|
664
|
+
streamedText += chunkTyped.delta?.text || chunkTyped.delta?.thinking || "";
|
|
661
665
|
} else if (chunkTyped.type === "message_start" && chunkTyped.message?.usage) {
|
|
662
666
|
inputTokens = chunkTyped.message.usage.input_tokens || 0;
|
|
663
667
|
} else if (chunkTyped.type === "message_delta") {
|
|
@@ -670,8 +674,10 @@ async function benchmarkSingleModelRest(model) {
|
|
|
670
674
|
continue;
|
|
671
675
|
} else {
|
|
672
676
|
const chunk = JSON.parse(trimmedLine);
|
|
673
|
-
if (chunk.type === "content_block_delta" && chunk.delta?.text) {
|
|
674
|
-
|
|
677
|
+
if (chunk.type === "content_block_delta" && (chunk.delta?.text || chunk.delta?.thinking)) {
|
|
678
|
+
if (!firstParsedTokenTime)
|
|
679
|
+
firstParsedTokenTime = Date.now();
|
|
680
|
+
streamedText += chunk.delta?.text || chunk.delta?.thinking || "";
|
|
675
681
|
} else if (chunk.type === "message_start" && chunk.message?.usage) {
|
|
676
682
|
inputTokens = chunk.message.usage.input_tokens || 0;
|
|
677
683
|
} else if (chunk.type === "message_delta") {
|
|
@@ -684,6 +690,8 @@ async function benchmarkSingleModelRest(model) {
|
|
|
684
690
|
} else if (model.providerType === "google") {
|
|
685
691
|
const chunk = JSON.parse(trimmedLine);
|
|
686
692
|
if (chunk.candidates?.[0]?.content?.parts?.[0]?.text) {
|
|
693
|
+
if (!firstParsedTokenTime)
|
|
694
|
+
firstParsedTokenTime = Date.now();
|
|
687
695
|
streamedText += chunk.candidates[0].content.parts[0].text;
|
|
688
696
|
}
|
|
689
697
|
if (chunk.usageMetadata?.promptTokenCount)
|
|
@@ -691,19 +699,42 @@ async function benchmarkSingleModelRest(model) {
|
|
|
691
699
|
if (chunk.usageMetadata?.candidatesTokenCount)
|
|
692
700
|
outputTokens = chunk.usageMetadata.candidatesTokenCount;
|
|
693
701
|
} else {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
702
|
+
const dataPrefix = trimmedLine.startsWith("data: ") ? 6 : trimmedLine.startsWith("data:") ? 5 : -1;
|
|
703
|
+
if (dataPrefix === -1)
|
|
704
|
+
continue;
|
|
705
|
+
const jsonStr = trimmedLine.slice(dataPrefix);
|
|
706
|
+
if (jsonStr === "[DONE]")
|
|
707
|
+
continue;
|
|
708
|
+
const chunk = JSON.parse(jsonStr);
|
|
709
|
+
if (chunk.choices?.[0]?.delta?.content) {
|
|
710
|
+
if (!firstParsedTokenTime)
|
|
711
|
+
firstParsedTokenTime = Date.now();
|
|
712
|
+
streamedText += chunk.choices[0].delta.content;
|
|
713
|
+
} else if (chunk.choices?.[0]?.delta?.reasoning) {
|
|
714
|
+
if (!firstParsedTokenTime)
|
|
715
|
+
firstParsedTokenTime = Date.now();
|
|
716
|
+
streamedText += chunk.choices[0].delta.reasoning;
|
|
717
|
+
} else if (chunk.choices?.[0]?.delta?.reasoning_content) {
|
|
718
|
+
if (!firstParsedTokenTime)
|
|
719
|
+
firstParsedTokenTime = Date.now();
|
|
720
|
+
streamedText += chunk.choices[0].delta.reasoning_content;
|
|
721
|
+
} else if (chunk.type === "content_block_delta" && chunk.delta?.text) {
|
|
722
|
+
if (!firstParsedTokenTime)
|
|
723
|
+
firstParsedTokenTime = Date.now();
|
|
724
|
+
streamedText += chunk.delta.text;
|
|
725
|
+
} else if (chunk.type === "content_block_delta" && chunk.delta?.thinking) {
|
|
726
|
+
if (!firstParsedTokenTime)
|
|
727
|
+
firstParsedTokenTime = Date.now();
|
|
728
|
+
streamedText += chunk.delta.thinking;
|
|
729
|
+
}
|
|
730
|
+
if (chunk.usage?.prompt_tokens)
|
|
731
|
+
inputTokens = chunk.usage.prompt_tokens;
|
|
732
|
+
if (chunk.usage?.completion_tokens)
|
|
733
|
+
outputTokens = chunk.usage.completion_tokens;
|
|
734
|
+
if (chunk.type === "message_start" && chunk.message?.usage?.input_tokens)
|
|
735
|
+
inputTokens = chunk.message.usage.input_tokens;
|
|
736
|
+
if (chunk.type === "message_delta" && chunk.usage?.output_tokens) {
|
|
737
|
+
outputTokens = chunk.usage.output_tokens;
|
|
707
738
|
}
|
|
708
739
|
}
|
|
709
740
|
} catch {
|
|
@@ -711,15 +742,18 @@ async function benchmarkSingleModelRest(model) {
|
|
|
711
742
|
}
|
|
712
743
|
}
|
|
713
744
|
}
|
|
745
|
+
await logger?.flush();
|
|
714
746
|
const endTime = Date.now();
|
|
715
747
|
const totalTime = endTime - startTime;
|
|
716
|
-
const
|
|
748
|
+
const effectiveFirstToken = firstParsedTokenTime ?? firstTokenTime;
|
|
749
|
+
const timeToFirstToken = effectiveFirstToken ? effectiveFirstToken - startTime : totalTime;
|
|
750
|
+
const generationTime = totalTime - timeToFirstToken;
|
|
717
751
|
const usedEstimateForOutput = !outputTokens;
|
|
718
752
|
const usedEstimateForInput = !inputTokens;
|
|
719
753
|
const finalOutputTokens = outputTokens || Math.round(streamedText.length / 4);
|
|
720
754
|
const finalInputTokens = inputTokens || Math.round(TEST_PROMPT.length / 4);
|
|
721
755
|
const totalTokens = finalInputTokens + finalOutputTokens;
|
|
722
|
-
const tokensPerSecond =
|
|
756
|
+
const tokensPerSecond = generationTime > 0 ? finalOutputTokens / generationTime * 1000 : 0;
|
|
723
757
|
return {
|
|
724
758
|
model: model.name,
|
|
725
759
|
provider: model.providerName,
|
|
@@ -734,6 +768,7 @@ async function benchmarkSingleModelRest(model) {
|
|
|
734
768
|
success: true
|
|
735
769
|
};
|
|
736
770
|
} catch (error) {
|
|
771
|
+
await logger?.flush();
|
|
737
772
|
return {
|
|
738
773
|
model: model.name,
|
|
739
774
|
provider: model.providerName,
|
package/package.json
CHANGED