/** * @license * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useMemo, useCallback } from 'react'; import { Search, FileDown, Settings2, Zap, Trash2, Copy, BarChart3, Globe, Users, Terminal, Download, Upload, BrainCircuit, X } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import { clsx, type ClassValue } from 'clsx'; import { twMerge } from 'tailwind-merge'; import { saveAs } from 'file-saver'; import { GoogleGenAI } from "@google/genai"; // Utility for tailwind classes function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } // Types interface KeywordInputs { A: string; B: string; C: string; D: string; E: string; F: string; } interface MetaInfo { url: string; product: string; persona: string; } export default function App() { const [meta, setMeta] = useState({ url: '', product: '', persona: '' }); const [suggestedKeywords, setSuggestedKeywords] = useState(''); const [inputs, setInputs] = useState({ A: '怎么\n如何\n在哪里', B: '最好的\n2024\n专业', C: 'SEO工具\n关键词生成器\n营销软件', D: '免费\n在线\n下载', E: '推荐\n热门\n排行', F: '好用吗\n多少钱', }); const [results, setResults] = useState([]); const [analyzing, setAnalyzing] = useState(false); const [activeTab, setActiveTab] = useState<'generate' | 'analyze'>('generate'); const inputConfig = [ { id: 'A', label: 'A前缀1', icon: }, { id: 'B', label: 'B前缀2', icon: }, { id: 'C', label: 'C主词 *', icon: }, { id: 'D', label: 'D通义词', icon: }, { id: 'E', label: 'E推荐词', icon: }, { id: 'F', label: 'F疑问词', icon: }, ]; const combinationActions = [ { label: 'C+D', pattern: ['C', 'D'] }, { label: 'A+C+D', pattern: ['A', 'C', 'D'] }, { label: 'B+C+D', pattern: ['B', 'C', 'D'] }, { label: 'A+B+C+D', pattern: ['A', 'B', 'C', 'D'] }, { label: 'C+D+E', pattern: ['C', 'D', 'E'] }, { label: 'C+D+F', pattern: ['C', 'D', 'F'] }, { label: 'A+C+D+E', pattern: ['A', 'C', 'D', 'E'] }, { label: 'B+C+D+E', pattern: ['B', 'C', 'D', 'E'] }, { label: 'A+B+C+D+E', pattern: ['A', 'B', 'C', 'D', 'E'] }, { label: 'A+B+C+D+F', pattern: ['A', 'B', 'C', 'D', 'F'] }, ]; // Logic: Cartesian Product const combineKeywords = (pattern: string[]) => { const listGroups = pattern.map(key => inputs[key as keyof KeywordInputs] .split('\n') .map(s => s.trim()) .filter(Boolean) ); if (listGroups.some(group => group.length === 0)) { alert('所有选定列必须包含至少一行内容'); return; } const cartesian = (...args: string[][]) => args.reduce((a, b) => a.flatMap(d => b.map(e => [...d, e])), [[]] ); const fullLists = cartesian(...listGroups); const combined = fullLists.map(list => list.join(' ')); setResults(prev => Array.from(new Set([...prev, ...combined]))); }; const handleExport = () => { if (results.length === 0) return; const blob = new Blob([results.join('\n')], { type: 'text/plain;charset=utf-8' }); saveAs(blob, `keywords_${new Date().toISOString().slice(0,10)}.txt`); }; const handleImport = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { const content = e.target?.result as string; setResults(prev => Array.from(new Set([...prev, ...content.split('\n').map(s => s.trim()).filter(Boolean)]))); }; reader.readAsText(file); }; const handleCopy = () => { navigator.clipboard.writeText(results.join('\n')); alert('已复制到剪贴板'); }; const clearResults = () => setResults([]); // Mock Analysis Logic (TF-IDF Simulation) const tfIdfStats = useMemo(() => { const allWords = results.join(' ').split(/\s+/).filter(w => w.length > 1); const count: Record = {}; allWords.forEach(w => count[w] = (count[w] || 0) + 1); return Object.entries(count) .sort((a, b) => b[1] - a[1]) .slice(0, 15) .map(([word, score]) => ({ word, score: (score * Math.log(results.length / score + 1)).toFixed(2) })); }, [results]); const generateAIAssistance = async () => { if (!meta.product) { alert('请至少输入主营产品信息'); return; } setAnalyzing(true); try { // First attempt: Get Google Suggestions const response = await fetch(`/api/suggest?q=${encodeURIComponent(meta.product)}`); const suggestions = await response.json(); if (suggestions && suggestions.length > 0) { setSuggestedKeywords(suggestions.join('\n')); } // Second attempt (Optional): Still use Gemini to fill the matrix if needed, // but the user specifically asked for Google Interface change. // I will keep AI logic for the matrix distribution but primary focus is the suggested keywords. const apiKey = process.env.GEMINI_API_KEY; if (apiKey) { const genAI = new GoogleGenAI({ apiKey }); const model = (genAI as any).getGenerativeModel({ model: "gemini-1.5-flash" }); const prompt = `针对产品: ${meta.product}, 用户画像: ${meta.persona || '一般用户'}。结合以下Google推荐词: ${suggestions.join(', ')}。 请将这些词扩展并分类到以下JSON格式中: { "A": ["前缀词1", "..."], "B": ["质量词1", "..."], "C": ["产品/主词", "..."], "D": ["属性词", "..."], "E": ["推荐语", "..."], "F": ["相关疑问", "..."] }`; const result = await model.generateContent(prompt); const text = result.response.text(); const cleanText = text.replace(/```json|```/gi, '').trim(); const aiKeywords = JSON.parse(cleanText); setInputs(prev => ({ A: (aiKeywords.A || []).join('\n'), B: (aiKeywords.B || []).join('\n'), C: (aiKeywords.C || []).join('\n'), D: (aiKeywords.D || []).join('\n'), E: (aiKeywords.E || []).join('\n'), F: (aiKeywords.F || []).join('\n'), })); } } catch (error) { console.error(error); alert('建议生成部分失败,请重试'); } finally { setAnalyzing(false); } }; return (
{/* Header Section */}

SEO+GEO 关键词生成器 v2.0

Professional Intelligence Suite

{/* Left Panel: Configuration & Stats (Bento col-span-3) */}

基础信息配置

setMeta({...meta, url: e.target.value})} className="w-full text-sm border-slate-200 rounded-xl bg-slate-50 p-2.5 focus:ring-2 focus:ring-indigo-500/10 focus:border-indigo-500 outline-none transition-all" placeholder="https://example.com" />