diff --git a/.env.example b/.env.example index ec825e8e..83f29aed 100644 --- a/.env.example +++ b/.env.example @@ -43,5 +43,10 @@ OPENAI_LIKE_API_KEY= # You only need this environment variable set if you want to use Mistral models MISTRAL_API_KEY= +# Get your xAI API key +# https://x.ai/api +# You only need this environment variable set if you want to use xAI models +XAI_API_KEY= + # Include this environment variable if you want more logging for debugging locally VITE_LOG_LEVEL=debug diff --git a/app/components/chat/APIKeyManager.tsx b/app/components/chat/APIKeyManager.tsx new file mode 100644 index 00000000..aab70107 --- /dev/null +++ b/app/components/chat/APIKeyManager.tsx @@ -0,0 +1,49 @@ +import React, { useState } from 'react'; +import { IconButton } from '~/components/ui/IconButton'; + +interface APIKeyManagerProps { + provider: string; + apiKey: string; + setApiKey: (key: string) => void; +} + +export const APIKeyManager: React.FC = ({ provider, apiKey, setApiKey }) => { + const [isEditing, setIsEditing] = useState(false); + const [tempKey, setTempKey] = useState(apiKey); + + const handleSave = () => { + setApiKey(tempKey); + setIsEditing(false); + }; + + return ( +
+ {provider} API Key: + {isEditing ? ( + <> + setTempKey(e.target.value)} + className="flex-1 p-1 text-sm rounded border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus" + /> + +
+ + setIsEditing(false)} title="Cancel"> +
+ + + ) : ( + <> + + {apiKey ? '••••••••' : 'Not set'} + + setIsEditing(true)} title="Edit API Key"> +
+ + + )} +
+ ); +}; diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index a47b6adf..bb0c5273 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -1,7 +1,7 @@ // @ts-nocheck // Preventing TS checks with files presented in the video for a better presentation. import type { Message } from 'ai'; -import React, { type RefCallback } from 'react'; +import React, { type RefCallback, useEffect } from 'react'; import { ClientOnly } from 'remix-utils/client-only'; import { Menu } from '~/components/sidebar/Menu.client'; import { IconButton } from '~/components/ui/IconButton'; @@ -11,6 +11,8 @@ import { MODEL_LIST, DEFAULT_PROVIDER } from '~/utils/constants'; import { Messages } from './Messages.client'; import { SendButton } from './SendButton.client'; import { useState } from 'react'; +import { APIKeyManager } from './APIKeyManager'; +import Cookies from 'js-cookie'; import styles from './BaseChat.module.scss'; @@ -26,15 +28,15 @@ const providerList = [...new Set(MODEL_LIST.map((model) => model.provider))] const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList }) => { return ( -
- { setProvider(e.target.value); const firstModel = [...modelList].find(m => m.provider == e.target.value); setModel(firstModel ? firstModel.name : ''); }} - className="w-full p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none" + className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all" > {providerList.map((provider) => (