Files

1 line
15 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "chicostate/creativeblock", "files": {"creativeblock/components/ChatBubble.tsx": {"9f62fc94bdff7485668b6770bf6b12db3e5644d3": {"t": 1785746575.774451, "n": 7172, "h": "05f3b7b25f4cbde1", "c": "import React, { useEffect, useState } from 'react';\nimport {\n View,\n Text,\n Modal,\n TouchableOpacity,\n StyleSheet,\n TextInput,\n FlatList,\n ActivityIndicator,\n Alert,\n} from 'react-native';\nimport { ThemedView } from './ThemedView';\nimport { ThemedText } from './ThemedText';\n\ntype ChatUser = {\n _id: number;\n name: string;\n avatar?: string;\n};\n\ntype IMessage = {\n _id: number;\n text: string;\n createdAt: Date;\n user: ChatUser;\n};\n\nconst BOT: ChatUser = {\n _id: 0,\n name: 'DeepSeek',\n avatar: 'https://cdn.deepseek.com/platform/favicon.png',\n};\n\nconst YOU: ChatUser = {\n _id: 1,\n name: 'You',\n};\n\nconst DEEPSEEK_API_URL =\n 'https://api.deepseek.com/v1/chat/completions'; // baseURL + route\nconst DEEPSEEK_API_KEY = 'sk-2f8bbae12ec14d6a9f1b442d9427b7ed'; // ← secure in .env for prod\n\nexport default function ChatBubble() {\n const [visible, setVisible] = useState(false);\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [inputText, setInputText] = useState('');\n const [loading, setLoading] = useState(false);\n\n // initial “welcome” message\n useEffect(() => {\n setMessages([\n {\n _id: Date.now(),\n text: 'Type your question or share what’s on your mind…',\n createdAt: new Date(),\n user: BOT,\n },\n ]);\n }, []);\n\n /* ------------------------------------------------------------------ */\n /* SEND TO DEEPSEEK */\n /* ------------------------------------------------------------------ */\n const sendMessageToDeepSeek = async (userMsg: IMessage) => {\n setLoading(true);\n\n try {\n const res = await fetch(DEEPSEEK_API_URL, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model: 'deepseek-chat', // or 'deepseek-reasoner'\n messages: [{ role: 'user', content: userMsg.text }],\n }),\n });\n\n if (!res.ok) {\n const errTxt = await res.text();\n throw new Error(\n `DeepSeek error (${res.status}): ${errTxt.slice(0, 200)}…`,\n );\n }\n\n const data = await res.json();\n const aiText =\n data.choices?.[0]?.message?.content?.trim() ||\n '🤖 (no response from DeepSeek)';\n\n const aiMessage: IMessage = {\n _id: Date.now() + 1,\n text: aiText,\n createdAt: new Date(),\n user: BOT,\n };\n\n setMessages(prev => [aiMessage, ...prev]);\n } catch (err: any) {\n console.error('DeepSeek API Error:', err);\n Alert.alert('DeepSeek Error', err.message);\n } finally {\n setLoading(false);\n }\n };\n\n /* ------------------------------------------------------------------ */\n /* UI LOGIC */\n /* ------------------------------------------------------------------ */\n const handleSend = () => {\n const trimmed = inputText.trim();\n if (!trimmed) return;\n\n const userMessage: IMessage = {\n _id: Date.now(),\n text: trimmed,\n createdAt: new Date(),\n user: YOU,\n };\n\n // add user msg locally\n setMessages(prev => [userMessage, ...prev]);\n setInputText('');\n\n // fire off to deepseek\n sendMessageToDeepSeek(userMessage);\n };\n\n return (\n <>\n {/* floating FAB */}\n <TouchableOpacity style={styles.fab} onPress={() => setVisible(true)}>\n <Text style={styles.fabText}>Chat</Text>\n </TouchableOpacity>\n\n {/* modal */}\n <Modal\n visible={visible}\n transparent\n animationType=\"slide\"\n onRequestClose={() => setVisible(false)}\n >\n <View style={styles.modalContainer}>\n <ThemedView style={styles.chatContainer}>\n <ThemedText type=\"title\" style={styles.chatTitle}>\n DeepSeek Chat\n </ThemedText>\n\n {loading && (\n <ActivityIndicator style={{ marginBottom: 6 }} size=\"small\" />\n )}\n\n <FlatList\n inverted\n data={messages}\n keyExtractor={item => item._id.toString()}\n renderItem={({ item }) => {\n const isUser = item.user._id === YOU._id;\n return (\n <View\n style={[\n styles.messageBubble,\n isUser ? styles.userBubble : styles.botBubble,\n ]}\n >\n <ThemedText style={styles.messageText}>\n {item.text}\n </ThemedText>\n </View>\n );\n }}\n style={styles.messagesList}\n />\n\n {/* input */}\n <View style={styles.inputRow}>\n <TextInput\n value={inputText}\n onChangeText={setInputText}\n placeholder=\"Type your question...\"\n style={styles.input}\n editable={!loading}\n />\n <TouchableOpacity\n onPress={handleSend}\n style={styles.sendButton}\n disabled={loading}\n >\n <Text style={styles.sendButtonText}>Send</Text>\n </TouchableOpacity>\n </View>\n\n <TouchableOpacity\n onPress={() => setVisible(false)}\n style={styles.closeButton}\n >\n <Text style={styles.closeButtonText}>Close</Text>\n </TouchableOpacity>\n </ThemedView>\n </View>\n </Modal>\n </>\n );\n}\n\n/* ------------------------------ styles ----------------------------- */\nconst styles = StyleSheet.create({\n fab: {\n position: 'absolute',\n bottom: 40,\n right: 20,\n backgroundColor: '#4A90E2',\n borderRadius: 30,\n width: 60,\n height: 60,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: 999,\n },\n fabText: { color: '#fff', fontWeight: 'bold' },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.4)',\n justifyContent: 'center',\n },\n chatContainer: {\n margin: 20,\n borderRadius: 10,\n padding: 15,\n maxHeight: '80%',\n },\n chatTitle: { textAlign: 'center', marginBottom: 6 },\n messagesList: { flexGrow: 0, maxHeight: 300, marginBottom: 10 },\n messageBubble: { marginVertical: 4, padding: 10, borderRadius: 8 },\n userBubble: { alignSelf: 'flex-end', backgroundColor: '#add8e6' },\n botBubble: { alignSelf: 'flex-start', backgroundColor: '#d3d3d3' },\n messageText: { fontSize: 16 },\n inputRow: { flexDirection: 'row' },\n input: {\n flex: 1,\n borderWidth: 1,\n borderColor: '#888',\n borderRadius: 6,\n paddingHorizontal: 8,\n marginRight: 8,\n },\n sendButton: {\n backgroundColor: '#4A90E2',\n borderRadius: 6,\n paddingHorizontal: 16,\n justifyContent: 'center',\n },\n sendButtonText: { color: '#fff', fontWeight: 'bold' },\n closeButton: {\n marginTop: 10,\n backgroundColor: 'red',\n borderRadius: 6,\n alignItems: 'center',\n paddingVertical: 8,\n },\n closeButtonText: { color: '#fff', fontWeight: 'bold' },\n});\n\n"}, "d2d788efe41831bc4631fccac0e4e68a64b08632": {"t": 1785765894.3495014, "n": 7172, "h": "05f3b7b25f4cbde1", "c": "import React, { useEffect, useState } from 'react';\nimport {\n View,\n Text,\n Modal,\n TouchableOpacity,\n StyleSheet,\n TextInput,\n FlatList,\n ActivityIndicator,\n Alert,\n} from 'react-native';\nimport { ThemedView } from './ThemedView';\nimport { ThemedText } from './ThemedText';\n\ntype ChatUser = {\n _id: number;\n name: string;\n avatar?: string;\n};\n\ntype IMessage = {\n _id: number;\n text: string;\n createdAt: Date;\n user: ChatUser;\n};\n\nconst BOT: ChatUser = {\n _id: 0,\n name: 'DeepSeek',\n avatar: 'https://cdn.deepseek.com/platform/favicon.png',\n};\n\nconst YOU: ChatUser = {\n _id: 1,\n name: 'You',\n};\n\nconst DEEPSEEK_API_URL =\n 'https://api.deepseek.com/v1/chat/completions'; // baseURL + route\nconst DEEPSEEK_API_KEY = 'sk-2f8bbae12ec14d6a9f1b442d9427b7ed'; // ← secure in .env for prod\n\nexport default function ChatBubble() {\n const [visible, setVisible] = useState(false);\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [inputText, setInputText] = useState('');\n const [loading, setLoading] = useState(false);\n\n // initial “welcome” message\n useEffect(() => {\n setMessages([\n {\n _id: Date.now(),\n text: 'Type your question or share what’s on your mind…',\n createdAt: new Date(),\n user: BOT,\n },\n ]);\n }, []);\n\n /* ------------------------------------------------------------------ */\n /* SEND TO DEEPSEEK */\n /* ------------------------------------------------------------------ */\n const sendMessageToDeepSeek = async (userMsg: IMessage) => {\n setLoading(true);\n\n try {\n const res = await fetch(DEEPSEEK_API_URL, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model: 'deepseek-chat', // or 'deepseek-reasoner'\n messages: [{ role: 'user', content: userMsg.text }],\n }),\n });\n\n if (!res.ok) {\n const errTxt = await res.text();\n throw new Error(\n `DeepSeek error (${res.status}): ${errTxt.slice(0, 200)}…`,\n );\n }\n\n const data = await res.json();\n const aiText =\n data.choices?.[0]?.message?.content?.trim() ||\n '🤖 (no response from DeepSeek)';\n\n const aiMessage: IMessage = {\n _id: Date.now() + 1,\n text: aiText,\n createdAt: new Date(),\n user: BOT,\n };\n\n setMessages(prev => [aiMessage, ...prev]);\n } catch (err: any) {\n console.error('DeepSeek API Error:', err);\n Alert.alert('DeepSeek Error', err.message);\n } finally {\n setLoading(false);\n }\n };\n\n /* ------------------------------------------------------------------ */\n /* UI LOGIC */\n /* ------------------------------------------------------------------ */\n const handleSend = () => {\n const trimmed = inputText.trim();\n if (!trimmed) return;\n\n const userMessage: IMessage = {\n _id: Date.now(),\n text: trimmed,\n createdAt: new Date(),\n user: YOU,\n };\n\n // add user msg locally\n setMessages(prev => [userMessage, ...prev]);\n setInputText('');\n\n // fire off to deepseek\n sendMessageToDeepSeek(userMessage);\n };\n\n return (\n <>\n {/* floating FAB */}\n <TouchableOpacity style={styles.fab} onPress={() => setVisible(true)}>\n <Text style={styles.fabText}>Chat</Text>\n </TouchableOpacity>\n\n {/* modal */}\n <Modal\n visible={visible}\n transparent\n animationType=\"slide\"\n onRequestClose={() => setVisible(false)}\n >\n <View style={styles.modalContainer}>\n <ThemedView style={styles.chatContainer}>\n <ThemedText type=\"title\" style={styles.chatTitle}>\n DeepSeek Chat\n </ThemedText>\n\n {loading && (\n <ActivityIndicator style={{ marginBottom: 6 }} size=\"small\" />\n )}\n\n <FlatList\n inverted\n data={messages}\n keyExtractor={item => item._id.toString()}\n renderItem={({ item }) => {\n const isUser = item.user._id === YOU._id;\n return (\n <View\n style={[\n styles.messageBubble,\n isUser ? styles.userBubble : styles.botBubble,\n ]}\n >\n <ThemedText style={styles.messageText}>\n {item.text}\n </ThemedText>\n </View>\n );\n }}\n style={styles.messagesList}\n />\n\n {/* input */}\n <View style={styles.inputRow}>\n <TextInput\n value={inputText}\n onChangeText={setInputText}\n placeholder=\"Type your question...\"\n style={styles.input}\n editable={!loading}\n />\n <TouchableOpacity\n onPress={handleSend}\n style={styles.sendButton}\n disabled={loading}\n >\n <Text style={styles.sendButtonText}>Send</Text>\n </TouchableOpacity>\n </View>\n\n <TouchableOpacity\n onPress={() => setVisible(false)}\n style={styles.closeButton}\n >\n <Text style={styles.closeButtonText}>Close</Text>\n </TouchableOpacity>\n </ThemedView>\n </View>\n </Modal>\n </>\n );\n}\n\n/* ------------------------------ styles ----------------------------- */\nconst styles = StyleSheet.create({\n fab: {\n position: 'absolute',\n bottom: 40,\n right: 20,\n backgroundColor: '#4A90E2',\n borderRadius: 30,\n width: 60,\n height: 60,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: 999,\n },\n fabText: { color: '#fff', fontWeight: 'bold' },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.4)',\n justifyContent: 'center',\n },\n chatContainer: {\n margin: 20,\n borderRadius: 10,\n padding: 15,\n maxHeight: '80%',\n },\n chatTitle: { textAlign: 'center', marginBottom: 6 },\n messagesList: { flexGrow: 0, maxHeight: 300, marginBottom: 10 },\n messageBubble: { marginVertical: 4, padding: 10, borderRadius: 8 },\n userBubble: { alignSelf: 'flex-end', backgroundColor: '#add8e6' },\n botBubble: { alignSelf: 'flex-start', backgroundColor: '#d3d3d3' },\n messageText: { fontSize: 16 },\n inputRow: { flexDirection: 'row' },\n input: {\n flex: 1,\n borderWidth: 1,\n borderColor: '#888',\n borderRadius: 6,\n paddingHorizontal: 8,\n marginRight: 8,\n },\n sendButton: {\n backgroundColor: '#4A90E2',\n borderRadius: 6,\n paddingHorizontal: 16,\n justifyContent: 'center',\n },\n sendButtonText: { color: '#fff', fontWeight: 'bold' },\n closeButton: {\n marginTop: 10,\n backgroundColor: 'red',\n borderRadius: 6,\n alignItems: 'center',\n paddingVertical: 8,\n },\n closeButtonText: { color: '#fff', fontWeight: 'bold' },\n});\n\n"}}}}