ai

import React, { useState, useEffect, useRef, useCallback } from ‘react’; import { initializeApp } from ‘firebase/app’; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from ‘firebase/auth’; import { getFirestore, doc, setDoc, getDoc, collection, query, onSnapshot, addDoc, deleteDoc } from ‘firebase/firestore’; // Removed shadcn/ui imports and will use native HTML elements with Tailwind for styling import { Plus, Trash2, Download, Copy } from ‘lucide-react’; // Using Lucide React for icons // Helper function to safely get appId and firebaseConfig const getFirebaseConfig = () => { try { return typeof __firebase_config !== ‘undefined’ ? JSON.parse(__firebase_config) : {}; } catch (e) { console.error(“Error parsing __firebase_config:”, e); return {}; } }; const appId = typeof __app_id !== ‘undefined’ ? __app_id : ‘default-app-id’; const firebaseConfig = getFirebaseConfig(); // Initialize Firebase (outside component to prevent re-initialization) let app, db, auth; if (Object.keys(firebaseConfig).length > 0) { app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); } // Main App Component const App = () => { const [user, setUser] = useState(null); const [sampleArticles, setSampleArticles] = useState([]); const [newSampleArticle, setNewSampleArticle] = useState(”); const [keyword, setKeyword] = useState(”); const [articleLength, setArticleLength] = useState(1500); // Default to 1500 words, changed to number const [generatedArticle, setGeneratedArticle] = useState(”); const [isLoading, setIsLoading] = useState(false); const [message, setMessage] = useState(”); // For user messages (e.g., success/error) const [isAuthReady, setIsAuthReady] = useState(false); // Firestore Refs const sampleArticlesRef = user && db ? collection(db, `artifacts/${appId}/users/${user.uid}/sample_articles`) : null; const generatedArticlesRef = user && db ? collection(db, `artifacts/${appId}/users/${user.uid}/generated_articles`) : null; // Authentication and Firestore Initialization useEffect(() => { if (!app || !auth || !db) { setMessage(“Firebase is not configured. Please ensure __firebase_config is correctly set.”); setIsAuthReady(false); return; } const unsubscribe = onAuthStateChanged(auth, async (currentUser) => { if (currentUser) { setUser(currentUser); } else { try { if (typeof __initial_auth_token !== ‘undefined’ && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (error) { console.error(“Error signing in:”, error); setMessage(`Authentication failed: ${error.message}`); } } setIsAuthReady(true); }); return () => unsubscribe(); }, []); // Fetch sample articles when user is authenticated useEffect(() => { if (!isAuthReady || !user || !sampleArticlesRef) return; const q = query(sampleArticlesRef); const unsubscribe = onSnapshot(q, (snapshot) => { const articles = snapshot.docs.map(doc => ({ id: doc.id, …doc.data() })); setSampleArticles(articles); }, (error) => { console.error(“Error fetching sample articles:”, error); setMessage(“Error fetching sample articles.”); }); return () => unsubscribe(); }, [isAuthReady, user, sampleArticlesRef]); // Function to add a new sample article const addSampleArticle = async () => { if (!newSampleArticle.trim() || !user || !sampleArticlesRef) { setMessage(“Please enter some text for the sample article.”); return; } try { await addDoc(sampleArticlesRef, { content: newSampleArticle, createdAt: new Date(), userId: user.uid, }); setNewSampleArticle(”); setMessage(“Sample article added!”); } catch (error) { console.error(“Error adding sample article:”, error); setMessage(“Failed to add sample article.”); } }; // Function to delete a sample article const deleteSampleArticle = async (id) => { if (!user || !sampleArticlesRef) return; try { await deleteDoc(doc(sampleArticlesRef, id)); setMessage(“Sample article deleted!”); } catch (error) { console.error(“Error deleting sample article:”, error); setMessage(“Failed to delete sample article.”); } }; // Function to generate article using Gemini API const generateArticle = async () => { if (!keyword.trim()) { setMessage(“Please enter a keyword to generate the article.”); return; } if (sampleArticles.length === 0) { setMessage(“Please upload 5-10 sample articles first for style guidance.”); return; } setIsLoading(true); setMessage(‘Generating article…’); // Construct the prompt using sample articles for style guidance let prompt = `You are an expert article writer. Your task is to generate a comprehensive, human-like, AdSense-friendly, and plagiarism-free article on the topic “${keyword}”. You must follow the exact writing style, structure, and tone from the following sample human-written articles. Analyze them carefully for introduction style (especially starting with a user problem and quick solution), paragraph length, heading hierarchy (H1, H2, H3), vocabulary, voice, and overall flow. —BEGIN SAMPLE ARTICLES FOR STYLE GUIDANCE— ${sampleArticles.map(sa => `\n—SAMPLE ARTICLE—\n${sa.content}\n—END SAMPLE ARTICLE—`).join(‘\n’)} —END SAMPLE ARTICLES FOR STYLE GUIDANCE— Now, generate a new article following these specific requirements: 1. **Topic**: “${keyword}” 2. **Writing Style, Structure, and Tone**: Strictly adhere to the examples provided in the “SAMPLE ARTICLES FOR STYLE GUIDANCE” section above. 3. **Real-time Information**: Incorporate the latest and most relevant information available about the topic. If specific external data isn’t provided, use your up-to-date general knowledge. 4. **Introduction**: Start with a common user problem related to “${keyword}” and immediately offer a quick, concise solution. 5. **Structure**: * Use a clear H1 for the main title. * Break down the content with SEO-friendly H2 and H3 headings. * Ensure paragraphs are well-structured and easy to read. 6. **EEAT (Expertise, Experience, Authoritativeness, Trustworthiness)**: Write the article in a way that demonstrates high EEAT. Use credible language, present facts clearly, and show a deep understanding of the subject. 7. **Human-like, AdSense-friendly, Plagiarism-free**: Ensure the generated content reads naturally, adheres to advertising policies, and is original. 8. **Length**: The article should be approximately ${articleLength} words long. Adjust the depth and breadth of topics to fit this word count. 9. **Conclusion & FAQ**: End the article with a strong concluding paragraph and then include an “FAQ” section. The FAQ should contain 3-5 common questions related to “${keyword}” based on typical search intent, with concise answers. Begin the article now.`; try { const payload = { contents: [{ role: “user”, parts: [{ text: prompt }] }], }; const apiKey = “”; // Canvas will provide this at runtime if empty const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts && result.candidates[0].content.parts.length > 0) { const text = result.candidates[0].content.parts[0].text; setGeneratedArticle(text); setMessage(“Article generated successfully!”); // Save generated article to Firestore if (user && generatedArticlesRef) { await addDoc(generatedArticlesRef, { keyword: keyword, articleContent: text, length: articleLength, createdAt: new Date(), userId: user.uid, }); } } else { console.error(“Unexpected API response structure:”, result); setMessage(“Failed to generate article: Unexpected response from AI.”); } } catch (error) { console.error(“Error generating article:”, error); setMessage(`Failed to generate article: ${error.message}`); } finally { setIsLoading(false); } }; // Function to copy generated article to clipboard const copyArticleToClipboard = () => { if (generatedArticle) { // Use document.execCommand for better iframe compatibility const textarea = document.createElement(‘textarea’); textarea.value = generatedArticle; document.body.appendChild(textarea); textarea.select(); document.execCommand(‘copy’); document.body.removeChild(textarea); setMessage(‘Article copied to clipboard!’); } }; // Function to export article as TXT const exportArticleAsTxt = () => { if (generatedArticle) { const blob = new Blob([generatedArticle], { type: ‘text/plain;charset=utf-8’ }); const url = URL.createObjectURL(blob); const a = document.createElement(‘a’); a.href = url; a.download = `${keyword.replace(/\s+/g, ‘-‘)}-article.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); setMessage(‘Article exported as TXT!’); } }; // Slider component for article length const LengthSlider = ({ value, onChange, min, max, step }) => { return ( onChange(Number(e.target.value))} className=”w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700″ /> ); }; if (!isAuthReady) { return (

Loading application…

); } // Ensure user ID is displayed for multi-user context const displayUserId = user ? `User ID: ${user.uid}` : ‘Not authenticated’; return (

AI Article Writer

{displayUserId}

{message && (
{message}
)}
{/* Left Column: Sample Articles & Generation Controls */}
{/* Replaced Card with div */}

1. Provide Sample Articles

Paste 5-10 human-written articles here. The AI will learn their style, structure, and tone.

{sampleArticles.length > 0 && (

Your Samples:

{sampleArticles.map((sa, index) => (
{index + 1}. {sa.content.substring(0, 100)}…
))}
)}