guardia-messenger/app/(tabs)/ai_agent.tsx

112 lines
5.6 KiB
TypeScript

import React, { useState, useCallback } from 'react';
import { View, Text, TextInput, ScrollView, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native';
import { ITSM_BASE } from '../../services/api';
const AGENTS = [
{ id: 'sr-manager', name: 'SR 관리자', icon: '📋', desc: 'SR 접수·분류·배정 자동화' },
{ id: 'incident-responder', name: '인시던트 대응', icon: '🚨', desc: '장애 감지·RCA·복구' },
{ id: 'deploy-engineer', name: '배포 엔지니어', icon: '🚀', desc: 'SSH 배포·롤백·헬스체크' },
{ id: 'ai-analyst', name: 'AI 분석가', icon: '🤖', desc: '이상탐지·예측·인사이트' },
{ id: 'csap-auditor', name: 'CSAP 감사관', icon: '🛡️', desc: 'CSAP 준수율 자동 점검' },
];
interface Message { role: 'user' | 'agent'; content: string; agent?: string; ts: string }
export default function AIAgentScreen() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const [selectedAgent, setSelectedAgent] = useState(AGENTS[0]);
const [loading, setLoading] = useState(false);
const sendMessage = useCallback(async () => {
if (!input.trim()) return;
const userMsg: Message = { role: 'user', content: input, ts: new Date().toISOString() };
setMessages(prev => [...prev, userMsg]);
setInput('');
setLoading(true);
try {
const r = await fetch(`${ITSM_BASE}/api/agent-collab/rooms`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ topic: input, agents: [selectedAgent.id] }),
});
if (r.ok) {
const room = await r.json();
const opinion = await fetch(`${ITSM_BASE}/api/agent-collab/rooms/${room.id}/ai-opinion`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ agent_id: selectedAgent.id }),
});
if (opinion.ok) {
const data = await opinion.json();
setMessages(prev => [...prev, {
role: 'agent', content: data.opinion || data.message || '처리 완료',
agent: selectedAgent.name, ts: new Date().toISOString(),
}]);
}
}
} catch {
setMessages(prev => [...prev, { role: 'agent', content: '[Ollama 처리 중...]', agent: selectedAgent.name, ts: new Date().toISOString() }]);
} finally { setLoading(false); }
}, [input, selectedAgent]);
return (
<View style={s.container}>
<Text style={s.title}>AI </Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false} style={s.agentBar}>
{AGENTS.map(a => (
<TouchableOpacity key={a.id} style={[s.agentChip, selectedAgent.id === a.id && s.agentActive]}
onPress={() => setSelectedAgent(a)}>
<Text style={s.agentIcon}>{a.icon}</Text>
<Text style={[s.agentName, selectedAgent.id === a.id && s.agentNameActive]}>{a.name}</Text>
</TouchableOpacity>
))}
</ScrollView>
<View style={s.agentDesc}><Text style={s.agentDescText}>{selectedAgent.icon} {selectedAgent.desc}</Text></View>
<ScrollView style={s.chat}>
{messages.map((m, i) => (
<View key={i} style={[s.bubble, m.role === 'user' ? s.userBubble : s.agentBubble]}>
{m.role === 'agent' && <Text style={s.agentLabel}>{m.agent}</Text>}
<Text style={s.bubbleText}>{m.content}</Text>
<Text style={s.ts}>{new Date(m.ts).toLocaleTimeString()}</Text>
</View>
))}
{loading && <ActivityIndicator color="#00A0C8" style={{ margin: 12 }} />}
</ScrollView>
<View style={s.inputRow}>
<TextInput style={s.input} value={input} onChangeText={setInput}
placeholder="에이전트에게 질문하세요..." placeholderTextColor="#888"
onSubmitEditing={sendMessage} />
<TouchableOpacity style={s.sendBtn} onPress={sendMessage}>
<Text style={s.sendText}></Text>
</TouchableOpacity>
</View>
</View>
);
}
const s = StyleSheet.create({
container: { flex: 1, backgroundColor: '#0A0E1A' },
title: { color: '#fff', fontSize: 18, fontWeight: '700', padding: 16, paddingBottom: 8 },
agentBar: { paddingHorizontal: 12, paddingVertical: 8, maxHeight: 80 },
agentChip: { alignItems: 'center', marginRight: 12, paddingHorizontal: 12, paddingVertical: 8,
borderRadius: 20, borderWidth: 1, borderColor: '#333', backgroundColor: '#1A1F2E' },
agentActive: { borderColor: '#00A0C8', backgroundColor: '#003366' },
agentIcon: { fontSize: 18 },
agentName: { color: '#aaa', fontSize: 11, marginTop: 2 },
agentNameActive: { color: '#00A0C8' },
agentDesc: { backgroundColor: '#1A1F2E', marginHorizontal: 12, marginBottom: 4, padding: 8, borderRadius: 8 },
agentDescText: { color: '#aaa', fontSize: 12 },
chat: { flex: 1, padding: 12 },
bubble: { maxWidth: '80%', marginBottom: 12, padding: 10, borderRadius: 12 },
userBubble: { alignSelf: 'flex-end', backgroundColor: '#003366' },
agentBubble: { alignSelf: 'flex-start', backgroundColor: '#1A1F2E' },
agentLabel: { color: '#00A0C8', fontSize: 11, fontWeight: '600', marginBottom: 4 },
bubbleText: { color: '#fff', fontSize: 14, lineHeight: 20 },
ts: { color: '#555', fontSize: 10, marginTop: 4, textAlign: 'right' },
inputRow: { flexDirection: 'row', padding: 12, borderTopWidth: 1, borderTopColor: '#222' },
input: { flex: 1, backgroundColor: '#1A1F2E', color: '#fff', borderRadius: 20, paddingHorizontal: 16, marginRight: 8 },
sendBtn: { backgroundColor: '#00A0C8', borderRadius: 20, paddingHorizontal: 16, justifyContent: 'center' },
sendText: { color: '#fff', fontWeight: '700' },
});