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>
  );
}