Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/lobehub/lobe-chat
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jan 27, 2025
2 parents 6b87496 + 27bd861 commit fdd5b65
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 50 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@

# Changelog

### [Version 1.48.3](https://github.com/lobehub/lobe-chat/compare/v1.48.2...v1.48.3)

<sup>Released on **2025-01-26**</sup>

#### 💄 Styles

- **misc**: Improve model pricing with CNY.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Styles

- **misc**: Improve model pricing with CNY, closes [#5599](https://github.com/lobehub/lobe-chat/issues/5599) ([6d91457](https://github.com/lobehub/lobe-chat/commit/6d91457))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>

### [Version 1.48.2](https://github.com/lobehub/lobe-chat/compare/v1.48.1...v1.48.2)

<sup>Released on **2025-01-25**</sup>
Expand Down
7 changes: 7 additions & 0 deletions changelog/v1.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[
{
"children": {
"improvements": ["Improve model pricing with CNY."]
},
"date": "2025-01-26",
"version": "1.48.3"
},
{
"children": {
"improvements": [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lobehub/chat",
"version": "1.48.2",
"version": "1.48.3",
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
Expand Down
67 changes: 31 additions & 36 deletions src/app/(main)/settings/provider/features/ModelList/ModelItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import { ModelInfoTags } from '@/components/ModelSelect';
import { useIsMobile } from '@/hooks/useIsMobile';
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
import { AiModelSourceEnum, AiProviderModelListItem, ChatModelPricing } from '@/types/aiModel';
import { formatPriceByCurrency } from '@/utils/format';

import ModelConfigModal from './ModelConfigModal';

const f = (number: number | undefined, text: string) =>
typeof number !== 'undefined' ? text : undefined;

export const useStyles = createStyles(({ css, token, cx }) => {
const config = css`
opacity: 0;
Expand Down Expand Up @@ -74,7 +72,7 @@ const ModelItem = memo<ModelItemProps>(
type,
}) => {
const { styles } = useStyles();
const { t } = useTranslation(['modelProvider', 'components', 'models']);
const { t } = useTranslation(['modelProvider', 'components', 'models', 'common']);
const theme = useTheme();

const [activeAiProvider, isModelLoading, toggleModelEnabled, removeAiModel] = useAiInfraStore(
Expand All @@ -90,41 +88,43 @@ const ModelItem = memo<ModelItemProps>(
const [showConfig, setShowConfig] = useState(false);

const formatPricing = (): string[] => {
if (!pricing) return [];

switch (type) {
case 'chat': {
return [
f(
pricing?.input,
t('providerModels.item.pricing.inputTokens', { amount: pricing?.input }),
),
f(
pricing?.output,
t('providerModels.item.pricing.outputTokens', { amount: pricing?.output }),
),
typeof pricing.input === 'number' &&
t('providerModels.item.pricing.inputTokens', {
amount: formatPriceByCurrency(pricing.input, pricing?.currency),
}),
typeof pricing.output === 'number' &&
t('providerModels.item.pricing.outputTokens', {
amount: formatPriceByCurrency(pricing.output, pricing?.currency),
}),
].filter(Boolean) as string[];
}
case 'embedding': {
return [
f(
pricing?.input,
t('providerModels.item.pricing.inputTokens', { amount: pricing?.input }),
),
typeof pricing.input === 'number' &&
t('providerModels.item.pricing.inputTokens', {
amount: formatPriceByCurrency(pricing.input, pricing?.currency),
}),
].filter(Boolean) as string[];
}
case 'tts': {
return [
f(
pricing?.input,
t('providerModels.item.pricing.inputCharts', { amount: pricing?.input }),
),
typeof pricing.input === 'number' &&
t('providerModels.item.pricing.inputCharts', {
amount: formatPriceByCurrency(pricing.input, pricing?.currency),
}),
].filter(Boolean) as string[];
}
case 'stt': {
return [
f(
pricing?.input,
t('providerModels.item.pricing.inputMinutes', { amount: pricing?.input }),
),
typeof pricing.input === 'number' &&
t('providerModels.item.pricing.inputMinutes', {
amount: formatPriceByCurrency(pricing.input, pricing?.currency),
}),
].filter(Boolean) as string[];
}

Expand All @@ -142,7 +142,12 @@ const ModelItem = memo<ModelItemProps>(
releasedAt && t('providerModels.item.releasedAt', { releasedAt }),
...formatPricing(),
].filter(Boolean) as string[];

const { message, modal } = App.useApp();
const copyModelId = async () => {
await copyToClipboard(id);
message.success({ content: t('copySuccess', { ns: 'common' }) });
};

const isMobile = useIsMobile();

Expand Down Expand Up @@ -179,12 +184,7 @@ const ModelItem = memo<ModelItemProps>(
</Flexbox>
</Flexbox>
<div>
<Tag
onClick={() => {
copyToClipboard(id);
}}
style={{ cursor: 'pointer', marginRight: 0 }}
>
<Tag onClick={copyModelId} style={{ cursor: 'pointer', marginRight: 0 }}>
{id}
</Tag>
</div>
Expand Down Expand Up @@ -251,12 +251,7 @@ const ModelItem = memo<ModelItemProps>(
<Flexbox flex={1} gap={2} style={{ minWidth: 0 }}>
<Flexbox align={'center'} gap={8} horizontal>
{displayName || id}
<Tag
onClick={() => {
copyToClipboard(id);
}}
style={{ cursor: 'pointer', marginRight: 0 }}
>
<Tag onClick={copyModelId} style={{ cursor: 'pointer', marginRight: 0 }}>
{id}
</Tag>
<Flexbox className={styles.config} horizontal>
Expand Down
2 changes: 2 additions & 0 deletions src/const/currency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// in 2025.01.26
export const USD_TO_CNY = 7.24;
2 changes: 0 additions & 2 deletions src/const/discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {
DiscoverProviderItem,
} from '@/types/discover';

export const CNY_TO_USD = 7.14;

const DEFAULT_CREATED_AT = new Date().toISOString();

export const DEFAULT_DISCOVER_ASSISTANT_ITEM: Partial<DiscoverAssistantItem> = {
Expand Down
11 changes: 2 additions & 9 deletions src/utils/format.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dayjs from 'dayjs';
import { describe, expect, it } from 'vitest';

import { CNY_TO_USD } from '@/const/discover';
import { USD_TO_CNY } from '@/const/currency';

import {
formatDate,
Expand Down Expand Up @@ -194,16 +194,9 @@ describe('format', () => {
expect(formatPriceByCurrency(1234.56, 'USD')).toBe('1,234.56');
});

it('should format CNY prices correctly', () => {
// Assuming CNY_TO_USD is 6.5
const CNY_TO_USD = 6.5;
expect(formatPriceByCurrency(1000, 'CNY')).toBe('140.06');
expect(formatPriceByCurrency(6500, 'CNY')).toBe('910.36');
});

it('should use the correct CNY_TO_USD conversion rate', () => {
const price = 1000;
const expectedCNY = formatPrice(price / CNY_TO_USD);
const expectedCNY = formatPrice(price / USD_TO_CNY);
expect(formatPriceByCurrency(price, 'CNY')).toBe(expectedCNY);
});
});
Expand Down
4 changes: 2 additions & 2 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dayjs from 'dayjs';
import { isNumber } from 'lodash-es';
import numeral from 'numeral';

import { CNY_TO_USD } from '@/const/discover';
import { USD_TO_CNY } from '@/const/currency';
import { ModelPriceCurrency } from '@/types/llm';

export const formatSize = (bytes: number, fractionDigits: number = 1): string => {
Expand Down Expand Up @@ -118,7 +118,7 @@ export const formatPrice = (price: number, fractionDigits: number = 2) => {

export const formatPriceByCurrency = (price: number, currency?: ModelPriceCurrency) => {
if (currency === 'CNY') {
return formatPrice(price / CNY_TO_USD);
return formatPrice(price / USD_TO_CNY);
}
return formatPrice(price);
};
Expand Down

0 comments on commit fdd5b65

Please sign in to comment.