Spaces:
Sleeping
Sleeping
File size: 5,028 Bytes
ba76bdd befc75a ba76bdd 0e995a4 ba76bdd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
"use client";
import { useState } from 'react';
import Image from 'next/image';
import { useToast } from "@/hooks/use-toast";
import { generateChatbotResponse } from '@/ai/flows/generate-chatbot-response';
import type { Message } from '@/lib/types';
import MessageList from './message-list';
import MessageForm from './message-form';
import { ThemeToggle } from './theme-toggle';
import { Bot, X } from 'lucide-react';
import { Button } from './ui/button';
export function Chat() {
const [messages, setMessages] = useState<Message[]>([
{
id: '1',
role: 'assistant',
content: "जय जोहार! मैं चत्तीसवाणी हावंव। आप मन के का मदद कर सकत हंव?",
},
]);
const [input, setInput] = useState('');
const [file, setFile] = useState<File | null>(null);
const [isLoading, setIsLoading] = useState(false);
const { toast } = useToast();
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files?.[0]) {
setFile(e.target.files[0]);
}
};
const handleRemoveFile = () => {
setFile(null);
}
const fileToDataUri = (file: File): Promise<string> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
const handleSendMessage = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if ((!input.trim() && !file) || isLoading) return;
setIsLoading(true);
let fileDataUri: string | undefined = undefined;
let previewUrl: string | undefined = undefined;
if (file) {
previewUrl = URL.createObjectURL(file);
fileDataUri = await fileToDataUri(file);
}
const userMessage: Message = {
id: Date.now().toString(),
role: 'user',
content: input,
imageUrl: previewUrl,
};
setMessages((prev) => [...prev, userMessage]);
const currentInput = input;
setInput('');
setFile(null);
try {
const chatHistory = [...messages, userMessage].map(({ role, content }) => ({ role, content }));
const response = await generateChatbotResponse({
message: currentInput,
chatHistory,
photoDataUri: fileDataUri
});
const assistantMessage: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: response.response,
};
setMessages((prev) => [...prev, assistantMessage]);
} catch (error) {
console.error("Error generating chatbot response:", error);
toast({
variant: "destructive",
title: "Oh no! Something went wrong.",
description: "There was a problem with our AI. Please try again later.",
});
const errorMessage: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: "Sorry, I'm having a little trouble right now. Please try again in a moment.",
};
setMessages((prev) => [...prev, errorMessage]);
} finally {
setIsLoading(false);
// Clean up the object URL
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
}
}
};
return (
<div className="flex h-screen w-full flex-col">
<header className="flex h-16 shrink-0 items-center justify-between border-b bg-background px-4">
<div className="flex items-center gap-2">
<Bot className="h-6 w-6 text-primary" />
<h1 className="text-lg font-semibold">ChhattisVani</h1>
<span className="text-xs text-muted-foreground">29.05.02 beta</span>
</div>
<ThemeToggle />
</header>
<div className="flex-1 overflow-hidden">
<MessageList messages={messages} isLoading={isLoading} />
</div>
<div className="w-full max-w-3xl mx-auto p-4 shrink-0">
{file && (
<div className="mb-2 p-2 border rounded-lg bg-muted flex items-center justify-between animate-slide-in-fade-in">
<div className="flex items-center gap-3">
<Image src={URL.createObjectURL(file)} alt="File preview" width={40} height={40} className="rounded object-cover" />
<span className="text-sm font-medium truncate max-w-xs">{file.name}</span>
</div>
<Button variant="ghost" size="icon" onClick={handleRemoveFile} className="h-7 w-7 shrink-0">
<X className="h-4 w-4" />
</Button>
</div>
)}
<MessageForm
input={input}
setInput={setInput}
handleSendMessage={handleSendMessage}
isLoading={isLoading}
handleFileChange={handleFileChange}
isFileSelected={!!file}
/>
<p className="text-xs text-center text-muted-foreground pt-2">
created with ❤️ by sameer banchhor
</p>
</div>
</div>
);
}
|