Skip to content
Merged
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
6 changes: 4 additions & 2 deletions react-native/src/api/bedrock-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
} from '../chat/util/BedrockMessageConvertor.ts';
import { invokeOpenAIWithCallBack } from './open-api.ts';
import { invokeOllamaWithCallBack } from './ollama-api.ts';
import { BedrockThinkingModels } from '../storage/Constants.ts';
import { BedrockThinkingModels, DeepSeekModels } from '../storage/Constants.ts';

type CallbackFunction = (
result: string,
Expand All @@ -45,7 +45,9 @@ export const invokeBedrockWithCallBack = async (
controller: AbortController,
callback: CallbackFunction
) => {
const isDeepSeek = getTextModel().modelId.includes('deepseek');
const isDeepSeek = DeepSeekModels.some(
model => model.modelId === getTextModel().modelId
);
const isOpenAI = getTextModel().modelId.includes('gpt');
const isOllama = getTextModel().modelId.startsWith('ollama-');
if (chatMode === ChatMode.Text && (isDeepSeek || isOpenAI || isOllama)) {
Expand Down
6 changes: 5 additions & 1 deletion react-native/src/chat/component/CustomMessageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { isMac } from '../../App.tsx';
import { CustomTokenizer } from './markdown/CustomTokenizer.ts';
import { State, TapGestureHandler } from 'react-native-gesture-handler';
import Markdown from './markdown/Markdown.tsx';
import { DeepSeekModels } from '../../storage/Constants.ts';
import { getTextModel } from '../../storage/StorageUtils.ts';

interface CustomMessageProps extends MessageProps<SwiftChatMessage> {
chatStatus: ChatStatus;
Expand Down Expand Up @@ -78,7 +80,9 @@ const CustomMessageComponent: React.FC<CustomMessageProps> = ({
currentMessage.user._id === 1
? 'You'
: currentMessage.user.name ?? 'Bedrock';
const isDeepSeek = userName.includes('DeepSeek');
const isDeepSeek = DeepSeekModels.some(
model => model.modelId === getTextModel().modelId
);
const isOpenAI = userName.includes('GPT');
const isOllama = userName.includes(':');

Expand Down
5 changes: 4 additions & 1 deletion react-native/src/chat/component/EmptyChatComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useNavigation } from '@react-navigation/native';
import { RouteParamList } from '../../types/RouteTypes.ts';
import { DrawerNavigationProp } from '@react-navigation/drawer';
import { getTextModel } from '../../storage/StorageUtils.ts';
import { DeepSeekModels } from '../../storage/Constants.ts';

const isAndroid = Platform.OS === 'android';
type NavigationProp = DrawerNavigationProp<RouteParamList>;
Expand All @@ -23,7 +24,9 @@ export const EmptyChatComponent = ({
chatMode,
}: EmptyChatComponentProps): React.ReactElement => {
const navigation = useNavigation<NavigationProp>();
const isDeepSeek = getTextModel().modelId.includes('deepseek');
const isDeepSeek = DeepSeekModels.some(
model => model.modelId === getTextModel().modelId
);
const isOpenAI = getTextModel().modelId.includes('gpt');
const isOllama = getTextModel().modelId.startsWith('ollama-');
const modelIcon = isDeepSeek
Expand Down
2 changes: 1 addition & 1 deletion react-native/src/chat/component/markdown/useMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ const useMarkdown = (
}
}
combinedText += newContent;
if (lastToken.type === 'space') {
if (lastToken.type === 'space' && lastTokenIndex > 0) {
combinedText =
cacheRef.current.cachedTokens[lastTokenIndex - 1].raw + combinedText;
}
Expand Down
17 changes: 16 additions & 1 deletion react-native/src/settings/ModelPrice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Usage, UsagePrice } from '../types/Chat.ts';
import { Model, Usage, UsagePrice } from '../types/Chat.ts';

export const getUsagePrice = (usage: Usage): UsagePrice => {
const usagePrice: UsagePrice = {
Expand Down Expand Up @@ -81,6 +81,10 @@ function getImagePrice(

export const ModelPrice: ModelPriceType = {
textModelPrices: {
'Bedrock DeepSeek-R1': {
inputTokenPrice: 0.00135,
outputTokenPrice: 0.0054,
},
'DeepSeek-V3': {
inputTokenPrice: 0.00027,
outputTokenPrice: 0.0011,
Expand Down Expand Up @@ -372,3 +376,14 @@ export function getTotalImagePrice(usage: Usage[]) {
.toFixed(6)
);
}

export function addBedrockPrefixToDeepseekModels(models: Model[]): void {
for (let i = 0; i < models.length; i++) {
if (models[i].modelName.toLowerCase().includes('deepseek')) {
models[i] = {
...models[i],
modelName: `Bedrock ${models[i].modelName}`,
};
}
}
}
32 changes: 22 additions & 10 deletions react-native/src/settings/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ import { DropdownItem, Model, UpgradeInfo } from '../types/Chat.ts';
import packageJson from '../../package.json';
import { isMac } from '../App.tsx';
import CustomDropdown from './DropdownComponent.tsx';
import { getTotalCost } from './ModelPrice.ts';
import {
addBedrockPrefixToDeepseekModels,
getTotalCost,
} from './ModelPrice.ts';
import {
BedrockThinkingModels,
DeepSeekModels,
DefaultTextModel,
getAllRegions,
getDefaultTextModels,
GPTModels,
getDefaultApiKeyModels,
} from '../storage/Constants.ts';
import CustomTextInput from './CustomTextInput.tsx';
import { requestAllOllamaModels } from '../api/ollama-api.ts';
Expand Down Expand Up @@ -138,23 +140,30 @@ function SettingsScreen(): React.JSX.Element {
return;
}
saveOllamaApiURL(ollamaApiUrl);
if (ollamaApiUrl.length > 0) {
fetchAndSetModelNames().then();
}
fetchAndSetModelNames().then();
}, [ollamaApiUrl]);

useEffect(() => {
if (deepSeekApiKey === getDeepSeekApiKey()) {
return;
}
saveDeepSeekApiKey(deepSeekApiKey);
fetchAndSetModelNames().then();
}, [deepSeekApiKey]);

useEffect(() => {
if (openAIApiKey === getOpenAIApiKey()) {
return;
}
saveOpenAIApiKey(openAIApiKey);
fetchAndSetModelNames().then();
}, [openAIApiKey]);

const fetchAndSetModelNames = async () => {
controllerRef.current = new AbortController();
const ollamaModels = await requestAllOllamaModels();
const response = await requestAllModels();
addBedrockPrefixToDeepseekModels(response.textModel);
if (response.imageModel.length > 0) {
setImageModels(response.imageModel);
const imageModel = getImageModel();
Expand All @@ -170,13 +179,16 @@ function SettingsScreen(): React.JSX.Element {
}
}
if (response.textModel.length === 0) {
response.textModel = [...getDefaultTextModels(), ...ollamaModels];
response.textModel = [
...DefaultTextModel,
...ollamaModels,
...getDefaultApiKeyModels(),
];
} else {
response.textModel = [
...response.textModel,
...ollamaModels,
...DeepSeekModels,
...GPTModels,
...getDefaultApiKeyModels(),
];
}
setTextModels(response.textModel);
Expand Down
14 changes: 10 additions & 4 deletions react-native/src/storage/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Model, SystemPrompt } from '../types/Chat.ts';
import { getDeepSeekApiKey, getOpenAIApiKey } from './StorageUtils.ts';

const RegionList = [
'us-west-2',
Expand Down Expand Up @@ -28,13 +29,11 @@ export const DeepSeekModels = [

export const BedrockThinkingModels = ['Claude 3.7 Sonnet'];

const DefaultTextModel = [
export const DefaultTextModel = [
{
modelName: 'Nova Pro',
modelId: 'us.amazon.nova-pro-v1:0',
},
...DeepSeekModels,
...GPTModels,
];

const DefaultImageModel = {
Expand Down Expand Up @@ -78,7 +77,14 @@ export function getAllRegions() {
}

export function getDefaultTextModels() {
return DefaultTextModel as Model[];
return [...DefaultTextModel, ...getDefaultApiKeyModels()] as Model[];
}

export function getDefaultApiKeyModels() {
return [
...(getDeepSeekApiKey().length > 0 ? DeepSeekModels : []),
...(getOpenAIApiKey().length > 0 ? GPTModels : []),
] as Model[];
}

export function getDefaultImageModels() {
Expand Down