fix: Remove all remaining grok references, delete GrokChat.tsx
This commit is contained in:
parent
5d4413ff51
commit
6e833b24a6
2 changed files with 2 additions and 269 deletions
|
|
@ -15,12 +15,9 @@ export function CookieExpiredDialog() {
|
|||
|
||||
if (!showCookieExpired) return null;
|
||||
|
||||
const providerName = settings.provider === 'meta' ? 'Meta AI' :
|
||||
settings.provider === 'grok' ? 'Grok' :
|
||||
'Google Whisk';
|
||||
const providerName = settings.provider === 'meta' ? 'Meta AI' : 'Google Whisk';
|
||||
|
||||
const providerUrl = settings.provider === 'meta' ? 'https://www.meta.ai' :
|
||||
settings.provider === 'grok' ? 'https://grok.com' :
|
||||
'https://labs.google/fx/tools/whisk/project';
|
||||
|
||||
const handleFixIssues = () => {
|
||||
|
|
|
|||
|
|
@ -1,264 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { X, Send, Maximize2, Minimize2, Loader2, Bot, Zap, Brain } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useStore } from '@/lib/store';
|
||||
|
||||
interface Message {
|
||||
role: 'user' | 'assistant';
|
||||
content: string;
|
||||
}
|
||||
|
||||
type AIProvider = 'grok' | 'meta';
|
||||
|
||||
const aiProviders = [
|
||||
{ id: 'grok' as AIProvider, name: 'Grok', icon: Zap, color: 'text-purple-400' },
|
||||
{ id: 'meta' as AIProvider, name: 'Llama 3', icon: Brain, color: 'text-blue-400' },
|
||||
];
|
||||
|
||||
export function GrokChat() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isMinimized, setIsMinimized] = useState(false);
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [input, setInput] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [selectedAI, setSelectedAI] = useState<AIProvider>('grok');
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// Auto-scroll to bottom
|
||||
useEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages, isOpen]);
|
||||
|
||||
// Focus input when opened
|
||||
useEffect(() => {
|
||||
if (isOpen && !isMinimized) {
|
||||
setTimeout(() => inputRef.current?.focus(), 100);
|
||||
}
|
||||
}, [isOpen, isMinimized]);
|
||||
|
||||
const handleSend = async () => {
|
||||
if (!input.trim() || isLoading) return;
|
||||
|
||||
const userMsg = input.trim();
|
||||
setInput('');
|
||||
setMessages(prev => [...prev, { role: 'user', content: userMsg }]);
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const history = messages.slice(-10).map(m => ({ role: m.role, content: m.content }));
|
||||
const { settings } = useStore.getState();
|
||||
|
||||
let res: Response;
|
||||
|
||||
if (selectedAI === 'grok') {
|
||||
// Use Grok via xLmiler backend
|
||||
const grokApiUrl = settings.grokApiUrl || 'http://localhost:3000';
|
||||
const apiKey = settings.grokApiKey;
|
||||
|
||||
res = await fetch('/api/grok-chat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
message: userMsg,
|
||||
history,
|
||||
grokApiUrl,
|
||||
apiKey
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// Use Meta AI (Llama 3)
|
||||
res = await fetch('/api/meta-chat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
message: userMsg,
|
||||
history,
|
||||
metaCookies: settings.metaCookies
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.error || data.detail) {
|
||||
const errorMsg = data.error || JSON.stringify(data.detail);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
setMessages(prev => [...prev, { role: 'assistant', content: data.response }]);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Chat Error:', error);
|
||||
setMessages(prev => [...prev, {
|
||||
role: 'assistant',
|
||||
content: `Error: ${error.message || 'Failed to connect.'}`
|
||||
}]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
handleSend();
|
||||
}
|
||||
};
|
||||
|
||||
const currentProvider = aiProviders.find(p => p.id === selectedAI)!;
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-4 right-4 z-[100] flex flex-col items-end pointer-events-none">
|
||||
|
||||
{/* Toggle Button */}
|
||||
{!isOpen && (
|
||||
<motion.button
|
||||
initial={{ scale: 0 }}
|
||||
animate={{ scale: 1 }}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="pointer-events-auto bg-black border border-white/20 text-white p-4 rounded-full shadow-2xl hover:shadow-purple-500/20 hover:border-purple-500/50 transition-all group"
|
||||
>
|
||||
<Bot className="h-8 w-8 group-hover:text-purple-400 transition-colors" />
|
||||
</motion.button>
|
||||
)}
|
||||
|
||||
{/* Chat Window */}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20, scale: 0.9 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
height: isMinimized ? 'auto' : '500px',
|
||||
width: isMinimized ? '300px' : '400px'
|
||||
}}
|
||||
exit={{ opacity: 0, y: 20, scale: 0.9 }}
|
||||
className="pointer-events-auto bg-black/90 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl overflow-hidden flex flex-col"
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-white/10 bg-white/5">
|
||||
<div className="flex items-center gap-3">
|
||||
{/* AI Selector */}
|
||||
<div className="flex bg-white/5 rounded-lg p-0.5">
|
||||
{aiProviders.map((provider) => (
|
||||
<button
|
||||
key={provider.id}
|
||||
onClick={() => {
|
||||
setSelectedAI(provider.id);
|
||||
setMessages([]); // Clear history on switch
|
||||
}}
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-medium transition-all",
|
||||
selectedAI === provider.id
|
||||
? "bg-white/10 text-white"
|
||||
: "text-white/50 hover:text-white/80"
|
||||
)}
|
||||
>
|
||||
<provider.icon className={cn("h-3.5 w-3.5", selectedAI === provider.id && provider.color)} />
|
||||
{provider.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={() => setIsMinimized(!isMinimized)}
|
||||
className="p-1.5 hover:bg-white/10 rounded-md text-white/70 hover:text-white transition-colors"
|
||||
>
|
||||
{isMinimized ? <Maximize2 className="h-4 w-4" /> : <Minimize2 className="h-4 w-4" />}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="p-1.5 hover:bg-red-500/20 hover:text-red-400 rounded-md text-white/70 transition-colors"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Messages Area */}
|
||||
{!isMinimized && (
|
||||
<>
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-4 custom-scrollbar">
|
||||
{messages.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center h-full text-center text-white/30 space-y-2">
|
||||
<currentProvider.icon className={cn("h-12 w-12 opacity-50", currentProvider.color)} />
|
||||
<p className="text-sm">Ask {currentProvider.name} anything...</p>
|
||||
</div>
|
||||
)}
|
||||
{messages.map((msg, idx) => (
|
||||
<div key={idx} className={cn(
|
||||
"flex w-full",
|
||||
msg.role === 'user' ? "justify-end" : "justify-start"
|
||||
)}>
|
||||
<div className={cn(
|
||||
"max-w-[85%] rounded-2xl px-4 py-2.5 text-sm leading-relaxed",
|
||||
msg.role === 'user'
|
||||
? selectedAI === 'grok'
|
||||
? "bg-purple-600/80 text-white rounded-br-sm"
|
||||
: "bg-blue-600/80 text-white rounded-br-sm"
|
||||
: "bg-white/10 text-white/90 rounded-bl-sm"
|
||||
)}>
|
||||
{msg.content}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{isLoading && (
|
||||
<div className="flex justify-start">
|
||||
<div className="bg-white/5 rounded-2xl px-4 py-2 flex items-center gap-2">
|
||||
<Loader2 className={cn("h-4 w-4 animate-spin", currentProvider.color)} />
|
||||
<span className="text-xs text-white/50">Thinking...</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
{/* Input Area */}
|
||||
<div className="p-4 border-t border-white/10 bg-white/5">
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={`Message ${currentProvider.name}...`}
|
||||
className={cn(
|
||||
"flex-1 bg-black/50 border border-white/10 rounded-xl px-4 py-2.5 text-sm text-white focus:outline-none transition-all placeholder:text-white/20",
|
||||
selectedAI === 'grok'
|
||||
? "focus:border-purple-500/50 focus:ring-1 focus:ring-purple-500/20"
|
||||
: "focus:border-blue-500/50 focus:ring-1 focus:ring-blue-500/20"
|
||||
)}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<button
|
||||
onClick={handleSend}
|
||||
disabled={!input.trim() || isLoading}
|
||||
className={cn(
|
||||
"p-2.5 disabled:opacity-50 disabled:cursor-not-allowed rounded-xl text-white transition-colors shadow-lg",
|
||||
selectedAI === 'grok'
|
||||
? "bg-purple-600 hover:bg-purple-500 shadow-purple-900/20"
|
||||
: "bg-blue-600 hover:bg-blue-500 shadow-blue-900/20"
|
||||
)}
|
||||
>
|
||||
<Send className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue