From 329015dadd9edad07c24231222bb3958098e8aec Mon Sep 17 00:00:00 2001 From: "$@#il" Date: Tue, 4 Mar 2025 23:40:08 +0530 Subject: [PATCH] prod:added ui for ai reasoning and logs --- .../chatAssistance/ChaatInterface.jsx | 90 ++++--- .../chatAssistance/StreamingText.jsx | 80 ++++++ .../chatAssistance/TypingAnimation.jsx | 23 ++ src/components/chatAssistance/chat.css | 218 ++++++++++++----- src/components/deployment/AIAnalysis.jsx | 65 +++++ src/components/deployment/LogTerminal.jsx | 39 +++ src/components/pages/DeploymentProgress.jsx | 229 +++++++++--------- 7 files changed, 546 insertions(+), 198 deletions(-) create mode 100644 src/components/chatAssistance/StreamingText.jsx create mode 100644 src/components/chatAssistance/TypingAnimation.jsx create mode 100644 src/components/deployment/AIAnalysis.jsx create mode 100644 src/components/deployment/LogTerminal.jsx diff --git a/src/components/chatAssistance/ChaatInterface.jsx b/src/components/chatAssistance/ChaatInterface.jsx index 74c6350..2d78a3a 100644 --- a/src/components/chatAssistance/ChaatInterface.jsx +++ b/src/components/chatAssistance/ChaatInterface.jsx @@ -8,11 +8,13 @@ import { PaperPlaneIcon, Cross2Icon } from '@radix-ui/react-icons'; import { cn } from '@/lib/utils'; import spiderIcon from '../../assets/spider.png'; import './chat.css'; +import { TypingAnimation } from './TypingAnimation'; +import { StreamingText } from './StreamingText'; export const ChatInterface = ({ triggerAnimation }) => { // Add API base URL from environment variable const API_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000'; - + const [isOpen, setIsOpen] = useState(false); const [inputMessage, setInputMessage] = useState(''); const [userId, setUserId] = useState(null); @@ -55,76 +57,104 @@ export const ChatInterface = ({ triggerAnimation }) => { const newMessages = [...messages, { text: inputMessage, isBot: false }]; setMessages(newMessages); setInputMessage(''); - - if (inputMessage.toLowerCase().includes('jump')) { - triggerAnimation('jump'); - } + setBotThinking(true); // Show bot is thinking try { + // Show typing animation while waiting for response + setIsTyping(true); const response = await fetch(`${API_URL}/api/llm/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: inputMessage, userId }) }); - const data = await response.json(); setMessages([...newMessages, { text: data.reply, isBot: true }]); } catch (error) { setMessages([...newMessages, { text: "Oops! Something went wrong. 😵", isBot: true }]); + } finally { + setIsTyping(false); + setBotThinking(false); } - - setIsTyping(false); }; - return ( -
+
{isOpen ? ( - - + +
-
- +
+ SP
-

Spider-Assist

-

{isTyping ? 'Weaving response...' : 'Ready to assist'}

+

Spider-Assist

+

+ {isTyping ? 'Weaving response...' : botThinking ? 'Processing...' : 'Ready to assist'} +

-
- - - -
+ + + +
{messages.map((msg, i) => (
-
{msg.text} +
+ {msg.isBot ? ( + + ) : ( + msg.text + )}
))} + {botThinking && ( +
+ +
+ )}
- - + +
{ e.preventDefault(); handleSend(); }} className="flex w-full gap-2"> - -
) : ( - )}
diff --git a/src/components/chatAssistance/StreamingText.jsx b/src/components/chatAssistance/StreamingText.jsx new file mode 100644 index 0000000..476d91b --- /dev/null +++ b/src/components/chatAssistance/StreamingText.jsx @@ -0,0 +1,80 @@ +import { motion, AnimatePresence } from "framer-motion"; +import { useState, useEffect } from "react"; + +export const StreamingText = ({ text, onComplete }) => { + const [displayedText, setDisplayedText] = useState(""); + const [currentIndex, setCurrentIndex] = useState(0); + + useEffect(() => { + if (currentIndex < text.length) { + const timer = setTimeout(() => { + setDisplayedText(prev => prev + text[currentIndex]); + setCurrentIndex(currentIndex + 1); + }, 50); // Slightly faster typing speed + + return () => clearTimeout(timer); + } else { + onComplete?.(); + } + }, [currentIndex, text]); + + return ( +
+
+ + {displayedText.split(" ").map((word, idx) => ( + + + {word} + + + + + ))} + + {currentIndex < text.length && ( + + )} +
+
+ +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/chatAssistance/TypingAnimation.jsx b/src/components/chatAssistance/TypingAnimation.jsx new file mode 100644 index 0000000..8f12912 --- /dev/null +++ b/src/components/chatAssistance/TypingAnimation.jsx @@ -0,0 +1,23 @@ +import { motion } from "framer-motion"; + +export const TypingAnimation = () => { + return ( +
+ + + +
+ ); +}; \ No newline at end of file diff --git a/src/components/chatAssistance/chat.css b/src/components/chatAssistance/chat.css index 1881d36..bccbfcc 100644 --- a/src/components/chatAssistance/chat.css +++ b/src/components/chatAssistance/chat.css @@ -1,20 +1,37 @@ /* Modern Chat Interface Styling */ /* Chat Icon Animation */ @keyframes float { - 0%, 100% { + + 0%, + 100% { transform: translateY(0); box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.4); } - 50% { + + 50% { transform: translateY(-8px); box-shadow: 0 20px 25px -5px rgba(59, 130, 246, 0.2); } } +@keyframes wave { + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } +} + +.animate-wave { + animation: wave 2s linear infinite; +} + /* Chat Icon Glow */ .chat-icon-button { background: linear-gradient(135deg, #2563eb, #1d4ed8); - box-shadow: + box-shadow: 0 0 20px 2px rgba(37, 99, 235, 0.3), 0 0 0 2px rgba(37, 99, 235, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.1); @@ -23,7 +40,7 @@ .chat-icon-button:hover { background: linear-gradient(135deg, #3b82f6, #2563eb); - box-shadow: + box-shadow: 0 0 30px 4px rgba(37, 99, 235, 0.4), 0 0 0 2px rgba(37, 99, 235, 0.2), inset 0 0 0 1px rgba(255, 255, 255, 0.2); @@ -36,23 +53,40 @@ /* Add this to your existing animations */ @keyframes typing { - 0%, 100% { transform: scale(0.8) translateY(0); } - 50% { transform: scale(1.2) translateY(-2px); } + + 0%, + 100% { + transform: scale(0.8) translateY(0); + } + + 50% { + transform: scale(1.2) translateY(-2px); + } } + .pulse-border { animation: pulseBorder 2s infinite; } @keyframes pulseBorder { - 0% { border-color: rgba(59, 130, 246, 0.1); } - 50% { border-color: rgba(59, 130, 246, 0.3); } - 100% { border-color: rgba(59, 130, 246, 0.1); } + 0% { + border-color: rgba(59, 130, 246, 0.1); + } + + 50% { + border-color: rgba(59, 130, 246, 0.3); + } + + 100% { + border-color: rgba(59, 130, 246, 0.1); + } } .glass-morphism { background: rgba(15, 23, 42, 0.8); backdrop-filter: blur(12px); } + .typing-dot { @apply h-2.5 w-2.5 bg-indigo-400 rounded-full; animation: typing 1.2s ease-in-out infinite; @@ -70,16 +104,14 @@ } .chat-message-bot { - @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 - before:rounded-bl-2xl before:bg-indigo-900/40; + @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 before:rounded-bl-2xl before:bg-indigo-900/40; backdrop-filter: blur(12px); box-shadow: 0 4px 15px -3px rgba(99, 102, 241, 0.1); border: 1px solid rgba(129, 140, 248, 0.1); } .chat-message-user { - @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 - after:rounded-br-2xl after:bg-gradient-to-br after:from-violet-500 after:to-purple-600; + @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 after:rounded-br-2xl after:bg-gradient-to-br after:from-violet-500 after:to-purple-600; backdrop-filter: blur(12px); box-shadow: 0 4px 15px -3px rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.1); @@ -91,6 +123,7 @@ opacity: 0; transform: translateY(20px) scale(0.95) rotate(-1deg); } + 100% { opacity: 1; transform: translateY(0) scale(1) rotate(0); @@ -106,7 +139,7 @@ background: linear-gradient(165deg, rgba(17, 24, 39, 0.95), rgba(15, 23, 42, 0.85)); backdrop-filter: blur(20px); border: 1px solid rgba(99, 102, 241, 0.1); - box-shadow: + box-shadow: 0 8px 32px -4px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255, 255, 255, 0.05); } @@ -128,8 +161,7 @@ } .chat-message-bot { - @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 - before:rounded-bl-2xl before:bg-slate-800/80; + @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 before:rounded-bl-2xl before:bg-slate-800/80; backdrop-filter: blur(12px); background: linear-gradient(to right, rgba(51, 65, 85, 0.3), rgba(71, 85, 105, 0.2)); box-shadow: 0 4px 15px -3px rgba(51, 65, 85, 0.2); @@ -137,17 +169,24 @@ } .chat-message-user { - @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 - after:rounded-br-2xl after:bg-gradient-to-br after:from-blue-600 after:to-indigo-700; + @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 after:rounded-br-2xl after:bg-gradient-to-br after:from-blue-600 after:to-indigo-700; backdrop-filter: blur(12px); background: linear-gradient(to right, rgba(37, 99, 235, 0.9), rgba(79, 70, 229, 0.9)); box-shadow: 0 4px 15px -3px rgba(37, 99, 235, 0.2); border: 1px solid rgba(37, 99, 235, 0.2); } + /* Enhanced animations */ @keyframes float { - 0%, 100% { transform: translateY(0) rotate(0deg); } - 50% { transform: translateY(-10px) rotate(2deg); } + + 0%, + 100% { + transform: translateY(0) rotate(0deg); + } + + 50% { + transform: translateY(-10px) rotate(2deg); + } } .new-message-animation { @@ -155,8 +194,15 @@ } @keyframes glowPulse { - 0%, 100% { box-shadow: 0 0 20px rgba(239, 68, 68, 0.1); } - 50% { box-shadow: 0 0 30px rgba(239, 68, 68, 0.2); } + + 0%, + 100% { + box-shadow: 0 0 20px rgba(239, 68, 68, 0.1); + } + + 50% { + box-shadow: 0 0 30px rgba(239, 68, 68, 0.2); + } } .thinking-animation { @@ -168,18 +214,21 @@ content: ''; position: absolute; inset: 0; - background: linear-gradient( - 90deg, - transparent, - rgba(239, 68, 68, 0.2), - transparent - ); + background: linear-gradient(90deg, + transparent, + rgba(239, 68, 68, 0.2), + transparent); animation: shimmer 1.5s infinite; } @keyframes shimmer { - 0% { transform: translateX(-100%); } - 100% { transform: translateX(100%); } + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } } .typing-dot { @@ -191,27 +240,52 @@ opacity: 0.5; } -.typing-dot:nth-child(2) { animation-delay: 0.2s; } -.typing-dot:nth-child(3) { animation-delay: 0.4s; } +.typing-dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-dot:nth-child(3) { + animation-delay: 0.4s; +} @keyframes typingDot { - 0%, 60%, 100% { transform: translateY(0); opacity: 0.5; } - 30% { transform: translateY(-4px); opacity: 1; } + + 0%, + 60%, + 100% { + transform: translateY(0); + opacity: 0.5; + } + + 30% { + transform: translateY(-4px); + opacity: 1; + } } + .pulse-border { animation: pulseBorder 2s infinite; } @keyframes pulseBorder { - 0% { border-color: rgba(59, 130, 246, 0.1); } - 50% { border-color: rgba(59, 130, 246, 0.3); } - 100% { border-color: rgba(59, 130, 246, 0.1); } + 0% { + border-color: rgba(59, 130, 246, 0.1); + } + + 50% { + border-color: rgba(59, 130, 246, 0.3); + } + + 100% { + border-color: rgba(59, 130, 246, 0.1); + } } .glass-morphism { background: rgba(15, 23, 42, 0.8); backdrop-filter: blur(12px); } + .typing-dot { @apply h-2.5 w-2.5 bg-indigo-400 rounded-full; animation: typing 1.2s ease-in-out infinite; @@ -229,16 +303,14 @@ } .chat-message-bot { - @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 - before:rounded-bl-2xl before:bg-indigo-900/40; + @apply relative before:absolute before:-left-3 before:top-0 before:h-5 before:w-5 before:rounded-bl-2xl before:bg-indigo-900/40; backdrop-filter: blur(12px); box-shadow: 0 4px 15px -3px rgba(99, 102, 241, 0.1); border: 1px solid rgba(129, 140, 248, 0.1); } .chat-message-user { - @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 - after:rounded-br-2xl after:bg-gradient-to-br after:from-violet-500 after:to-purple-600; + @apply relative after:absolute after:-right-3 after:top-0 after:h-5 after:w-5 after:rounded-br-2xl after:bg-gradient-to-br after:from-violet-500 after:to-purple-600; backdrop-filter: blur(12px); box-shadow: 0 4px 15px -3px rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.1); @@ -246,8 +318,15 @@ /* Enhanced animations */ @keyframes float { - 0%, 100% { transform: translateY(0) rotate(0deg); } - 50% { transform: translateY(-10px) rotate(2deg); } + + 0%, + 100% { + transform: translateY(0) rotate(0deg); + } + + 50% { + transform: translateY(-10px) rotate(2deg); + } } .new-message-animation { @@ -255,8 +334,15 @@ } @keyframes glowPulse { - 0%, 100% { box-shadow: 0 0 20px rgba(239, 68, 68, 0.1); } - 50% { box-shadow: 0 0 30px rgba(239, 68, 68, 0.2); } + + 0%, + 100% { + box-shadow: 0 0 20px rgba(239, 68, 68, 0.1); + } + + 50% { + box-shadow: 0 0 30px rgba(239, 68, 68, 0.2); + } } .thinking-animation { @@ -268,18 +354,21 @@ content: ''; position: absolute; inset: 0; - background: linear-gradient( - 90deg, - transparent, - rgba(239, 68, 68, 0.2), - transparent - ); + background: linear-gradient(90deg, + transparent, + rgba(239, 68, 68, 0.2), + transparent); animation: shimmer 1.5s infinite; } @keyframes shimmer { - 0% { transform: translateX(-100%); } - 100% { transform: translateX(100%); } + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } } .typing-dot { @@ -291,10 +380,25 @@ opacity: 0.5; } -.typing-dot:nth-child(2) { animation-delay: 0.2s; } -.typing-dot:nth-child(3) { animation-delay: 0.4s; } +.typing-dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-dot:nth-child(3) { + animation-delay: 0.4s; +} @keyframes typingDot { - 0%, 60%, 100% { transform: translateY(0); opacity: 0.5; } - 30% { transform: translateY(-4px); opacity: 1; } + + 0%, + 60%, + 100% { + transform: translateY(0); + opacity: 0.5; + } + + 30% { + transform: translateY(-4px); + opacity: 1; + } } \ No newline at end of file diff --git a/src/components/deployment/AIAnalysis.jsx b/src/components/deployment/AIAnalysis.jsx new file mode 100644 index 0000000..1389ee0 --- /dev/null +++ b/src/components/deployment/AIAnalysis.jsx @@ -0,0 +1,65 @@ +import { motion } from "framer-motion"; +import { StreamingText } from "../chatAssistance/StreamingText"; + +export const AIAnalysis = ({ logs }) => { + return ( +
+
+
+ +
+
+
+

+ AI Analysis +

+

Real-time deployment insights

+
+
+ +
+
+

Performance Metrics

+ +

Build optimization: 80%

+
+
+

Security Check

+ +

Vulnerability scan: 95% safe

+
+
+ +
+
+

AI Insights

+ + Live Analysis + +
+
+ +
+ +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/components/deployment/LogTerminal.jsx b/src/components/deployment/LogTerminal.jsx new file mode 100644 index 0000000..de87b75 --- /dev/null +++ b/src/components/deployment/LogTerminal.jsx @@ -0,0 +1,39 @@ +import { motion } from "framer-motion"; + +export const LogTerminal = ({ logs }) => { + return ( +
+
+

+ Deployment Logs +

+
+ + LIVE +
+
+ +
+ {logs.map((log, index) => ( + + {log} + + ))} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/pages/DeploymentProgress.jsx b/src/components/pages/DeploymentProgress.jsx index 80dee6d..6374b83 100644 --- a/src/components/pages/DeploymentProgress.jsx +++ b/src/components/pages/DeploymentProgress.jsx @@ -2,9 +2,10 @@ import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { useNavigate, useParams, useLocation } from "react-router-dom"; import "./DeploymentProgress.css"; -import NavBar from "../NavBar"; import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from "recharts"; import axios from "axios"; +import { AIAnalysis } from "../deployment/AIAnalysis"; +import { LogTerminal } from "../deployment/LogTerminal"; const DeploymentProgress = () => { const API_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000'; @@ -56,21 +57,21 @@ const DeploymentProgress = () => { useEffect(() => { let lastFetchedTimestamp = null; - + const fetchLogs = async () => { try { const url = lastFetchedTimestamp ? `${API_URL}/getLogs/${id}?since=${lastFetchedTimestamp}` : `${API_URL}/getLogs/${id}`; - + const response = await fetch(url); if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); - + const data = await response.json(); - + if (data.logs?.length) { lastFetchedTimestamp = data.logs[data.logs.length - 1].created_at; // Track last log timestamp - + setLogs((prevLogs) => { const newLogs = data.logs.map( (log) => @@ -81,18 +82,18 @@ const DeploymentProgress = () => { return Array.from(new Set([...prevLogs, ...newLogs])); }); } - + setProgress(data.progress || progress); setDeploymentStats(data.stats || deploymentStats); } catch (error) { console.error("Error fetching logs:", error.message); } }; - + const interval = setInterval(fetchLogs, 2000); return () => clearInterval(interval); }, [id]); - + const handleCancel = () => { setIsDeploying(false); @@ -100,132 +101,138 @@ const DeploymentProgress = () => { }; return (
- {/* Background Effects */} -
-
-
-
+ {/* Background Effects */} +
+
+
+
+
+ +
+
+

+ Deployment Progress +

+

Live deployment logs and real-time analytics

-
-
-

- Deployment Progress -

-

Live deployment logs and real-time analytics

-
- -
- {["Total Deployments", "Success Rate", "Failure Rate"].map((label, index) => ( -
+ {["Total Deployments", "Success Rate", "Failure Rate"].map((label, index) => ( +
-

{label}

-
- - - - {COLORS.map((color, idx) => ( - - ))} - - - - -
-
- ))} +
+ + + + {COLORS.map((color, idx) => ( + + ))} + + + + +
+ ))} +
-
-
+
-
-

+

Deployment Logs

- LIVE -
-
- {logs.map((log, index) => ( -
- {log} -
- ))} -
-
- -
-
-
+
+ {logs.map((log, index) => ( +
+ {log}
+ ))}
+
+
+ +
+
+
+
+
+ + {/* //logs anf ai Analysis */} +
+ + +
-
- {isDeploying ? ( - <> - - + - - ) : ( - + + ) : ( + - )} -
+ Go Back Home + + )} +
-
- {["/assects/images/photoShowcase.png", "/assects/images/showCase.png"].map((img, idx) => ( -
+ {["/assects/images/photoShowcase.png", "/assects/images/showCase.png"].map((img, idx) => ( +
- Showcase -

- {idx === 0 ? "🚀 Try Our Cloud Services!" : "🔒 Secure Your Applications!"} -

-

- {idx === 0 - ? "Experience seamless deployments. Sign up now for 20% off!" - : "Ensure your applications stay secure. Learn more."} -

- -
- ))} + {idx === 0 ? "Sign Up" : "Learn More"} +
+ ))}
+
); };