From 1767ec293afff32166bcf9d89c91185723624929 Mon Sep 17 00:00:00 2001 From: NabilThange Date: Fri, 23 May 2025 13:55:15 +0530 Subject: [PATCH 1/4] mobile pe alag | laptp pe alag cards --- README.md | 36 +- app/ar-mode/MobileCarousel.tsx | 55 +++ app/ar-mode/ar-mode-content.tsx | 507 ++++++++++++-------- jsrepo.json | 11 + lib/groq-service.ts | 193 ++++++-- package.json | 3 +- pnpm-lock.yaml | 46 +- src/blocks/Components/Carousel/Carousel.tsx | 275 +++++++++++ src/components/ui/carousel.tsx | 177 +++++++ 9 files changed, 1038 insertions(+), 265 deletions(-) create mode 100644 app/ar-mode/MobileCarousel.tsx create mode 100644 jsrepo.json create mode 100644 src/blocks/Components/Carousel/Carousel.tsx create mode 100644 src/components/ui/carousel.tsx diff --git a/README.md b/README.md index 5f2577e..a340141 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Today's AI assistants are *too slow*, *too basic*, or *too disconnected* from real user needs. **NbAIl** solves this by combining **super-fast text, smooth voice conversation, intelligent command execution, and planned augmented reality (AR) capabilities** — all in a **single multimodal powerhouse**. -One of NbAIl’s proudest innovations: **Command Mode**. +One of NbAIl's proudest innovations: **Command Mode**. Simply type a command like `/open notepad and write hello world`, and our **Terminator Agent**, powered by **Groq** for understanding and **local Python automation**, will **open system apps, type messages, and perform actions** automatically. **Zero manual work. Full smart automation.** Built to behave like a *true futuristic assistant* — not just a chatbot. @@ -68,7 +68,7 @@ Built to behave like a *true futuristic assistant* — not just a chatbot. - ✅ **Multi-mode Switcher** — instantly switch between chat, voice, command, and AR - ✅ **Error Handling & Fail-Safes** — graceful recovery when apps not found -🚀 **NbAIl doesn’t just "chat." It "acts."** +🚀 **NbAIl doesn't just "chat." It "acts."** --- @@ -125,7 +125,7 @@ python terminator_agent.py ```bash ngrok http 8000 -(Replace 5000 with your local port if it’s different.) +(Replace 5000 with your local port if it's different.) ``` — @@ -147,7 +147,7 @@ ngrok http 8000 # 🔮 Future Scope of NbAIl While NbAIl already delivers a futuristic multimodal experience, the journey has just begun! -Here’s what’s planned for future versions: +Here's what's planned for future versions: --- @@ -190,7 +190,7 @@ Here’s what’s planned for future versions: # 📚 Resources / Credits This project would not have been possible without the amazing technologies, APIs, and open-source tools available to the community. -Here’s what powered NbAIl: +Here's what powered NbAIl: --- @@ -254,3 +254,29 @@ Bigger, smarter, and even crazier updates are on the way. > **"The ones who are crazy enough to think they can change the world are the ones who do."** > — Apple, 1997 + +## Environment Variables + +You'll need to set up the following environment variables in your `.env.local` file: + +- `NEXT_PUBLIC_GROQ_API_KEY`: Your Groq API key for AI analysis +- `NEXT_PUBLIC_MISTRAL_API_KEY`: Your Mistral API key for alternative AI analysis (optional) + +### Obtaining API Keys + +1. **Groq API Key**: + - Visit [Groq's website](https://console.groq.com/) + - Create an account and generate an API key + +2. **Mistral API Key**: + - Visit [Mistral's website](https://mistral.ai/) + - Create an account and generate an API key + - Note: We're using the Pixtral 12B 2409 model for AR mode vision analysis + +Example `.env.local` file: +``` +NEXT_PUBLIC_GROQ_API_KEY=your_groq_api_key_here +NEXT_PUBLIC_MISTRAL_API_KEY=your_mistral_api_key_here +``` + +**Note**: Keep your API keys confidential and never commit them to version control. diff --git a/app/ar-mode/MobileCarousel.tsx b/app/ar-mode/MobileCarousel.tsx new file mode 100644 index 0000000..04ee0ef --- /dev/null +++ b/app/ar-mode/MobileCarousel.tsx @@ -0,0 +1,55 @@ +import { AnimatePresence, motion } from "framer-motion"; +import Carousel from "@/src/blocks/Components/Carousel/Carousel"; // Adjusted import path +import { FiLayers, FiCode, FiFileText } from "react-icons/fi"; + +const MobileCarousel = ({ showCards }: { showCards: boolean }) => { + return ( + // Only show on mobile devices (md:hidden) +
+
+ + {showCards && ( + + , + }, + { + title: "Object Detection", + description: "Real-time object and gesture recognition", + id: 2, + icon: , + }, + { + title: "Face Analysis", + description: "Detailed facial recognition and traits", + id: 3, + icon: , + }, + ]} + baseWidth={250} + autoplay={true} + autoplayDelay={3000} + pauseOnHover={true} + loop={true} + round={false} + /> + + )} + +
+
+ ); +}; + +export default MobileCarousel; \ No newline at end of file diff --git a/app/ar-mode/ar-mode-content.tsx b/app/ar-mode/ar-mode-content.tsx index e52ee69..fbe05f4 100644 --- a/app/ar-mode/ar-mode-content.tsx +++ b/app/ar-mode/ar-mode-content.tsx @@ -5,12 +5,14 @@ import { useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { ArrowLeft, Camera, Mic, Loader2, AlertTriangle, Volume2, X, RefreshCw, CircleDot, ArrowRight } from "lucide-react" import { motion, AnimatePresence } from "framer-motion" -// Import the new service function -import { getGroqVisionAnalysis, getGroqTranscription } from "@/lib/groq-service" +// Import the new service function and provider enum +import { getGroqVisionAnalysis, getGroqTranscription, AIProvider } from "@/lib/groq-service" import { speakText } from "@/lib/tts-service" import ReactMarkdown from 'react-markdown' import InfoWidget from '@/components/ar/InfoWidget' import React from 'react' +import Carousel from "@/src/components/ui/carousel" +import { FiLayers, FiCode, FiFileText } from 'react-icons/fi' // THESE IMPORTS ARE LIKELY NEEDED BASED ON LINTER ERRORS - ADDING THEM HERE import * as faceapi from 'face-api.js'; @@ -57,6 +59,7 @@ export default function ARModeContent() { // Renamed from ARModePage const captureIntervalRef = useRef(null); const [recordStartTime, setRecordStartTime] = useState(null); const [isRecording, setIsRecording] = useState(false); + const [aiProvider, setAiProvider] = useState(AIProvider.GROQ); // Face-API model loading options @@ -410,7 +413,7 @@ export default function ARModeContent() { // Renamed from ARModePage } try { - const response = await getGroqVisionAnalysis(imageDataUrl, DETAILED_BASE_PROMPT); + const response = await getGroqVisionAnalysis(imageDataUrl, DETAILED_BASE_PROMPT, aiProvider); setAiResponse(response); console.log("[captureAndAnalyzeFrame] Groq vision analysis complete. Response:", response); } catch (err) { @@ -432,7 +435,8 @@ export default function ARModeContent() { // Renamed from ARModePage setAiResponse, setShowCards, setLastAnalysisTime, - videoRef // videoRef.current is used by analysis helpers + videoRef, + aiProvider ]); // Effect to handle recording logic (timer and periodic capture) @@ -565,7 +569,7 @@ export default function ARModeContent() { // Renamed from ARModePage try { // Using DETAILED_BASE_PROMPT for manual analysis as well - const response = await getGroqVisionAnalysis(imageDataUrl, DETAILED_BASE_PROMPT) + const response = await getGroqVisionAnalysis(imageDataUrl, DETAILED_BASE_PROMPT, aiProvider) setAiResponse(response) } catch (err) { console.error("Error analyzing image with Groq (handleAnalyzeImage):", err); @@ -577,7 +581,7 @@ export default function ARModeContent() { // Renamed from ARModePage setShowCards(true); // Show all cards after analyses are attempted setIsAnalyzing(false); setStatusMessage(null); - }, [modelsReady, mediaPipeModelsReady, captureFrame, DETAILED_BASE_PROMPT, performFaceApiAnalysis, performMediaPipeAnalysis, getGroqVisionAnalysis, setAiResponse, setCapturedImagePreviewUrl, setObjectCardContent, setIdentityInfoContent, setError, setFaceApiError, setMediaPipeError, setShowCards, setStatusMessage, videoRef]); + }, [modelsReady, mediaPipeModelsReady, captureFrame, DETAILED_BASE_PROMPT, performFaceApiAnalysis, performMediaPipeAnalysis, getGroqVisionAnalysis, setAiResponse, setCapturedImagePreviewUrl, setObjectCardContent, setIdentityInfoContent, setError, setFaceApiError, setMediaPipeError, setShowCards, setStatusMessage, videoRef, aiProvider]); // --- Flip Camera --- @@ -778,7 +782,7 @@ export default function ARModeContent() { // Renamed from ARModePage try { // Send the combined prompt to the vision analysis function - const response = await getGroqVisionAnalysis(imageDataUrl, finalPrompt) + const response = await getGroqVisionAnalysis(imageDataUrl, finalPrompt, aiProvider) setAiResponse(response) setStatusMessage("Speaking response...") // Speak the response @@ -813,7 +817,7 @@ export default function ARModeContent() { // Renamed from ARModePage setIsAnalyzing(false); setShowCards(true); // Show cards after all analysis attempts (might be empty if errors) } - }, [captureFrame, modelsReady, mediaPipeModelsReady, DETAILED_BASE_PROMPT, performFaceApiAnalysis, performMediaPipeAnalysis, getGroqVisionAnalysis, speakText, videoRef, setCapturedImagePreviewUrl, setObjectCardContent, setIdentityInfoContent, setAiResponse, setError, setFaceApiError, setMediaPipeError, setShowCards, setStatusMessage, setIsAnalyzing, setIsSpeaking]); + }, [captureFrame, modelsReady, mediaPipeModelsReady, DETAILED_BASE_PROMPT, performFaceApiAnalysis, performMediaPipeAnalysis, getGroqVisionAnalysis, speakText, videoRef, setCapturedImagePreviewUrl, setObjectCardContent, setIdentityInfoContent, setAiResponse, setError, setFaceApiError, setMediaPipeError, setShowCards, setStatusMessage, setIsAnalyzing, setIsSpeaking, aiProvider]); // Main prediction loop and drawing logic useEffect(() => { @@ -861,23 +865,43 @@ export default function ARModeContent() { // Renamed from ARModePage // ... existing code ... }, []); + // Prepare slides data for the new Carousel + const arModeSlides = [ + { + title: "Scene Analysis", + button: "Explore Insights", + description: aiResponse || "Detailed description of the surrounding environment, capturing key visual elements and context.", + }, + { + title: "Identity Card", + button: "View Traits", + src: capturedImagePreviewUrl || "/images/identity-analysis.jpg", + description: identityInfoContent || "Demographic and emotional insights about detected individuals." + }, + { + title: "Object Detection", + button: "Recognize Items", + src: "/images/object-detection.jpg", + description: objectCardContent || "Comprehensive list of detected objects and gestures in the scene." + } + ]; + return ( // Conditional rendering based on isClient is handled by the early return // So, this JSX assumes it's client-side.
{/* Header */}
- -

AR Mode

{/* Recording Timer / Info Widget Container */} +
+
router.push('/chat')} + className="flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white text-xs cursor-pointer hover:bg-white/20 transition-colors" + > + Chats +
+
+
{isRecording && (
@@ -887,11 +911,21 @@ export default function ARModeContent() { // Renamed from ARModePage )} {/* Info Widget with updated styling */}
-
router.push('/chat')} - className="flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white text-xs cursor-pointer hover:bg-white/20 transition-colors" - > - Chats + {/* AI Provider Selector */} +
+ +
+ + + +
@@ -1007,192 +1041,271 @@ export default function ARModeContent() { // Renamed from ARModePage
- {/* Detected Person Card - Top Left */} -
-
- - {showCards && (capturedImagePreviewUrl || identityInfoContent) && ( - - {/* Image Section */} -
-
-

- {capturedImagePreviewUrl ? "Identity Snapshot" : "Detecting..."} -

-
- {capturedImagePreviewUrl && ( - Captured scene - )} -
- - {/* Identity Traits Pills */} - {identityInfoContent && ( -
- {identityInfoContent.split('\n').map((trait, index) => { - const cleanTrait = trait.replace('- ', ''); - let icon = '🤔'; - if (cleanTrait.includes('Age')) icon = '🎂'; - if (cleanTrait.includes('Gender')) icon = '👤'; - if (cleanTrait.includes('Mood')) icon = '😀'; - - return ( -
- {icon} {cleanTrait} -
- ); - })} -
- )} + {/* Responsive Info Cards Container */} +
+ {/* Top Row Elements - Desktop/Tablet */} +
+
router.push('/chat')} + className="flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white text-xs cursor-pointer hover:bg-white/20 transition-colors" + > + Chats +
+
+
+ +
+
+ + {/* Carousel Section - Mobile Only */} +
+
+ + {showCards && ( + + + + )} + +
+
- {!identityInfoContent && ( -
-
- 🤔 No Clear Face Detected + {/* Desktop/Tablet Info Cards - Hidden on Mobile */} +
+ {/* Detected Person Card - Top Left */} +
+
+ + {showCards && (capturedImagePreviewUrl || identityInfoContent) && ( + + {/* Image Section */} +
+
+

+ {capturedImagePreviewUrl ? "Identity Snapshot" : "Detecting..."} +

+ {capturedImagePreviewUrl && ( + Captured scene + )}
- )} - - {/* Footer */} -

- Detected by NbAIl -

-
- )} -
-
-
- {/* Objects & Gestures Card - Bottom Left */} -
-
- - {showCards && objectCardContent && ( - -

Objects & Gestures

- - {objectCardContent && ( - <> -

Detected Objects

-
- {objectCardContent.includes("Detected Objects:") && - objectCardContent.split("\n") - .filter(line => line.trim().startsWith("- ")) - .map((item, index) => ( - - {item.replace("- ", "")} - - )) - } -
+ {/* Identity Traits Pills */} + {identityInfoContent && ( +
+ {identityInfoContent.split('\n').map((trait, index) => { + const cleanTrait = trait.replace('- ', ''); + let icon = '🤔'; + if (cleanTrait.includes('Age')) icon = '🎂'; + if (cleanTrait.includes('Gender')) icon = '👤'; + if (cleanTrait.includes('Mood')) icon = '😀'; + + return ( +
+ {icon} {cleanTrait} +
+ ); + })} +
+ )} -

Detected Gestures

+ {!identityInfoContent && (
- {objectCardContent.includes("Detected Gestures:") && - objectCardContent.split("\n") - .filter(line => line.trim().startsWith("- ") && line.trim() !== "- None") - .map((item, index) => ( - - {item.replace("- ", "")} - - )) - } - {(!objectCardContent.includes("Detected Gestures:") || - objectCardContent.includes("- None")) && ( - - No gestures detected - - )} +
+ 🤔 No Clear Face Detected +
- - )} -
- )} -
-
-
+ )} - {/* Scene Analysis Card - Bottom Right */} -
-
- - {showCards && aiResponse && ( - -
-

Scene Analysis

- {!isRecording && ( - - )} -
-
- {aiResponse && ( - { - // Safely handle children - const processText = (text: string) => - text.split(/\s+/).map((word, wordIndex) => - word.length > 5 - ? {word} - : {word} - ); + {/* Footer */} +

+ Detected by NbAIl +

+ + )} + +
+
+ + {/* Objects & Gestures Card - Bottom Left */} +
+
+ + {showCards && objectCardContent && ( + +

Objects & Gestures

+ + {objectCardContent && ( + <> +

Detected Objects

+
+ {objectCardContent.includes("Detected Objects:") && + objectCardContent.split("\n") + .filter(line => line.trim().startsWith("- ")) + .map((item, index) => ( + + {item.replace("- ", "")} + + )) + } +
- const processChild = (child: React.ReactNode, index: number) => { - if (typeof child === 'string') { - return processText(child); - } - return child; - }; - - return ( -

- {React.Children.map(children, processChild)} -

- ); +

Detected Gestures

+
+ {objectCardContent.includes("Detected Gestures:") && + objectCardContent.split("\n") + .filter(line => line.trim().startsWith("- ") && line.trim() !== "- None") + .map((item, index) => ( + + {item.replace("- ", "")} + + )) } - }} - > - {aiResponse} - + {(!objectCardContent.includes("Detected Gestures:") || + objectCardContent.includes("- None")) && ( + + No gestures detected + + )} +
+ )} -
- - )} - + + )} + +
+
+ + {/* Scene Analysis Card - Bottom Right */} +
+
+ + {showCards && aiResponse && ( + +
+

Scene Analysis

+ {!isRecording && ( + + )} +
+
+ {aiResponse && ( + { + // Safely handle children + const processText = (text: string) => + text.split(/\s+/).map((word, wordIndex) => + word.length > 5 + ? {word} + : {word} + ); + + const processChildren = (children: React.ReactNode) => { + return React.Children.map(children, (child, index) => { + if (typeof child === 'string') { + return processText(child); + } + return child; + }); + }; + + return ( +

+ {processChildren(props.children)} +

+ ); + } + }} + > + {aiResponse} +
+ )} +
+
+ )} +
+
-
+
+ + {/* Header for Mobile */} +
+
+
router.push('/chat')} + className="flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white text-xs cursor-pointer hover:bg-white/20 transition-colors" + > + Chats +
+
+ +
+ {isRecording && ( +
+ + {formatRecordingTime(recordingTime)} +
+ )} +
+ {/* AI Provider Selector */} +
+ +
+ + + +
+
+ +
+
+
{/* Controls */}