// @ts-nocheck // Preventing TS checks with files presented in the video for a better presentation. import type { Message } from 'ai'; 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'; import { Workbench } from '~/components/workbench/Workbench.client'; import { classNames } from '~/utils/classNames'; import { MODEL_LIST, DEFAULT_PROVIDER, PROVIDER_LIST, initializeModelList } 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'; import type { ProviderInfo } from '~/utils/types'; import FilePreview from './FilePreview'; const EXAMPLE_PROMPTS = [ { text: 'Build a todo app in React using Tailwind' }, { text: 'Build a simple blog using Astro' }, { text: 'Create a cookie consent form using Material UI' }, { text: 'Make a space invaders game' }, { text: 'How do I center a div?' }, ]; const providerList = PROVIDER_LIST; const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList }) => { return (
); }; const TEXTAREA_MIN_HEIGHT = 76; interface BaseChatProps { textareaRef?: React.RefObject | undefined; messageRef?: RefCallback | undefined; scrollRef?: RefCallback | undefined; showChat?: boolean; chatStarted?: boolean; isStreaming?: boolean; messages?: Message[]; enhancingPrompt?: boolean; promptEnhanced?: boolean; input?: string; model?: string; setModel?: (model: string) => void; provider?: ProviderInfo; setProvider?: (provider: ProviderInfo) => void; handleStop?: () => void; sendMessage?: (event: React.UIEvent, messageInput?: string) => void; handleInputChange?: (event: React.ChangeEvent) => void; enhancePrompt?: () => void; uploadedFiles?: File[]; setUploadedFiles?: (files: File[]) => void; imageDataList?: string[]; setImageDataList?: (dataList: string[]) => void; } export const BaseChat = React.forwardRef( ( { textareaRef, messageRef, scrollRef, showChat = true, chatStarted = false, isStreaming = false, model, setModel, provider, setProvider, input = '', enhancingPrompt, handleInputChange, promptEnhanced, enhancePrompt, sendMessage, handleStop, uploadedFiles, setUploadedFiles, imageDataList, setImageDataList, messages, children, // Add this }, ref, ) => { const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200; const [apiKeys, setApiKeys] = useState>({}); const [modelList, setModelList] = useState(MODEL_LIST); useEffect(() => { // Load API keys from cookies on component mount try { const storedApiKeys = Cookies.get('apiKeys'); if (storedApiKeys) { const parsedKeys = JSON.parse(storedApiKeys); if (typeof parsedKeys === 'object' && parsedKeys !== null) { setApiKeys(parsedKeys); } } } catch (error) { console.error('Error loading API keys from cookies:', error); // Clear invalid cookie data Cookies.remove('apiKeys'); } initializeModelList().then((modelList) => { setModelList(modelList); }); }, []); const updateApiKey = (provider: string, key: string) => { try { const updatedApiKeys = { ...apiKeys, [provider]: key }; setApiKeys(updatedApiKeys); // Save updated API keys to cookies with 30 day expiry and secure settings Cookies.set('apiKeys', JSON.stringify(updatedApiKeys), { expires: 30, // 30 days secure: true, // Only send over HTTPS sameSite: 'strict', // Protect against CSRF path: '/', // Accessible across the site }); } catch (error) { console.error('Error saving API keys to cookies:', error); } }; const handleRemoveFile = () => { setUploadedFiles([]); setImageDataList([]); }; const handleFileUpload = () => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.onchange = async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const base64Image = e.target?.result as string; setUploadedFiles?.([...uploadedFiles, file]); setImageDataList?.([...imageDataList, base64Image]); }; reader.readAsDataURL(file); } }; input.click(); }; return (
{() => }
{!chatStarted && (

Where ideas begin

Bring ideas to life in seconds or get help on existing projects.

)}
{() => { return chatStarted ? ( ) : null; }}
{provider && ( updateApiKey(provider.name, key)} /> )} { setUploadedFiles?.(uploadedFiles.filter((_, i) => i !== index)); setImageDataList?.(imageDataList.filter((_, i) => i !== index)); }} />