Ads

import { useState, useRef, useEffect, useCallback } from "react"; // ── Icons ────────────────────────────────────────────────────────────────── const Icon = ({ d, size = 20, className = "" }) => ( ); const Icons = { math: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5", science: "M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 0 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 0-2-2V9m0 0h18", english: "M4 6h16M4 12h16M4 18h7", social: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm14 10v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75", send: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z", image: "M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2zM8.5 13.5l2.5 3 3.5-4.5 4.5 6H5l3.5-4.5z", camera: "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2zM12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z", copy: "M20 9H11a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-9a2 2 0 0 0-2-2zM5 15H4a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h3a2 2 0 0 0 2-2v-1", download: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3", share: "M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13", history: "M3 3h6M3 8h9M3 13h5M12 17l1-5 4 2-5 3zM22 17l-1-5-4 2 5 3z", settings: "M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z", home: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2zM9 22V12h6v10", back: "M19 12H5M12 19l-7-7 7-7", moon: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z", sun: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42M12 5a7 7 0 1 0 0 14A7 7 0 0 0 12 5z", trash: "M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6", star: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z", check: "M20 6L9 17l-5-5", x: "M18 6L6 18M6 6l12 12", user: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z", logout: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9", google: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", book: "M4 19.5A2.5 2.5 0 0 1 6.5 17H20M4 4.5A2.5 2.5 0 0 0 6.5 7H20v13H6.5A2.5 2.5 0 0 1 4 17.5v-13z", sparkle: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z", attach: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48", }; // ── Storage ──────────────────────────────────────────────────────────────── const STORAGE_KEY = "ai_study_helper_v1"; const loadData = () => { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}"); } catch { return {}; } }; const saveData = (data) => { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch {} }; // ── Subjects Config ──────────────────────────────────────────────────────── const SUBJECTS = [ { id: "math", name: "Mathematics", nameHi: "เค—เคฃिเคค", icon: "math", color: "#6366f1", bg: "#eef2ff", darkBg: "#1e1b4b", emoji: "๐Ÿ“", desc: "Algebra, Geometry, Calculus & more", descHi: "เคฌीเคœเค—เคฃिเคค, เคœ्เคฏाเคฎिเคคि, เค•เคฒเคจ เค”เคฐ เค…เคงिเค•" }, { id: "science", name: "Science", nameHi: "เคตिเคœ्เคžाเคจ", icon: "science", color: "#10b981", bg: "#ecfdf5", darkBg: "#064e3b", emoji: "๐Ÿ”ฌ", desc: "Physics, Chemistry, Biology", descHi: "เคญौเคคिเค•ी, เคฐเคธाเคฏเคจ, เคœीเคต เคตिเคœ्เคžाเคจ" }, { id: "english", name: "English", nameHi: "เค…ंเค—्เคฐेเคœ़ी", icon: "english", color: "#f59e0b", bg: "#fffbeb", darkBg: "#451a03", emoji: "๐Ÿ“š", desc: "Grammar, Literature, Writing", descHi: "เคต्เคฏाเค•เคฐเคฃ, เคธाเคนिเคค्เคฏ, เคฒेเค–เคจ" }, { id: "social", name: "Social Studies", nameHi: "เคธाเคฎाเคœिเค• เค…เคง्เคฏเคฏเคจ", icon: "social", color: "#ec4899", bg: "#fdf2f8", darkBg: "#500724", emoji: "๐ŸŒ", desc: "History, Geography, Civics", descHi: "เค‡เคคिเคนाเคธ, เคญूเค—ोเคฒ, เคจाเค—เคฐिเค•เคถाเคธ्เคค्เคฐ" }, ]; // ── API Call ─────────────────────────────────────────────────────────────── async function askAI(subject, question, imageBase64, lang) { const subj = SUBJECTS.find(s => s.id === subject); const langNote = lang === "hi" ? "Reply in Hindi (Devanagari script) with English technical terms where needed." : "Reply in English. You may include Hindi translations for key terms in brackets."; const systemPrompt = `You are an expert ${subj.name} teacher for school and college students. ${langNote} Format your answer with: 1. **Brief Problem Understanding** (1-2 lines) 2. **Step-by-Step Solution** (numbered steps, each explained simply) 3. **Key Concepts Used** (bullet points) 4. **Final Answer** (highlighted clearly) 5. **Pro Tip** (one helpful tip related to this topic) Use simple language. If math, show all calculations. Be encouraging and student-friendly.`; const content = []; if (imageBase64) { content.push({ type: "image", source: { type: "base64", media_type: "image/jpeg", data: imageBase64 } }); content.push({ type: "text", text: question ? `Question from image: ${question}` : "Please read this image, identify the question/problem shown, and solve it step by step." }); } else { content.push({ type: "text", text: question }); } const res = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1000, system: systemPrompt, messages: [{ role: "user", content }], }), }); const data = await res.json(); return data.content?.[0]?.text || "Sorry, could not generate an answer. Please try again."; } // ── Step Colors (cycling) ────────────────────────────────────────────────── const STEP_COLORS = ["#c084fc", "#60a5fa", "#34d399", "#fb923c", "#f472b6", "#a78bfa"]; // ── Inline Bold helper ───────────────────────────────────────────────────── function InlineBold({ text, color }) { const parts = text.split(/\*\*(.*?)\*\*/g); return ( <> {parts.map((p, j) => j % 2 === 1 ? {p} : p )} </> ); } // ── Answer Card Renderer — image-style dark card ─────────────────────────── function renderAnswer(text, dark, subjectColor) { const lines = text.split("\n").filter((l, i, arr) => !(l.trim() === "" && arr[i - 1]?.trim() === "")); const accent = subjectColor || "#a855f7"; let stepCount = 0; return (
{lines.map((line, i) => { const trimmed = line.trim(); if (!trimmed) return
; // ── Section header (## or # or **Header**) if (trimmed.startsWith("## ") || trimmed.startsWith("# ")) { const txt = trimmed.replace(/^#+\s*/, "").replace(/\*\*/g, ""); return (

{txt}

); } // ── Step line: "Step 1:", "Step1:", "1.", numbered const stepMatch = trimmed.match(/^(?:Step\s*(\d+)[:\.]?\s*|(\d+)\.\s+)(.*)$/i); if (stepMatch) { const num = stepMatch[1] || stepMatch[2]; const rest = stepMatch[3]; const color = STEP_COLORS[(parseInt(num) - 1) % STEP_COLORS.length]; stepCount++; return (
Step{num}:
); } // ── Final Answer line if (/^(the\s+)?answer\s+is/i.test(trimmed) || trimmed.toLowerCase().startsWith("final answer") || trimmed.toLowerCase().startsWith("∴") || trimmed.toLowerCase().startsWith("therefore")) { return (
); } // ── Bullet point if (trimmed.startsWith("- ") || trimmed.startsWith("• ")) { return (
); } // ── Bold-only line (section label) if (trimmed.startsWith("**") && trimmed.endsWith("**")) { return (

