@@ -83,73 +76,35 @@ const Page = () => {
-
- {topics.map((t, i) => (
-
setActiveTopic(t.key)}
- >
- {t.display}
-
- ))}
-
-
- {loading ? (
-
- ) : (
-
- {discover &&
- discover?.map((item, i) => (
-
-

-
-
- {item.title.slice(0, 100)}...
-
-
- {item.content.slice(0, 100)}...
-
+
+ {discover &&
+ discover?.map((item, i) => (
+
+

+
+
+ {item.title.slice(0, 100)}...
-
- ))}
-
- )}
+
+ {item.content.slice(0, 100)}...
+
+
+
+ ))}
+
>
);
diff --git a/src/app/globals.css b/src/app/globals.css
index 6bdc1a8..f75daca 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -11,11 +11,3 @@
display: none;
}
}
-
-@media screen and (-webkit-min-device-pixel-ratio: 0) {
- select,
- textarea,
- input {
- font-size: 16px !important;
- }
-}
diff --git a/src/app/manifest.ts b/src/app/manifest.ts
deleted file mode 100644
index 792e752..0000000
--- a/src/app/manifest.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import type { MetadataRoute } from 'next';
-
-export default function manifest(): MetadataRoute.Manifest {
- return {
- name: 'Perplexica - Chat with the internet',
- short_name: 'Perplexica',
- description:
- 'Perplexica is an AI powered chatbot that is connected to the internet.',
- start_url: '/',
- display: 'standalone',
- background_color: '#0a0a0a',
- theme_color: '#0a0a0a',
- screenshots: [
- {
- src: '/screenshots/p1.png',
- form_factor: 'wide',
- sizes: '2560x1600',
- },
- {
- src: '/screenshots/p2.png',
- form_factor: 'wide',
- sizes: '2560x1600',
- },
- {
- src: '/screenshots/p1_small.png',
- form_factor: 'narrow',
- sizes: '828x1792',
- },
- {
- src: '/screenshots/p2_small.png',
- form_factor: 'narrow',
- sizes: '828x1792',
- },
- ],
- icons: [
- {
- src: '/icon-50.png',
- sizes: '50x50',
- type: 'image/png' as const,
- },
- {
- src: '/icon-100.png',
- sizes: '100x100',
- type: 'image/png',
- },
- {
- src: '/icon.png',
- sizes: '440x440',
- type: 'image/png',
- purpose: 'any',
- },
- ],
- };
-}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 25981b5..e18aca9 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,5 +1,4 @@
import ChatWindow from '@/components/ChatWindow';
-import { ChatProvider } from '@/lib/hooks/useChat';
import { Metadata } from 'next';
import { Suspense } from 'react';
@@ -12,9 +11,7 @@ const Home = () => {
return (
-
-
-
+
);
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
index 6fb8255..05338c3 100644
--- a/src/app/settings/page.tsx
+++ b/src/app/settings/page.tsx
@@ -21,10 +21,8 @@ interface SettingsType {
anthropicApiKey: string;
geminiApiKey: string;
ollamaApiUrl: string;
- ollamaApiKey: string;
lmStudioApiUrl: string;
deepseekApiKey: string;
- aimlApiKey: string;
customOpenaiApiKey: string;
customOpenaiApiUrl: string;
customOpenaiModelName: string;
@@ -145,17 +143,15 @@ const Page = () => {
const [selectedEmbeddingModel, setSelectedEmbeddingModel] = useState<
string | null
>(null);
- const [isLoading, setIsLoading] = useState(true);
+ const [isLoading, setIsLoading] = useState(false);
const [automaticImageSearch, setAutomaticImageSearch] = useState(false);
const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false);
const [systemInstructions, setSystemInstructions] = useState
('');
- const [measureUnit, setMeasureUnit] = useState<'Imperial' | 'Metric'>(
- 'Metric',
- );
const [savingStates, setSavingStates] = useState>({});
useEffect(() => {
const fetchConfig = async () => {
+ setIsLoading(true);
const res = await fetch(`/api/config`, {
headers: {
'Content-Type': 'application/json',
@@ -214,10 +210,6 @@ const Page = () => {
setSystemInstructions(localStorage.getItem('systemInstructions')!);
- setMeasureUnit(
- localStorage.getItem('measureUnit')! as 'Imperial' | 'Metric',
- );
-
setIsLoading(false);
};
@@ -376,8 +368,6 @@ const Page = () => {
localStorage.setItem('embeddingModel', value);
} else if (key === 'systemInstructions') {
localStorage.setItem('systemInstructions', value);
- } else if (key === 'measureUnit') {
- localStorage.setItem('measureUnit', value.toString());
}
} catch (err) {
console.error('Failed to save:', err);
@@ -426,35 +416,13 @@ const Page = () => {
) : (
config && (
-
+
-
-
- Measurement Units
-
-
@@ -548,7 +516,7 @@ const Page = () => {
-
-
- Ollama API Key (Can be left blank)
-
-
{
- setConfig((prev) => ({
- ...prev!,
- ollamaApiKey: e.target.value,
- }));
- }}
- onSave={(value) => saveConfig('ollamaApiKey', value)}
- />
-
-
GROQ API Key
@@ -914,25 +863,6 @@ const Page = () => {
/>
-
-
- AI/ML API Key
-
-
{
- setConfig((prev) => ({
- ...prev!,
- aimlApiKey: e.target.value,
- }));
- }}
- onSave={(value) => saveConfig('aimlApiKey', value)}
- />
-
-
LM Studio API URL
diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx
index a5d8cf9..0cf125b 100644
--- a/src/components/Chat.tsx
+++ b/src/components/Chat.tsx
@@ -5,11 +5,28 @@ import MessageInput from './MessageInput';
import { File, Message } from './ChatWindow';
import MessageBox from './MessageBox';
import MessageBoxLoading from './MessageBoxLoading';
-import { useChat } from '@/lib/hooks/useChat';
-
-const Chat = () => {
- const { messages, loading, messageAppeared } = useChat();
+const Chat = ({
+ loading,
+ messages,
+ sendMessage,
+ messageAppeared,
+ rewrite,
+ fileIds,
+ setFileIds,
+ files,
+ setFiles,
+}: {
+ messages: Message[];
+ sendMessage: (message: string) => void;
+ loading: boolean;
+ messageAppeared: boolean;
+ rewrite: (messageId: string) => void;
+ fileIds: string[];
+ setFileIds: (fileIds: string[]) => void;
+ files: File[];
+ setFiles: (files: File[]) => void;
+}) => {
const [dividerWidth, setDividerWidth] = useState(0);
const dividerRef = useRef(null);
const messageEnd = useRef(null);
@@ -55,8 +72,12 @@ const Chat = () => {
key={i}
message={msg}
messageIndex={i}
+ history={messages}
+ loading={loading}
dividerRef={isLast ? dividerRef : undefined}
isLast={isLast}
+ rewrite={rewrite}
+ sendMessage={sendMessage}
/>
{!isLast && msg.role === 'assistant' && (
@@ -71,7 +92,14 @@ const Chat = () => {
className="bottom-24 lg:bottom-10 fixed z-40"
style={{ width: dividerWidth }}
>
-
+
)}
diff --git a/src/components/ChatWindow.tsx b/src/components/ChatWindow.tsx
index 0d40c83..93c8a0c 100644
--- a/src/components/ChatWindow.tsx
+++ b/src/components/ChatWindow.tsx
@@ -1,13 +1,17 @@
'use client';
+import { useEffect, useRef, useState } from 'react';
import { Document } from '@langchain/core/documents';
import Navbar from './Navbar';
import Chat from './Chat';
import EmptyChat from './EmptyChat';
+import crypto from 'crypto';
+import { toast } from 'sonner';
+import { useSearchParams } from 'next/navigation';
+import { getSuggestions } from '@/lib/actions';
import { Settings } from 'lucide-react';
import Link from 'next/link';
import NextError from 'next/error';
-import { useChat } from '@/lib/hooks/useChat';
export type Message = {
messageId: string;
@@ -25,8 +29,512 @@ export interface File {
fileId: string;
}
-const ChatWindow = () => {
- const { hasError, isReady, notFound, messages } = useChat();
+interface ChatModelProvider {
+ name: string;
+ provider: string;
+}
+
+interface EmbeddingModelProvider {
+ name: string;
+ provider: string;
+}
+
+const checkConfig = async (
+ setChatModelProvider: (provider: ChatModelProvider) => void,
+ setEmbeddingModelProvider: (provider: EmbeddingModelProvider) => void,
+ setIsConfigReady: (ready: boolean) => void,
+ setHasError: (hasError: boolean) => void,
+) => {
+ try {
+ let chatModel = localStorage.getItem('chatModel');
+ let chatModelProvider = localStorage.getItem('chatModelProvider');
+ let embeddingModel = localStorage.getItem('embeddingModel');
+ let embeddingModelProvider = localStorage.getItem('embeddingModelProvider');
+
+ const autoImageSearch = localStorage.getItem('autoImageSearch');
+ const autoVideoSearch = localStorage.getItem('autoVideoSearch');
+
+ if (!autoImageSearch) {
+ localStorage.setItem('autoImageSearch', 'true');
+ }
+
+ if (!autoVideoSearch) {
+ localStorage.setItem('autoVideoSearch', 'false');
+ }
+
+ const providers = await fetch(`/api/models`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }).then(async (res) => {
+ if (!res.ok)
+ throw new Error(
+ `Failed to fetch models: ${res.status} ${res.statusText}`,
+ );
+ return res.json();
+ });
+
+ if (
+ !chatModel ||
+ !chatModelProvider ||
+ !embeddingModel ||
+ !embeddingModelProvider
+ ) {
+ if (!chatModel || !chatModelProvider) {
+ const chatModelProviders = providers.chatModelProviders;
+
+ chatModelProvider =
+ chatModelProvider || Object.keys(chatModelProviders)[0];
+
+ chatModel = Object.keys(chatModelProviders[chatModelProvider])[0];
+
+ if (!chatModelProviders || Object.keys(chatModelProviders).length === 0)
+ return toast.error('No chat models available');
+ }
+
+ if (!embeddingModel || !embeddingModelProvider) {
+ const embeddingModelProviders = providers.embeddingModelProviders;
+
+ if (
+ !embeddingModelProviders ||
+ Object.keys(embeddingModelProviders).length === 0
+ )
+ return toast.error('No embedding models available');
+
+ embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
+ embeddingModel = Object.keys(
+ embeddingModelProviders[embeddingModelProvider],
+ )[0];
+ }
+
+ localStorage.setItem('chatModel', chatModel!);
+ localStorage.setItem('chatModelProvider', chatModelProvider);
+ localStorage.setItem('embeddingModel', embeddingModel!);
+ localStorage.setItem('embeddingModelProvider', embeddingModelProvider);
+ } else {
+ const chatModelProviders = providers.chatModelProviders;
+ const embeddingModelProviders = providers.embeddingModelProviders;
+
+ if (
+ Object.keys(chatModelProviders).length > 0 &&
+ !chatModelProviders[chatModelProvider]
+ ) {
+ const chatModelProvidersKeys = Object.keys(chatModelProviders);
+ chatModelProvider =
+ chatModelProvidersKeys.find(
+ (key) => Object.keys(chatModelProviders[key]).length > 0,
+ ) || chatModelProvidersKeys[0];
+
+ localStorage.setItem('chatModelProvider', chatModelProvider);
+ }
+
+ if (
+ chatModelProvider &&
+ !chatModelProviders[chatModelProvider][chatModel]
+ ) {
+ chatModel = Object.keys(
+ chatModelProviders[
+ Object.keys(chatModelProviders[chatModelProvider]).length > 0
+ ? chatModelProvider
+ : Object.keys(chatModelProviders)[0]
+ ],
+ )[0];
+ localStorage.setItem('chatModel', chatModel);
+ }
+
+ if (
+ Object.keys(embeddingModelProviders).length > 0 &&
+ !embeddingModelProviders[embeddingModelProvider]
+ ) {
+ embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
+ localStorage.setItem('embeddingModelProvider', embeddingModelProvider);
+ }
+
+ if (
+ embeddingModelProvider &&
+ !embeddingModelProviders[embeddingModelProvider][embeddingModel]
+ ) {
+ embeddingModel = Object.keys(
+ embeddingModelProviders[embeddingModelProvider],
+ )[0];
+ localStorage.setItem('embeddingModel', embeddingModel);
+ }
+ }
+
+ setChatModelProvider({
+ name: chatModel!,
+ provider: chatModelProvider,
+ });
+
+ setEmbeddingModelProvider({
+ name: embeddingModel!,
+ provider: embeddingModelProvider,
+ });
+
+ setIsConfigReady(true);
+ } catch (err) {
+ console.error('An error occurred while checking the configuration:', err);
+ setIsConfigReady(false);
+ setHasError(true);
+ }
+};
+
+const loadMessages = async (
+ chatId: string,
+ setMessages: (messages: Message[]) => void,
+ setIsMessagesLoaded: (loaded: boolean) => void,
+ setChatHistory: (history: [string, string][]) => void,
+ setFocusMode: (mode: string) => void,
+ setNotFound: (notFound: boolean) => void,
+ setFiles: (files: File[]) => void,
+ setFileIds: (fileIds: string[]) => void,
+) => {
+ const res = await fetch(`/api/chats/${chatId}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ if (res.status === 404) {
+ setNotFound(true);
+ setIsMessagesLoaded(true);
+ return;
+ }
+
+ const data = await res.json();
+
+ const messages = data.messages.map((msg: any) => {
+ return {
+ ...msg,
+ ...JSON.parse(msg.metadata),
+ };
+ }) as Message[];
+
+ setMessages(messages);
+
+ const history = messages.map((msg) => {
+ return [msg.role, msg.content];
+ }) as [string, string][];
+
+ console.debug(new Date(), 'app:messages_loaded');
+
+ document.title = messages[0].content;
+
+ const files = data.chat.files.map((file: any) => {
+ return {
+ fileName: file.name,
+ fileExtension: file.name.split('.').pop(),
+ fileId: file.fileId,
+ };
+ });
+
+ setFiles(files);
+ setFileIds(files.map((file: File) => file.fileId));
+
+ setChatHistory(history);
+ setFocusMode(data.chat.focusMode);
+ setIsMessagesLoaded(true);
+};
+
+const ChatWindow = ({ id }: { id?: string }) => {
+ const searchParams = useSearchParams();
+ const initialMessage = searchParams.get('q');
+
+ const [chatId, setChatId] = useState(id);
+ const [newChatCreated, setNewChatCreated] = useState(false);
+
+ const [chatModelProvider, setChatModelProvider] = useState(
+ {
+ name: '',
+ provider: '',
+ },
+ );
+
+ const [embeddingModelProvider, setEmbeddingModelProvider] =
+ useState({
+ name: '',
+ provider: '',
+ });
+
+ const [isConfigReady, setIsConfigReady] = useState(false);
+ const [hasError, setHasError] = useState(false);
+ const [isReady, setIsReady] = useState(false);
+
+ useEffect(() => {
+ checkConfig(
+ setChatModelProvider,
+ setEmbeddingModelProvider,
+ setIsConfigReady,
+ setHasError,
+ );
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const [loading, setLoading] = useState(false);
+ const [messageAppeared, setMessageAppeared] = useState(false);
+
+ const [chatHistory, setChatHistory] = useState<[string, string][]>([]);
+ const [messages, setMessages] = useState([]);
+
+ const [files, setFiles] = useState([]);
+ const [fileIds, setFileIds] = useState([]);
+
+ const [focusMode, setFocusMode] = useState('webSearch');
+ const [optimizationMode, setOptimizationMode] = useState('speed');
+
+ const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
+
+ const [notFound, setNotFound] = useState(false);
+
+ useEffect(() => {
+ if (
+ chatId &&
+ !newChatCreated &&
+ !isMessagesLoaded &&
+ messages.length === 0
+ ) {
+ loadMessages(
+ chatId,
+ setMessages,
+ setIsMessagesLoaded,
+ setChatHistory,
+ setFocusMode,
+ setNotFound,
+ setFiles,
+ setFileIds,
+ );
+ } else if (!chatId) {
+ setNewChatCreated(true);
+ setIsMessagesLoaded(true);
+ setChatId(crypto.randomBytes(20).toString('hex'));
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const messagesRef = useRef([]);
+
+ useEffect(() => {
+ messagesRef.current = messages;
+ }, [messages]);
+
+ useEffect(() => {
+ if (isMessagesLoaded && isConfigReady) {
+ setIsReady(true);
+ console.debug(new Date(), 'app:ready');
+ } else {
+ setIsReady(false);
+ }
+ }, [isMessagesLoaded, isConfigReady]);
+
+ const sendMessage = async (message: string, messageId?: string) => {
+ if (loading) return;
+ if (!isConfigReady) {
+ toast.error('Cannot send message before the configuration is ready');
+ return;
+ }
+
+ setLoading(true);
+ setMessageAppeared(false);
+
+ let sources: Document[] | undefined = undefined;
+ let recievedMessage = '';
+ let added = false;
+
+ messageId = messageId ?? crypto.randomBytes(7).toString('hex');
+
+ setMessages((prevMessages) => [
+ ...prevMessages,
+ {
+ content: message,
+ messageId: messageId,
+ chatId: chatId!,
+ role: 'user',
+ createdAt: new Date(),
+ },
+ ]);
+
+ const messageHandler = async (data: any) => {
+ if (data.type === 'error') {
+ toast.error(data.data);
+ setLoading(false);
+ return;
+ }
+
+ if (data.type === 'sources') {
+ sources = data.data;
+ if (!added) {
+ setMessages((prevMessages) => [
+ ...prevMessages,
+ {
+ content: '',
+ messageId: data.messageId,
+ chatId: chatId!,
+ role: 'assistant',
+ sources: sources,
+ createdAt: new Date(),
+ },
+ ]);
+ added = true;
+ }
+ setMessageAppeared(true);
+ }
+
+ if (data.type === 'message') {
+ if (!added) {
+ setMessages((prevMessages) => [
+ ...prevMessages,
+ {
+ content: data.data,
+ messageId: data.messageId,
+ chatId: chatId!,
+ role: 'assistant',
+ sources: sources,
+ createdAt: new Date(),
+ },
+ ]);
+ added = true;
+ }
+
+ setMessages((prev) =>
+ prev.map((message) => {
+ if (message.messageId === data.messageId) {
+ return { ...message, content: message.content + data.data };
+ }
+
+ return message;
+ }),
+ );
+
+ recievedMessage += data.data;
+ setMessageAppeared(true);
+ }
+
+ if (data.type === 'messageEnd') {
+ setChatHistory((prevHistory) => [
+ ...prevHistory,
+ ['human', message],
+ ['assistant', recievedMessage],
+ ]);
+
+ setLoading(false);
+
+ const lastMsg = messagesRef.current[messagesRef.current.length - 1];
+
+ const autoImageSearch = localStorage.getItem('autoImageSearch');
+ const autoVideoSearch = localStorage.getItem('autoVideoSearch');
+
+ if (autoImageSearch === 'true') {
+ document
+ .getElementById(`search-images-${lastMsg.messageId}`)
+ ?.click();
+ }
+
+ if (autoVideoSearch === 'true') {
+ document
+ .getElementById(`search-videos-${lastMsg.messageId}`)
+ ?.click();
+ }
+
+ if (
+ lastMsg.role === 'assistant' &&
+ lastMsg.sources &&
+ lastMsg.sources.length > 0 &&
+ !lastMsg.suggestions
+ ) {
+ const suggestions = await getSuggestions(messagesRef.current);
+ setMessages((prev) =>
+ prev.map((msg) => {
+ if (msg.messageId === lastMsg.messageId) {
+ return { ...msg, suggestions: suggestions };
+ }
+ return msg;
+ }),
+ );
+ }
+ }
+ };
+
+ const res = await fetch('/api/chat', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ content: message,
+ message: {
+ messageId: messageId,
+ chatId: chatId!,
+ content: message,
+ },
+ chatId: chatId!,
+ files: fileIds,
+ focusMode: focusMode,
+ optimizationMode: optimizationMode,
+ history: chatHistory,
+ chatModel: {
+ name: chatModelProvider.name,
+ provider: chatModelProvider.provider,
+ },
+ embeddingModel: {
+ name: embeddingModelProvider.name,
+ provider: embeddingModelProvider.provider,
+ },
+ systemInstructions: localStorage.getItem('systemInstructions'),
+ }),
+ });
+
+ if (!res.body) throw new Error('No response body');
+
+ const reader = res.body?.getReader();
+ const decoder = new TextDecoder('utf-8');
+
+ let partialChunk = '';
+
+ while (true) {
+ const { value, done } = await reader.read();
+ if (done) break;
+
+ partialChunk += decoder.decode(value, { stream: true });
+
+ try {
+ const messages = partialChunk.split('\n');
+ for (const msg of messages) {
+ if (!msg.trim()) continue;
+ const json = JSON.parse(msg);
+ messageHandler(json);
+ }
+ partialChunk = '';
+ } catch (error) {
+ console.warn('Incomplete JSON, waiting for next chunk...');
+ }
+ }
+ };
+
+ const rewrite = (messageId: string) => {
+ const index = messages.findIndex((msg) => msg.messageId === messageId);
+
+ if (index === -1) return;
+
+ const message = messages[index - 1];
+
+ setMessages((prev) => {
+ return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
+ });
+ setChatHistory((prev) => {
+ return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
+ });
+
+ sendMessage(message.content, message.messageId);
+ };
+
+ useEffect(() => {
+ if (isReady && initialMessage && isConfigReady) {
+ sendMessage(initialMessage);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isConfigReady, isReady, initialMessage]);
+
if (hasError) {
return (
@@ -51,11 +559,31 @@ const ChatWindow = () => {
{messages.length > 0 ? (
<>
-
-
+
+
>
) : (
-
+
)}
)
diff --git a/src/components/EmptyChat.tsx b/src/components/EmptyChat.tsx
index e40a338..838849f 100644
--- a/src/components/EmptyChat.tsx
+++ b/src/components/EmptyChat.tsx
@@ -1,11 +1,32 @@
import { Settings } from 'lucide-react';
import EmptyChatMessageInput from './EmptyChatMessageInput';
+import { useState } from 'react';
import { File } from './ChatWindow';
import Link from 'next/link';
-import WeatherWidget from './WeatherWidget';
-import NewsArticleWidget from './NewsArticleWidget';
-const EmptyChat = () => {
+const EmptyChat = ({
+ sendMessage,
+ focusMode,
+ setFocusMode,
+ optimizationMode,
+ setOptimizationMode,
+ fileIds,
+ setFileIds,
+ files,
+ setFiles,
+}: {
+ sendMessage: (message: string) => void;
+ focusMode: string;
+ setFocusMode: (mode: string) => void;
+ optimizationMode: string;
+ setOptimizationMode: (mode: string) => void;
+ fileIds: string[];
+ setFileIds: (fileIds: string[]) => void;
+ files: File[];
+ setFiles: (files: File[]) => void;
+}) => {
+ const [isSettingsOpen, setIsSettingsOpen] = useState(false);
+
return (
@@ -13,21 +34,21 @@ const EmptyChat = () => {
-
-
-
- Research begins here.
-
-
-
-
+
+
+ Research begins here.
+
+
);
diff --git a/src/components/EmptyChatMessageInput.tsx b/src/components/EmptyChatMessageInput.tsx
index 3c5ff6b..43d1e28 100644
--- a/src/components/EmptyChatMessageInput.tsx
+++ b/src/components/EmptyChatMessageInput.tsx
@@ -1,15 +1,34 @@
import { ArrowRight } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
+import CopilotToggle from './MessageInputActions/Copilot';
import Focus from './MessageInputActions/Focus';
import Optimization from './MessageInputActions/Optimization';
import Attach from './MessageInputActions/Attach';
-import { useChat } from '@/lib/hooks/useChat';
+import { File } from './ChatWindow';
-const EmptyChatMessageInput = () => {
- const { sendMessage } = useChat();
-
- /* const [copilotEnabled, setCopilotEnabled] = useState(false); */
+const EmptyChatMessageInput = ({
+ sendMessage,
+ focusMode,
+ setFocusMode,
+ optimizationMode,
+ setOptimizationMode,
+ fileIds,
+ setFileIds,
+ files,
+ setFiles,
+}: {
+ sendMessage: (message: string) => void;
+ focusMode: string;
+ setFocusMode: (mode: string) => void;
+ optimizationMode: string;
+ setOptimizationMode: (mode: string) => void;
+ fileIds: string[];
+ setFileIds: (fileIds: string[]) => void;
+ files: File[];
+ setFiles: (files: File[]) => void;
+}) => {
+ const [copilotEnabled, setCopilotEnabled] = useState(false);
const [message, setMessage] = useState('');
const inputRef = useRef
(null);
@@ -65,11 +84,20 @@ const EmptyChatMessageInput = () => {
/>
-
+