import React, { useState, useRef, useEffect, SyntheticEvent } from 'react' import { FaRobot } from 'react-icons/fa'; import { useStoreActions, useStoreState } from '@/store' import { Avatar, Dropdown } from '@/components/ui' import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage' import { useLocalization } from '@/utils/hooks/useLocalization' import { getAi } from '@/services/ai.service' import { AiDto } from '@/proxy/ai/models' import { Container } from '@/components/shared' import { Helmet } from 'react-helmet' // Types type ChatType = 'chat' | 'query' | 'analyze' interface BaseContent { type: ChatType question: string sql: string | null answer: string | any[] chart?: string error?: string } type MessageContent = string | BaseContent interface Message { role: 'user' | 'assistant' content: MessageContent } const isContentObject = (content: MessageContent): content is BaseContent => typeof content !== 'string' && 'type' in content // Main Component const Assistant = () => { // Hooks const { addAiPost } = useStoreActions((actions) => actions.base.messages) const [messages, setMessages] = useState([]) const [input, setInput] = useState('') const [loading, setLoading] = useState(false) const [bot, setBot] = useState<{ key: string; name: string }[]>([]) const [selectedBot, setSelectedBot] = useState(null) const { id, avatar } = useStoreState((state) => state.auth.user) const inputRef = useRef(null) const bottomRef = useRef(null) const { VITE_AI_URL } = import.meta.env const { translate } = useLocalization() const aiPosts = useStoreState((state) => state.base.messages.aiPosts) useEffect(() => { if (messages.length === 0 && aiPosts.length > 0) { setMessages(aiPosts) // artık doğrudan Message[] } }, [aiPosts]) // Botları çek useEffect(() => { const fetchBots = async () => { try { const result = await getAi() const items = result?.data?.items?.map((bot: AiDto) => ({ key: bot.id!, name: bot.botName, })) ?? [] setBot(items) if (items.length > 0) setSelectedBot(items[0].key) } catch (error) { console.error('Bot listesi alınırken hata oluştu:', error) } } fetchBots() }, []) // Scroll to bottom useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages]) // Input focus after loading useEffect(() => { if (!loading) inputRef.current?.focus() }, [loading]) // Bot seçim işlemi const onBotItemClick = (eventKey: string) => setSelectedBot(eventKey) // Gönderme işlemi const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!input.trim()) return const userMessage = input.trim() setInput('') setLoading(true) // 1️⃣ Soruyu store'a ekle addAiPost({ role: 'user', content: userMessage }) setMessages((prev) => [...prev, { role: 'user', content: userMessage }]) try { const response = await fetch(VITE_AI_URL + selectedBot, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ biletId: crypto.randomUUID(), question: userMessage, sessionId: id, }), }) const data = await response.json() const raw = Array.isArray(data) ? data[0] : data const mapped: BaseContent = { ...raw, result: raw.result || raw.answer || raw.error || 'Sonuç bulunamadı.', } // 2️⃣ Cevabı store'a ekle const formattedAnswer = typeof mapped.answer === 'string' ? mapped.answer : JSON.stringify(mapped.answer) addAiPost({ role: 'assistant', content: mapped }) // mapped bir BaseContent setMessages((prev) => [...prev, { role: 'assistant', content: mapped }]) } catch { const errorMessage = 'Üzgünüm, bir hata oluştu. Lütfen tekrar deneyin.' addAiPost({ role: 'assistant', content: errorMessage }) setMessages((prev) => [ ...prev, { role: 'assistant', content: errorMessage, }, ]) } setLoading(false) } // Mesaj içeriği render const renderMessageContent = (message: Message) => { if (message.role === 'assistant' && isContentObject(message.content)) { const { type, sql, answer, chart, error } = message.content as BaseContent & { error?: string } const typeStyles: Record = { chat: 'bg-blue-100 text-blue-700', query: 'bg-green-100 text-green-700', analyze: 'bg-yellow-100 text-yellow-800', } const typeLabels: Record = { chat: '🗨️ ' + translate('::AI.SohbetAnswer'), query: '📊 ' + translate('::AI.DatabaseAnswer'), analyze: '📈 ' + translate('::AI.AnalizAnswer'), } const cleanedSql = (() => { try { const rawSql = decodeURIComponent(sql || '') return rawSql.replace(/^```sql\n?/, '').replace(/```$/, '') } catch { return sql } })() return (
{typeLabels[type] || type}
{sql && (
                {cleanedSql}
              
)} {error ? (
⚠️ Hata: {error}
) : typeof answer === 'string' ? (
{answer}
) : Array.isArray(answer) ? ( answer.length === 0 ? (
Sonuç bulunamadı.
) : (
{Object.keys(answer[0]).map((col) => ( ))} {answer.map((row, rowIndex) => ( {Object.keys(row).map((col, colIndex) => { const val = row[col] const display = val === null || val === undefined ? '—' : typeof val === 'boolean' ? val ? 'Evet' : 'Hayır' : typeof val === 'string' && val.endsWith('T00:00:00.000Z') ? new Date(val).toLocaleDateString('tr-TR') : String(val) return ( ) })} ))}
{col}
{display}
) ) : typeof answer === 'object' && answer !== null && (answer as any).message ? (
{String((answer as any).message)}
) : (
              {JSON.stringify(answer, null, 2)}
            
)} {chart && (
Grafik
)}
) } return
{String(message.content)}
} // Render return (
{messages.length === 0 && (

{translate('::AI.Welcome')}

{translate('::AI.Name')}

)} {messages.map((msg, idx) => (
{msg.role === 'user' ? ( ) : ( )}
{renderMessageContent(msg)}
))} {loading && (
{translate('::AI.WaitAnswer')}
)}