CoolFace
Apppublic

FriendlyMM/Genset-Maintenance-Assistant

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
ChatInterface.tsx199 linesDownload Raw Back to components
1import React, { useRef, useEffect } from 'react';2import { Send, Bot, User, AlertTriangle, Loader2 } from 'lucide-react';3import ReactMarkdown from 'react-markdown';4import { Message, Language } from '../types';5 6interface ChatInterfaceProps {7  messages: Message[];8  inputValue: string;9  setInputValue: (val: string) => void;10  isLoading: boolean;11  onSend: (text?: string) => void;12  hasData: boolean;13  onOpenSidebar: () => void;14  language: Language;15}16 17const QUICK_ACTIONS_EN = [18  "Oil Change Interval",19  "Valve Lash Adjustment Interval",20  "Major Overhaul Interval",21  "Coolant Change Interval",22  "Next Maintenance Service",23  "Recommended Load Factor",24  "Contact Information"25];26 27const QUICK_ACTIONS_MM = [28  "အင်ဂျင်ဝိုင် လဲလှယ်ရန် သတ်မှတ်ချိန်",29  "Valve Lash ချိန်ညှိရန် သတ်မှတ်ချိန်",30  "Major Overhaul ပြုလုပ်ရန်အချိန်",31  "Coolant လဲလှယ်ရန် သတ်မှတ်ချိန်",32  "နောက်ထပ် ပြုလုပ်ရမည့် Maintenance",33  "သတ်မှတ် Load Factor",34  "ဆက်သွယ်ရန် လိပ်စာ"35];36 37export const ChatInterface: React.FC<ChatInterfaceProps> = ({38  messages,39  inputValue,40  setInputValue,41  isLoading,42  onSend,43  hasData,44  onOpenSidebar,45  language46}) => {47  const messagesEndRef = useRef<HTMLDivElement>(null);48 49  const scrollToBottom = () => {50    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });51  };52 53  useEffect(() => {54    scrollToBottom();55  }, [messages]);56 57  const handleKeyDown = (e: React.KeyboardEvent) => {58    if (e.key === 'Enter' && !e.shiftKey) {59      e.preventDefault();60      onSend();61    }62  };63 64  const quickActions = language === 'mm' ? QUICK_ACTIONS_MM : QUICK_ACTIONS_EN;65  const placeholderText = language === 'mm' 66    ? (!hasData ? "ကျေးဇူးပြု၍ Schedule CSV ဖိုင် အရင်တင်ပါ..." : "ပြုပြင်ထိန်းသိမ်းမှုနှင့် ပတ်သက်၍ မေးမြန်းနိုင်ပါသည်...")67    : (!hasData ? "Upload schedule first..." : "Ask a question...");68  const missingDataText = language === 'mm' ? "အချက်အလက် မရှိပါ" : "Data missing";69 70  return (71    <div className="flex-1 flex flex-col h-full bg-industrial-950 relative w-full">72      {/* Mobile Sidebar Toggle - Only visible when sidebar is hidden on small screens */}73      <div className="lg:hidden p-4 bg-industrial-900 border-b border-industrial-700 flex justify-between items-center shrink-0">74         <h1 className="text-lg font-bold text-white">Genset Assistant</h1>75         <button onClick={onOpenSidebar} className="text-action-500 font-medium text-sm px-2 py-1 hover:bg-industrial-800 rounded">76           Settings77         </button>78      </div>79 80      {/* Messages Area */}81      <div className="flex-1 overflow-y-auto p-4 md:p-6 space-y-6 scroll-smooth">82        {messages.length === 0 && (83          <div className="h-full flex flex-col items-center justify-center text-center opacity-60 p-4">84            <div className="bg-industrial-800 p-6 rounded-full mb-6">85              <Bot className="w-12 h-12 md:w-16 md:h-16 text-action-500" />86            </div>87            <h1 className="text-xl md:text-2xl font-bold text-white mb-2">Maintenance Assistant</h1>88            <p className="text-industrial-400 text-sm md:text-base max-w-md mx-auto">89              {!hasData 90                ? (language === 'mm' ? "ဆက်လက်လုပ်ဆောင်ရန်အတွက် ကျေးဇူးပြု၍ Maintenance Schedule CSV ဖိုင်ကို Settings တွင် Upload ပြုလုပ်ပေးပါ။" : "Please upload your maintenance schedule CSV in the settings to get started.")91                : (language === 'mm' ? "အင်ဂျင်ဝိုင်၊ Overhaul ကာလ သို့မဟုတ် အခြား ပြုပြင်ထိန်းသိမ်းမှုဆိုင်ရာများကို မေးမြန်းနိုင်ပါသည်။" : "Ask me about oil changes, overhaul intervals, or any service requirements for your genset.")}92            </p>93            {!hasData && (94               <button 95                 onClick={onOpenSidebar}96                 className="mt-6 px-6 py-2 bg-action-600 hover:bg-action-500 text-white rounded-md font-medium transition-colors"97               >98                 {language === 'mm' ? "Schedule ဖိုင်တင်မည်" : "Upload Schedule"}99               </button>100            )}101          </div>102        )}103 104        {messages.map((msg) => (105          <div106            key={msg.id}107            className={`flex gap-3 md:gap-4 ${msg.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`}108          >109            <div className={`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${110              msg.role === 'user' ? 'bg-industrial-700' : 'bg-action-600'111            }`}>112              {msg.role === 'user' ? <User className="w-5 h-5 text-white" /> : <Bot className="w-5 h-5 text-white" />}113            </div>114            115            <div className={`flex flex-col max-w-[85%] md:max-w-[75%] ${msg.role === 'user' ? 'items-end' : 'items-start'}`}>116               <div117                className={`px-4 py-3 rounded-2xl text-sm md:text-base leading-relaxed shadow-sm ${118                  msg.role === 'user'119                    ? 'bg-industrial-700 text-white rounded-tr-none'120                    : 'bg-industrial-800 text-industrial-100 rounded-tl-none border border-industrial-700'121                }`}122              >123                {msg.role === 'user' ? (124                  msg.text125                ) : (126                  <div className="prose prose-invert prose-sm md:prose-base max-w-none prose-a:text-action-500 prose-a:no-underline hover:prose-a:underline font-normal">127                     <ReactMarkdown>{msg.text}</ReactMarkdown>128                  </div>129                )}130              </div>131              <span className="text-[10px] md:text-xs text-industrial-500 mt-1 px-1">132                {msg.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}133              </span>134            </div>135          </div>136        ))}137        {isLoading && (138          <div className="flex gap-4">139             <div className="w-8 h-8 rounded-full bg-action-600 flex items-center justify-center flex-shrink-0">140               <Bot className="w-5 h-5 text-white" />141             </div>142             <div className="bg-industrial-800 px-5 py-3 rounded-2xl rounded-tl-none border border-industrial-700 flex items-center">143                <Loader2 className="w-5 h-5 text-action-500 animate-spin mr-2" />144                <span className="text-industrial-400 text-sm">145                  {language === 'mm' ? "ရှာဖွေနေပါသည်..." : "Analyzing schedule..."}146                </span>147             </div>148          </div>149        )}150        <div ref={messagesEndRef} />151      </div>152 153      {/* Input Area */}154      <div className="p-3 md:p-6 bg-industrial-900 border-t border-industrial-800 shrink-0">155        156        {/* Quick Actions */}157        <div className="max-w-4xl mx-auto mb-3 overflow-x-auto flex gap-2 pb-1 px-1 -mx-1 mask-linear-fade scrollbar-hide">158          {quickActions.map((action) => (159            <button160              key={action}161              onClick={() => onSend(action)}162              disabled={isLoading}163              className="flex-shrink-0 px-3 py-1.5 md:px-4 md:py-2 bg-industrial-800 hover:bg-industrial-700 text-industrial-200 text-xs md:text-sm border border-industrial-700 rounded-full transition-colors whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed hover:border-action-500/50"164            >165              {action}166            </button>167          ))}168        </div>169 170        <div className="max-w-4xl mx-auto relative flex items-center">171          <input172            type="text"173            value={inputValue}174            onChange={(e) => setInputValue(e.target.value)}175            onKeyDown={handleKeyDown}176            disabled={isLoading}177            placeholder={placeholderText}178            className="w-full bg-industrial-950 text-white placeholder-industrial-500 border border-industrial-700 rounded-xl py-3 pl-4 pr-12 md:py-4 md:pl-5 md:pr-14 text-base md:text-sm focus:outline-none focus:ring-2 focus:ring-action-500 focus:border-transparent transition-all disabled:opacity-50 disabled:cursor-not-allowed"179          />180          <button181            onClick={() => onSend()}182            disabled={!inputValue.trim() || isLoading}183            className="absolute right-2 md:right-3 p-1.5 md:p-2 bg-action-600 hover:bg-action-500 text-white rounded-lg transition-colors disabled:opacity-50 disabled:bg-industrial-700"184          >185            <Send className="w-5 h-5" />186          </button>187        </div>188        {!hasData && (189          <div className="max-w-4xl mx-auto mt-2 flex justify-center">190             <span className="text-xs text-safety-500 flex items-center gap-1">191                <AlertTriangle className="w-3 h-3" />192                {missingDataText}193             </span>194          </div>195        )}196      </div>197    </div>198  );199};