{trimmed.slice(2, -2)}

); } // ── Pro Tip if (/^(pro\s*tip|tip|note)[:\s]/i.test(trimmed)) { return (
๐Ÿ’ก
); } // ── Default plain text return (

); })}
); } // ── Main App ─────────────────────────────────────────────────────────────── export default function App() { const stored = loadData(); const [page, setPage] = useState("home"); const [subject, setSubject] = useState(null); const [dark, setDark] = useState(stored.dark ?? false); const [lang, setLang] = useState(stored.lang ?? "en"); const [chats, setChats] = useState(stored.chats ?? {}); const [input, setInput] = useState(""); const [loading, setLoading] = useState(false); const [image, setImage] = useState(null); const [imagePreview, setImagePreview] = useState(null); const [user, setUser] = useState(stored.user ?? null); const [copied, setCopied] = useState(null); const [historyFilter, setHistoryFilter] = useState("all"); const [cameraOpen, setCameraOpen] = useState(false); const chatEndRef = useRef(null); const fileRef = useRef(null); const videoRef = useRef(null); const canvasRef = useRef(null); const streamRef = useRef(null); // persist useEffect(() => { saveData({ dark, lang, chats, user }); }, [dark, lang, chats, user]); useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [chats, subject]); const subj = SUBJECTS.find(s => s.id === subject); const subjectChats = subject ? (chats[subject] ?? []) : []; // ── Camera ────────────────────────────────────────────────────────────── const openCamera = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }); streamRef.current = stream; setCameraOpen(true); setTimeout(() => { if (videoRef.current) videoRef.current.srcObject = stream; }, 100); } catch { alert("Camera access denied or not available."); } }; const capturePhoto = () => { const v = videoRef.current, c = canvasRef.current; if (!v || !c) return; c.width = v.videoWidth; c.height = v.videoHeight; c.getContext("2d").drawImage(v, 0, 0); const dataUrl = c.toDataURL("image/jpeg", 0.85); setImagePreview(dataUrl); setImage(dataUrl.split(",")[1]); closeCamera(); }; const closeCamera = () => { streamRef.current?.getTracks().forEach(t => t.stop()); setCameraOpen(false); }; // ── File Upload ────────────────────────────────────────────────────────── const handleFile = (file) => { if (!file) return; const r = new FileReader(); r.onload = (e) => { const base64 = e.target.result.split(",")[1]; setImage(base64); setImagePreview(e.target.result); }; r.readAsDataURL(file); }; // ── Send ───────────────────────────────────────────────────────────────── const send = async () => { if (!input.trim() && !image) return; const q = input.trim(); const imgB64 = image; const imgPrev = imagePreview; setInput(""); setImage(null); setImagePreview(null); setLoading(true); const userMsg = { role: "user", text: q, image: imgPrev, ts: Date.now() }; setChats(prev => ({ ...prev, [subject]: [...(prev[subject] ?? []), userMsg] })); try { const answer = await askAI(subject, q || "Solve this problem from the image", imgB64, lang); const aiMsg = { role: "ai", text: answer, ts: Date.now(), subject }; setChats(prev => ({ ...prev, [subject]: [...(prev[subject] ?? []), aiMsg] })); } catch { const errMsg = { role: "ai", text: "❌ Network error. Please check your connection and try again.", ts: Date.now(), subject }; setChats(prev => ({ ...prev, [subject]: [...(prev[subject] ?? []), errMsg] })); } setLoading(false); }; // ── Copy ───────────────────────────────────────────────────────────────── const copyText = (text, id) => { navigator.clipboard.writeText(text).then(() => { setCopied(id); setTimeout(() => setCopied(null), 2000); }); }; // ── Download ───────────────────────────────────────────────────────────── const downloadAnswer = (msg) => { const blob = new Blob([msg.text], { type: "text/plain" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = `answer-${msg.subject}-${new Date(msg.ts).toLocaleDateString()}.txt`; a.click(); }; // ── Mock Google Login ───────────────────────────────────────────────────── const googleLogin = () => { const mockUser = { name: "Student", email: "student@gmail.com", avatar: "https://ui-avatars.com/api/?name=Student&background=6366f1&color=fff&size=80" }; setUser(mockUser); }; // ── Theme tokens ────────────────────────────────────────────────────────── const t = { bg: dark ? "#0f172a" : "#f8fafc", card: dark ? "#1e293b" : "#ffffff", border: dark ? "#334155" : "#e2e8f0", text: dark ? "#f1f5f9" : "#0f172a", muted: dark ? "#94a3b8" : "#64748b", inputBg: dark ? "#0f172a" : "#f8fafc", navBg: dark ? "#1e293b" : "#ffffff", userBubble: dark ? "#312e81" : "#ede9fe", userText: dark ? "#c7d2fe" : "#3730a3", }; // ──────────────────────────────────────────────────────────────────────── // PAGES // ──────────────────────────────────────────────────────────────────────── // ── HOME ───────────────────────────────────────────────────────────────── const HomePage = () => (
{/* Hero */}
{/* Top bar */}
๐ŸŽ“
StudyAI
{/* Hero text */}

{lang === "hi" ? "AI Study Helper" : "AI Study Helper"}

{lang === "hi" ? "เค•ोเคˆ เคญी เคธเคตाเคฒ เคชूเค›ो — เคคुเคฐंเคค เคœเคตाเคฌ เคชाเค“" : "Ask any question — get instant step-by-step answers"}

{["๐Ÿ“ท Photo", "๐Ÿ–ผ Image", "✍️ Type"].map(t2 => ( {t2} ))}
{/* Stats strip */}
{[["100%", lang === "hi" ? "เคฎुเคซ्เคค" : "Free"], ["4", lang === "hi" ? "เคตिเคทเคฏ" : "Subjects"], ["2", lang === "hi" ? "เคญाเคทा" : "Languages"]].map(([v, l]) => (
{v}
{l}
))}
{/* Choose Subject */}
<
Reviewed by “Manish Kumar Official Links” on June 11, 2026 Rating: 5

Ads

Powered by Blogger.