♻️ refactor: optimize state management, switch to @tanstack/vue-virtual, and improve performance
- Centralize `useAgents` and `useModels` state within the Nuxt app context to prevent data leaks and improve initialization. - Migrate virtualization from `vue-virtual-scroller` to `@tanstack/vue-virtual` with new `RowVirtualizerFixed` and `RowVirtualizerDynamic` components. - Upgrade Nuxt to v4.3.1 and remove `@vue-macros/nuxt`. - Replace `big.js` with an optimized custom `lshDecimal` string manipulation logic for pricing calculations in the provider API. - Implement automatic focus redirection in `ChatInput` to capture standard keyboard input. - Refactor Sidenav and Settings components to utilize virtualization for long lists (topics, agents, models). - Enhance theme colors and mobile experience. More work to come on both of these.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { type Entity } from '@triplit/client';
|
||||
import Big from 'big.js';
|
||||
import * as z from 'zod';
|
||||
import { SupportedModalities } from '~/types/model';
|
||||
import { Providers } from '~/types/model';
|
||||
@@ -246,14 +245,65 @@ const getModelData = (modelId: string, providerId: string, modelsDevData: any) =
|
||||
}
|
||||
}
|
||||
|
||||
const formatBig = (bigValue: Big) => {
|
||||
let str = bigValue.toString();
|
||||
// const formatBig = (bigValue: Big) => {
|
||||
// let str = bigValue.toString();
|
||||
|
||||
if (!str.includes('.')) return str + '.00';
|
||||
if (str.split('.')[1]!.length === 1) return str + '0';
|
||||
// if (!str.includes('.')) return str + '.00';
|
||||
// if (str.split('.')[1]!.length === 1) return str + '0';
|
||||
|
||||
return str;
|
||||
};
|
||||
// return str;
|
||||
// };
|
||||
|
||||
// this function multiplies a string in the format of 'D.DD' by 1_000_000
|
||||
// it does this by finding the first digit that is not a zero, and then
|
||||
// left shifting it in decimal by 3 places
|
||||
const lshDecimal = (number: string, shift: number) => {
|
||||
if (number.length === 0) {
|
||||
return '0.00';
|
||||
}
|
||||
|
||||
let value = '';
|
||||
let isNegative = number[0] === '-';
|
||||
let [integerPart, fractionalPart] = number.substring(isNegative ? 1 : 0).split('.');
|
||||
|
||||
if (!fractionalPart) {
|
||||
fractionalPart = '';
|
||||
}
|
||||
|
||||
if (shift <= fractionalPart.length) {
|
||||
integerPart += fractionalPart.substring(0, shift);
|
||||
fractionalPart = fractionalPart.substring(shift);
|
||||
} else if (shift > fractionalPart.length) {
|
||||
integerPart += fractionalPart;
|
||||
for (let i = 0; i < shift - fractionalPart.length; i++) {
|
||||
integerPart += '0';
|
||||
}
|
||||
fractionalPart = '';
|
||||
}
|
||||
|
||||
if (isNegative) {
|
||||
value += '-';
|
||||
}
|
||||
|
||||
integerPart = integerPart!.replace(/^0+/, '');
|
||||
if (integerPart.length === 0) {
|
||||
integerPart = '0';
|
||||
}
|
||||
|
||||
value += integerPart;
|
||||
|
||||
if (fractionalPart.length > 0) {
|
||||
if (fractionalPart.length < 2) {
|
||||
fractionalPart += '0';
|
||||
}
|
||||
|
||||
value += '.' + fractionalPart;
|
||||
} else {
|
||||
value += '.00';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
const normalizeResponse = async (response: Record<string, any>, provider: typeof Providers[number], baseUrl: string, modelsDevData: any) => {
|
||||
switch (provider) {
|
||||
@@ -289,35 +339,37 @@ const normalizeResponse = async (response: Record<string, any>, provider: typeof
|
||||
switch (key) {
|
||||
case 'prompt':
|
||||
case 'completion':
|
||||
case 'request':
|
||||
case 'image':
|
||||
case 'audio':
|
||||
case 'discount':
|
||||
pricing[key] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing[key] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'request':
|
||||
pricing['request'] = lshDecimal(model.pricing[key], 3);
|
||||
break;
|
||||
case 'image_tokens':
|
||||
pricing['imageTokens'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['imageTokens'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'image_output':
|
||||
pricing['imageOutput'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['imageOutput'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'audio_output':
|
||||
pricing['audioOutput'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['audioOutput'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'input_audio_cache':
|
||||
pricing['inputAudioCache'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['inputAudioCache'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'web_search':
|
||||
pricing['webSearch'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['webSearch'] = lshDecimal(model.pricing[key], 3);
|
||||
break;
|
||||
case 'internal_reasoning':
|
||||
pricing['internalReasoning'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['internalReasoning'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'input_cache_read':
|
||||
pricing['inputCacheRead'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['inputCacheRead'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
case 'input_cache_write':
|
||||
pricing['inputCacheWrite'] = formatBig(Big(model.pricing[key]).mul(1_000_000));
|
||||
pricing['inputCacheWrite'] = lshDecimal(model.pricing[key], 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user