import React, { useState, useEffect, useRef, useMemo } from 'react';
import {
Wand2, Layout, Type, UserSquare2, Image as ImageIcon, Eraser, Sparkles,
Layers, Minimize2, Maximize2, Scan, Package, Heart, Video, Mic2,
Settings, LogOut, ChevronRight, Play, Download, Trash2, Send,
Camera, Shirt, Palette, Volume2, Plus, Search, HelpCircle,
Menu, X, CheckCircle2, AlertCircle, Loader2, FileJson, User, MonitorPlay,
Move, Focus, UserCheck, Film, Music, Mic, Crop, ArrowRight
} from 'lucide-react';
/**
* GOOGLE GENAI CONFIGURATION & SERVICES
*/
const apiKey = ""; // Runtime provides this via environment
// Mock service for local logic when API is loading or not yet configured
const geminiService = {
async generateText(prompt) {
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
});
const result = await response.json();
return result.candidates?.[0]?.content?.parts?.[0]?.text || "Maaf, terjadi kesalahan saat memproses teks.";
} catch (e) {
console.error(e);
// Fallback response for demo if API fails
return "Ini adalah contoh respons otomatis dari Magic AI. Dalam aplikasi nyata, teks ini dihasilkan oleh Gemini berdasarkan input Anda untuk meningkatkan kualitas prompt.";
}
},
async generateImage(prompt) {
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/imagen-4.0-generate-001:predict?key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ instances: { prompt }, parameters: { sampleCount: 1 } })
});
const result = await response.json();
return `data:image/png;base64,${result.predictions[0].bytesBase64Encoded}`;
} catch (e) {
console.error(e);
// Fallback image (using placeholder service)
return `https://placehold.co/1024x1024/6366f1/ffffff?text=${encodeURIComponent(prompt.substring(0, 20))}`;
}
},
async generateSpeech(text, voice = "Kore") {
// Mock simulation for TTS
return new Promise(resolve => setTimeout(() => resolve("audio_data_mock"), 2000));
},
async generateVideo(prompt) {
// Mock simulation for Veo
return new Promise(resolve => setTimeout(() => resolve("https://www.w3schools.com/html/mov_bbb.mp4"), 3000));
},
async enhancePrompt(currentInput) {
const prompt = `Bertindaklah sebagai Prompt Engineer ahli. Tulis ulang dan tingkatkan deskripsi berikut agar menjadi prompt yang sangat detail, artistik, dan profesional untuk AI Generator (Image/Video). Tambahkan detail pencahayaan, gaya, dan mood. Input: "${currentInput}". Outputkan HANYA prompt final dalam bahasa Inggris.`;
return this.generateText(prompt);
}
};
/**
* REUSABLE UI COMPONENTS
*/
const GlassCard = ({ children, className = "" }) => (
{children}
);
const Button = ({ children, onClick, variant = "primary", className = "", loading = false, disabled = false, icon: Icon }) => {
const variants = {
primary: "bg-gradient-to-r from-indigo-600 to-purple-600 text-white hover:opacity-90 shadow-lg shadow-indigo-200",
secondary: "bg-white/60 text-slate-700 hover:bg-white/80 border border-slate-200",
danger: "bg-rose-500 text-white hover:bg-rose-600",
ghost: "bg-transparent text-slate-500 hover:bg-slate-100",
magic: "bg-gradient-to-r from-amber-200 to-yellow-400 text-amber-900 border border-amber-300 hover:from-amber-300 hover:to-yellow-500"
};
return (
{loading ? : (
<>
{Icon && }
{children}
>
)}
);
};
// New Component: Magic AI Input Wrapper
const MagicInput = ({ value, onChange, placeholder, className = "", multiline = false }) => {
const [loading, setLoading] = useState(false);
const handleMagic = async () => {
if (!value) return;
setLoading(true);
try {
const enhanced = await geminiService.enhancePrompt(value);
onChange({ target: { value: enhanced } });
} catch (e) {
console.error(e);
} finally {
setLoading(false);
}
};
return (
{multiline ? (
) : (
)}
{loading ? : }
);
};
/**
* MAIN APP COMPONENT
*/
export default function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [user, setUser] = useState(null);
const [activeMenu, setActiveMenu] = useState('ugc-studio');
const [sidebarOpen, setSidebarOpen] = useState(true);
// Auto-seeding
useEffect(() => {
const savedUser = localStorage.getItem('wiki_ai_user');
if (savedUser) {
setUser(JSON.parse(savedUser));
setIsAuthenticated(true);
} else {
const admin = { email: 'didiknice@gmail.com', role: 'ADMIN', name: 'Didik Admin' };
localStorage.setItem('wiki_ai_admin_seed', JSON.stringify(admin));
}
}, []);
const handleLogin = (e) => {
e.preventDefault();
const email = e.target.email.value;
const adminSeed = JSON.parse(localStorage.getItem('wiki_ai_admin_seed'));
if (email === adminSeed.email) {
setUser(adminSeed);
setIsAuthenticated(true);
localStorage.setItem('wiki_ai_user', JSON.stringify(adminSeed));
}
};
const handleLogout = () => {
localStorage.removeItem('wiki_ai_user');
setIsAuthenticated(false);
setUser(null);
};
if (!isAuthenticated) return ;
return (
{/* Background Ornaments */}
setSidebarOpen(!sidebarOpen)} />
);
}
/**
* PAGE: LOGIN & SIDEBAR (Simplified for brevity as they are unchanged logic-wise)
*/
function LoginPage({ onLogin }) {
return (
);
}
function Sidebar({ activeMenu, setActiveMenu, user, onLogout, isOpen, setIsOpen }) {
const menuGroups = [
{
title: "CREATE",
items: [
{ id: 'ugc-studio', label: 'UGC Studio', icon: Layout, color: 'text-purple-600' },
{ id: 'text-gen', label: 'Text Generator', icon: Type, color: 'text-blue-600' }
]
},
{
title: "VISUALS",
items: [
{ id: 'ai-model', label: 'AI Model', icon: UserSquare2, color: 'text-indigo-600', sub: true },
{ id: 'image-gen', label: 'Image Gen', icon: ImageIcon, color: 'text-pink-600' },
{ id: 'remove-bg', label: 'Remove BG', icon: Eraser, color: 'text-rose-600' },
{ id: 'magic-edit', label: 'Magic Edit', icon: Sparkles, color: 'text-orange-500' },
{ id: 'enhancer', label: 'Enhancer', icon: Maximize2, color: 'text-yellow-500' },
{ id: 'merger', label: 'Merger', icon: Layers, color: 'text-cyan-500' },
{ id: 'unmask', label: 'Expand / Uncrop', icon: Scan, color: 'text-sky-500' }
]
},
{
title: "COMMERCIAL",
items: [
{ id: 'product-photo', label: 'Product Photography', icon: Package, color: 'text-amber-500' },
{ id: 'lifestyle', label: 'Lifestyle Preset', icon: Heart, color: 'text-teal-600' }
]
},
{
title: "MEDIA",
items: [
{ id: 'video-veo', label: 'Video Veo', icon: Video, color: 'text-rose-600' },
{ id: 'audio-studio', label: 'Voiceover Studio', icon: Volume2, color: 'text-fuchsia-600' },
{ id: 'live-assistant', label: 'Live AI', icon: Mic2, color: 'text-red-500', live: true }
]
}
];
return (
<>
{/* Header */}
{menuGroups.map((group, idx) => (
{group.title}
{group.items.map(item => (
{ setActiveMenu(item.id); if(window.innerWidth < 768) setIsOpen(false); }}
className={`w-full flex items-center justify-between p-3 rounded-xl transition-all duration-200 group
${activeMenu === item.id ? 'bg-indigo-50/80 text-indigo-700 shadow-sm' : 'text-slate-500 hover:bg-slate-50 hover:text-slate-800'}`}
>
{item.label}
{item.live && }
{item.sub && }
))}
))}
{/* Footer User Profile */}
{user?.name?.[0]}
{user?.name}
Sign Out
{isOpen && setIsOpen(false)}>
}
>
);
}
function Header({ activeMenu, setSidebarOpen }) {
return (
{activeMenu.replace('-', ' ')}
);
}
/**
* TOOL RENDERER
*/
function ToolRenderer({ activeMenu }) {
switch (activeMenu) {
// CREATE
case 'ugc-studio': return ;
case 'text-gen': return ;
// VISUALS
case 'ai-model': return ;
case 'image-gen': return ;
case 'remove-bg': return ;
case 'magic-edit': return ;
case 'enhancer': return ;
case 'merger': return ;
case 'unmask': return ;
// COMMERCIAL
case 'product-photo': return ;
case 'lifestyle': return ;
// MEDIA
case 'video-veo': return ;
case 'audio-studio': return ;
case 'live-assistant': return ;
default: return Not found
;
}
}
/**
* ==========================================
* CATEGORY: CREATE
* ==========================================
*/
function UGCStudio() {
// ... Existing UGC Studio logic, but with MagicInput ...
const [activeTab, setActiveTab] = useState('script');
const [prompt, setPrompt] = useState('');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
const handleGenerate = async () => {
setLoading(true);
try {
if (activeTab === 'script') {
const text = await geminiService.generateText(`Buat script UGC untuk: ${prompt}`);
setResult({ type: 'text', content: text });
} else {
const img = await geminiService.generateImage(`Professional photo: ${prompt}`);
setResult({ type: 'image', content: img });
}
} catch(e) { console.error(e); }
finally { setLoading(false); }
};
return (
{[{id:'script', icon:Type, label:'Script'}, {id:'model', icon:UserSquare2, label:'Model'}, {id:'pose', icon:Camera, label:'Pose'}].map(tab => (
setActiveTab(tab.id)}
className={`px-4 py-2 rounded-xl flex items-center gap-2 font-semibold text-sm border ${activeTab===tab.id ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-white text-slate-500'}`}>
{tab.label}
))}
Input Context
setPrompt(e.target.value)}
placeholder="Deskripsikan kebutuhan konten Anda..."
className="h-40"
/>
Generate
{loading ? : result ? (
result.type === 'text' ? {result.content}
:
) : Hasil akan muncul di sini
}
);
}
function TextGenerator() {
const [prompt, setPrompt] = useState('');
const [output, setOutput] = useState('');
const [loading, setLoading] = useState(false);
return (
Text Generator
setPrompt(e.target.value)} placeholder="Apa yang ingin Anda tulis hari ini?" className="h-full flex-1" />
{setLoading(true); setOutput(await geminiService.generateText(prompt)); setLoading(false);}} className="py-4">Generate
{loading ? : {output || "Output text..."}
}
);
}
/**
* ==========================================
* CATEGORY: VISUALS (Expanded)
* ==========================================
*/
function AIModelStudio() {
const [prompt, setPrompt] = useState('');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
return (
Model Settings
Prompt Detail
setPrompt(e.target.value)} placeholder="Asian female model, 20s, street style..." className="h-32"/>
Studio Lighting Natural
Full Body Portrait
{setLoading(true); setResult(await geminiService.generateImage(prompt)); setLoading(false);}} className="py-3">Create Model
{loading ? : result ? : }
);
}
function ImageGen() {
const [prompt, setPrompt] = useState('');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
return (
setPrompt(e.target.value)} placeholder="Gambarkan visi Anda... (e.g., Cyberpunk city at night)" className="min-h-[120px] text-lg"/>
{setLoading(true); setResult(await geminiService.generateImage(prompt)); setLoading(false);}} className="absolute right-4 bottom-4" icon={Sparkles}>Generate
{loading ? : result ? : Belum ada gambar
}
);
}
function RemoveBG() {
// Simulated BG removal using existing mock
const [image, setImage] = useState(null);
const [loading, setLoading] = useState(false);
return (
);
}
function MagicEdit() {
const [instruction, setInstruction] = useState('');
return (
Canvas Area (Masking)
{/* Canvas logic is same as previous, simplified for this display */}
Magic Instruction
setInstruction(e.target.value)} placeholder="Ganti kemeja dengan jaket kulit..." className="h-32"/>
Apply Edit
);
}
// NEW: Photo Enhancer
function PhotoEnhancer() {
const [loading, setLoading] = useState(false);
return (
AI Photo Enhancer
Upscale resolution, fix blurry faces, and restore details automatically.
Original (Before)
{loading ? : Enhanced (After)
}
{['2x Upscale', '4x Ultra', 'Face Fix', 'Color Restore'].map(opt => (
{opt}
))}
{setLoading(true); setTimeout(() => setLoading(false), 2000)}} className="mx-auto px-12 py-4">Start Enhancing
);
}
// NEW: Photo Merger
function PhotoMerger() {
const [prompt, setPrompt] = useState('');
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
return (
Photo Merger
Source Images
{[1,2,3,4].map(i => (
))}
Merge Instruction
setPrompt(e.target.value)} placeholder="Gabungkan gambar-gambar ini di pantai saat sunset..." className="h-32"/>
{setLoading(true); setResult(await geminiService.generateImage(prompt)); setLoading(false);}} className="py-3">Merge Photos
{loading ? : result ? : }
);
}
// NEW: Uncrop / Expand
function ImageUncrop() {
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
return (
Generative Expand (Uncrop)
Perluas bingkai gambar Anda dengan AI yang mengisi detail secara otomatis.
{/* Simulation of an image in the center with borders */}
{/* Outpainting area */}
{result &&
}
{loading &&
}
1:1 Square
9:16 Story
16:9 Landscape
{setLoading(true); setResult(await geminiService.generateImage("Expanded landscape scenery")); setLoading(false);}} className="py-4 mx-auto px-12">Generate Expansion
);
}
/**
* ==========================================
* CATEGORY: COMMERCIAL (Enhanced)
* ==========================================
*/
function CommercialPreset({ type }) {
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
const [customContext, setCustomContext] = useState('');
const options = type === 'product' ? [
{ label: 'Surface', items: ['Marble', 'Wood', 'Water', 'Podium'] },
{ label: 'Lighting', items: ['Softbox', 'Hard Light', 'Neon', 'Natural'] },
] : [
{ label: 'Theme', items: ['Wedding', 'Corporate', 'Casual', 'Holiday'] },
{ label: 'Background', items: ['Office', 'Studio', 'Park', 'City'] },
];
const handleRender = async () => {
setLoading(true);
const prompt = `Commercial ${type} photography. Context: ${customContext}. Professional, 8k resolution.`;
const img = await geminiService.generateImage(prompt);
setResult(img);
setLoading(false);
};
return (
{type} Studio
Preset profesional untuk hasil instan.
{options.map(opt => (
{opt.label}
{opt.items.map(item => (
{item}
))}
))}
Custom Concept (Magic)
setCustomContext(e.target.value)} placeholder="Tambahkan detail khusus (e.g., nuansa musim panas)..." className="h-24"/>
Render {type}
{loading ? : result ? : (
)}
);
}
/**
* ==========================================
* CATEGORY: MEDIA (Expanded)
* ==========================================
*/
// NEW: Video Veo
function VideoVeo() {
const [activeTab, setActiveTab] = useState('text-to-video');
const [prompt, setPrompt] = useState('');
const [loading, setLoading] = useState(false);
const [videoUrl, setVideoUrl] = useState(null);
const handleGenerateVideo = async () => {
setLoading(true);
setVideoUrl(null);
try {
const url = await geminiService.generateVideo(prompt);
setVideoUrl(url);
} catch(e) { console.error(e); }
finally { setLoading(false); }
};
return (
{['text-to-video', 'image-to-video'].map(t => (
setActiveTab(t)} className={`px-4 py-2 rounded-xl text-sm font-bold capitalize transition-all ${activeTab === t ? 'bg-white shadow text-rose-600' : 'text-slate-500'}`}>
{t.replace(/-/g, ' ')}
))}
Veo Director
setPrompt(e.target.value)} placeholder={activeTab === 'text-to-video' ? "Deskripsikan adegan video secara detail..." : "Deskripsikan gerakan untuk gambar ini..."} className="h-40"/>
{activeTab === 'image-to-video' && (
)}
Duration
5s (Default)
Resolution
1080p
Generate Video
{loading ? (
RENDERING VEO-3.1 MODEL...
) : videoUrl ? (
) : (
)}
);
}
function AudioStudio() {
const [text, setText] = useState('');
const [loading, setLoading] = useState(false);
return (
Voiceover Studio
setText(e.target.value)} placeholder="Masukkan teks naskah podcast atau narasi..." className="flex-1 min-h-[300px]"/>
Pilih Suara (Kore)
{setLoading(true); setTimeout(() => setLoading(false), 2000)}} className="flex-1">Generate Audio
{loading ? : }
VISUALIZER PREVIEW
);
}
function LiveAssistant() {
const [isLive, setIsLive] = useState(false);
return (
{isLive &&
}
setIsLive(!isLive)} className={`w-32 h-32 rounded-full flex items-center justify-center text-white shadow-2xl transition-all active:scale-95 ${isLive ? 'bg-indigo-600' : 'bg-slate-800'}`}>
{isLive ? 'Listening...' : 'Tap to Speak'}
Wiki AI Live Assistant
);
}
/**
* CUSTOM STYLES
*/
if (typeof document !== 'undefined') {
const style = document.createElement('style');
style.innerHTML = `
.custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 10px; }
.scroll-hide::-webkit-scrollbar { display: none; }
@keyframes shimmer { 100% { transform: translateX(100%); } }
`;
document.head.appendChild(style);
const link = document.createElement('link');
link.href = 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap';
link.rel = 'stylesheet';
document.head.appendChild(link);
}