| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import React, { useState, useEffect } from 'react'
- import {
- View, Text, TextInput, TouchableOpacity, FlatList,
- StyleSheet, SafeAreaView, StatusBar, ActivityIndicator
- } from 'react-native'
- import { client, Session, Message } from './src/services/api'
- const MODES = ['build', 'plan', 'debug', 'solo'] as const
- type Mode = typeof MODES[number]
- export default function App() {
- const [sessions, setSessions] = useState<Session[]>([])
- const [currentSession, setCurrentSession] = useState<Session | null>(null)
- const [messages, setMessages] = useState<Message[]>([])
- const [inputText, setInputText] = useState('')
- const [mode, setMode] = useState<Mode>('build')
- const [connected, setConnected] = useState(false)
- const [loading, setLoading] = useState(true)
- useEffect(() => {
- checkConnection()
- }, [])
- async function checkConnection() {
- try {
- if (typeof window !== 'undefined') {
- await fetch('http://localhost:4096/global/health')
- }
- setConnected(true)
- } catch { }
- setLoading(false)
- }
- async function createSession() {
- try {
- const s = await client.createSession(`Chat ${new Date().toLocaleTimeString()}`)
- setCurrentSession(s)
- setMessages([])
- } catch (e) {
- console.error(e)
- }
- }
- async function sendMessage() {
- if (!inputText.trim() || !currentSession) return
- const userMsg: Message = {
- id: `u_${Date.now()}`, role: 'user',
- content: inputText, createdAt: new Date().toISOString()
- }
- setMessages(prev => [...prev, userMsg])
- setInputText('')
- try {
- await client.sendPrompt(currentSession.id, inputText, mode)
- const msgs = await client.getMessages(currentSession.id)
- setMessages(msgs)
- } catch (e) {
- console.error(e)
- }
- }
- if (loading) {
- return (
- <View style={styles.center}>
- <ActivityIndicator size="large" color="#e74c3c" />
- <Text style={styles.brand}>K I R I N</Text>
- </View>
- )
- }
- return (
- <SafeAreaView style={styles.container}>
- <StatusBar barStyle="light-content" backgroundColor="#1a1a2e" />
- {/* Mode Tabs */}
- <View style={styles.modeBar}>
- {MODES.map(m => (
- <TouchableOpacity key={m} style={[styles.modeTab, mode === m && styles.modeActive]}
- onPress={() => setMode(m)}>
- <Text style={[styles.modeText, mode === m && styles.modeActiveText]}>{m}</Text>
- </TouchableOpacity>
- ))}
- <Text style={styles.status}>{connected ? '🟢' : '🔴'}</Text>
- </View>
- {/* Chat Area */}
- {!currentSession ? (
- <View style={styles.center}>
- <Text style={styles.logo}>🦄</Text>
- <Text style={styles.brand}>K I R I N</Text>
- <TouchableOpacity style={styles.newChatBtn} onPress={createSession}>
- <Text style={styles.newChatText}>New Chat</Text>
- </TouchableOpacity>
- </View>
- ) : (
- <FlatList
- data={messages}
- keyExtractor={item => item.id}
- style={styles.messageList}
- renderItem={({ item }) => (
- <View style={[styles.bubble, item.role === 'user' ? styles.userBubble : styles.aiBubble]}>
- <Text style={[styles.bubbleText, item.role === 'user' ? styles.userText : styles.aiText]}>
- {item.content}
- </Text>
- </View>
- )}
- />
- )}
- {/* Input Bar */}
- <View style={styles.inputBar}>
- <TextInput
- style={styles.input}
- placeholder="Message..."
- placeholderTextColor="#7f8c8d"
- value={inputText}
- onChangeText={setInputText}
- onSubmitEditing={sendMessage}
- />
- <TouchableOpacity style={styles.sendBtn} onPress={sendMessage}>
- <Text style={styles.sendText}>→</Text>
- </TouchableOpacity>
- </View>
- </SafeAreaView>
- )
- }
- const styles = StyleSheet.create({
- container: { flex: 1, backgroundColor: '#0f172a' },
- center: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#0f172a' },
- logo: { fontSize: 48, opacity: 0.3 },
- brand: { fontSize: 20, fontWeight: '700', color: '#e74c3c', marginTop: 8, letterSpacing: 4 },
- modeBar: { flexDirection: 'row', padding: 8, backgroundColor: '#16213e', alignItems: 'center' },
- modeTab: { paddingHorizontal: 12, paddingVertical: 4, borderRadius: 6, marginRight: 4 },
- modeActive: { backgroundColor: '#e74c3c' },
- modeText: { fontSize: 12, color: '#7f8c8d' },
- modeActiveText: { color: '#fff' },
- status: { fontSize: 10, marginLeft: 'auto' },
- newChatBtn: { marginTop: 16, backgroundColor: '#e74c3c', paddingHorizontal: 24, paddingVertical: 10, borderRadius: 8 },
- newChatText: { color: '#fff', fontWeight: '600' },
- messageList: { flex: 1, padding: 8 },
- bubble: { padding: 10, borderRadius: 8, marginBottom: 6, maxWidth: '85%' },
- userBubble: { alignSelf: 'flex-end', backgroundColor: '#2c3e5033' },
- aiBubble: { alignSelf: 'flex-start', backgroundColor: '#16213e' },
- bubbleText: { fontSize: 14 },
- userText: { color: '#ecf0f1' },
- aiText: { color: '#bdc3c7' },
- inputBar: { flexDirection: 'row', padding: 8, backgroundColor: '#1a1a2e', alignItems: 'center' },
- input: { flex: 1, height: 40, backgroundColor: '#1a1a2e', borderRadius: 8, borderWidth: 1, borderColor: '#2c3e50', paddingHorizontal: 12, color: '#ecf0f1', fontSize: 14 },
- sendBtn: { width: 40, height: 40, backgroundColor: '#e74c3c', borderRadius: 8, justifyContent: 'center', alignItems: 'center', marginLeft: 6 },
- sendText: { color: '#fff', fontSize: 18 },
- })
|