CoolFace
Apppublic

Alpha108/GenerativeEngineOptimization

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
app.py589 linesDownload Raw Back to root
1"""2Main Streamlit Application - GEO SEO AI Optimizer3Entry point for the application with UI components4"""5 6import streamlit as st7import os8import tempfile9import json10from typing import Dict, Any, List11 12# Import our custom modules13from utils.parser import PDFParser, TextParser, WebpageParser14from utils.scorer import GEOScorer15from utils.optimizer import ContentOptimizer16from utils.chunker import VectorChunker17from utils.export import ResultExporter18from utils.lang_utils import detect_language, translate_text19from rag_utils import create_vectorstore_from_text, create_rag_chain20 21# Import LangChain components22from langchain_groq import ChatGroq23from langchain_community.embeddings import HuggingFaceEmbeddings24 25from langdetect import detect26from deep_translator import GoogleTranslator27def detect_and_translate_to_english(text: str) -> str:28    try:29        lang = detect(text)30        if lang != "en":31            st.warning(f"Detected Language: {lang}. Translating to English...")32            translated_text = GoogleTranslator(source='auto', target='en').translate(text)33            return translated_text34        else:35            return text36    except Exception as e:37        st.error(f"Translation failed: {e}")38        return text39 40 41# Assume `translated_content` is your PDF or webpage content in text format (after translation)42 43 44class GEOSEOApp:45    """Main application class that orchestrates all components"""46    47    48    def __init__(self):49        self.setup_config()50        self.setup_models()51        self.setup_parsers()52        self.setup_components()53    54    55    def setup_config(self):56        """Initialize configuration and API keys"""57        self.groq_api_key = os.getenv("GROQ_API_KEY", "your-groq-api-key")58        self.hf_api_key = os.getenv("HUGGINGFACE_API_KEY", "your-huggingface-api-key")59        60        # Create data directory if it doesn't exist61        os.makedirs("data/uploaded_files", exist_ok=True)62    63    def setup_models(self):64        """Initialize LLM and embedding models"""65        self.llm = ChatGroq(66            api_key=self.groq_api_key,67            model_name="llama3-8b-8192",68            temperature=0.169        )70        71        self.embeddings = HuggingFaceEmbeddings(72            model_name="sentence-transformers/all-MiniLM-L6-v2",73            model_kwargs={"device": "cpu"},74            cache_folder="./hf_cache",75        )76    77    def setup_parsers(self):78        """Initialize content parsers"""79        self.pdf_parser = PDFParser()80        self.text_parser = TextParser()81        self.webpage_parser = WebpageParser()82    83    def setup_components(self):84        """Initialize processing components"""85        self.geo_scorer = GEOScorer(self.llm)86        self.content_optimizer = ContentOptimizer(self.llm)87        self.vector_chunker = VectorChunker(self.embeddings)88        self.result_exporter = ResultExporter()89    90    def run(self):91        """Main application runner"""92        st.set_page_config(93            page_title="GEO SEO AI Optimizer", 94            page_icon="๐Ÿš€", 95            layout="wide"96        )97        98        st.title("๐Ÿš€ GEO SEO AI Optimizer")99        st.markdown("*Optimize your content for AI search engines and LLM systems*")100        101        # Sidebar102        self.render_sidebar()103        104        # Main tabs105        tab1, tab2, tab3,tab4 = st.tabs([106            "๐ŸŒ Website GEO Analysis",107            "๐Ÿ”ง Content Enhancement", 108            "๐Ÿ“„ Document Q&A", 109            "๐ŸŒ Translation"110        ])111        112        with tab1:113            self.render_website_analysis_tab()114        115        with tab2:116            self.render_content_enhancement_tab()117        118        with tab3:119            self.render_document_qa_tab()120        with tab4:121            self.render_multilingual_tab()122    123    def render_sidebar(self):124        """Render sidebar with information and controls"""125        st.sidebar.title("๐Ÿ› ๏ธ GEO Tools")126        st.sidebar.markdown("- ๐Ÿ“„ Document Q&A with RAG")127        st.sidebar.markdown("- ๐Ÿ”ง Content Enhancement")128        st.sidebar.markdown("- ๐ŸŒ Website GEO Analysis")129        st.sidebar.markdown("- ๐Ÿ“Š AI-First SEO Scoring")130        131        st.sidebar.markdown("---")132        st.sidebar.markdown("### ๐Ÿ”ง Configuration")133        st.sidebar.markdown("Set your API keys:")134        st.sidebar.code("export GROQ_API_KEY='your-key'")135        136        st.sidebar.markdown("---")137        st.sidebar.markdown("### ๐Ÿ“– GEO Metrics")138        st.sidebar.markdown("**AI Search Visibility**: How likely AI engines will surface your content")139        st.sidebar.markdown("**Query Intent Matching**: How well content matches user queries")140        st.sidebar.markdown("**Conversational Readiness**: Suitability for AI chat responses")141        st.sidebar.markdown("**Citation Worthiness**: Probability of being cited by AI")142        143        st.sidebar.markdown("---")144        st.sidebar.markdown("### โ„น๏ธ Components")145        st.sidebar.markdown("- **Parser**: Extract content from various sources")146        st.sidebar.markdown("- **Scorer**: Analyze GEO performance")147        st.sidebar.markdown("- **Optimizer**: Enhance content for AI")148        st.sidebar.markdown("- **Chunker**: Create vector embeddings")149        st.sidebar.markdown("- **Exporter**: Generate reports")150    151    def render_document_qa_tab(self):152        """Render Document Q&A tab"""153        st.header("๐Ÿ“„ Document Question Answering")154        st.markdown("Upload documents or paste text to ask questions using RAG.")155        156        # File upload157        uploaded_file = st.file_uploader("Upload a PDF file", type=["pdf"])158        159        # Text input160        pasted_text = st.text_area("Or paste text directly:", height=150)161        162        # Question input163        user_query = st.text_input("Ask a question about the content:")164        165        # Submit button166        if st.button("๐Ÿ” Ask Question", key="qa_submit"):167            if not user_query.strip():168                st.warning("Please enter a question.")169                return170            171            try:172                # Parse content173                documents = []174                175                if uploaded_file:176                    with st.spinner("Processing PDF..."):177                         temp_path = self.save_uploaded_file(uploaded_file)178                         documents = self.pdf_parser.parse(temp_path)179                         os.unlink(temp_path)180 181                         # ๐Ÿง  Translate each document if needed182                         for doc in documents:183                             doc.page_content = detect_and_translate_to_english(doc.page_content)184 185                186                elif pasted_text.strip():187                    with st.spinner("Processing text..."):188                         translated_text = detect_and_translate_to_english(pasted_text)189                         documents = self.text_parser.parse(translated_text)190 191 192                else:193                    st.warning("Please upload a PDF or paste some text.")194                    return195                196                # Create vector store and answer question197                with st.spinner("Creating embeddings and searching..."):198                    # Create new vectorstore and update RAG199                    vectorstore = create_vectorstore_from_text(documents, self.embeddings)200                    st.session_state.rag_chain = create_rag_chain(self.llm, vectorstore)201 202                    result = st.session_state.rag_chain.invoke({"query": user_query})203 204                205                # Display results206                st.markdown("### ๐Ÿ’ฌ Answer")207                st.write(result["result"])208                209                # Show sources210                with st.expander("๐Ÿ“„ Source Documents"):211                    for i, doc in enumerate(result.get("source_documents", [])):212                        st.write(f"**Source {i+1}:**")213                        content = doc.page_content214                        st.write(content[:500] + "..." if len(content) > 500 else content)215                        if hasattr(doc, 'metadata') and doc.metadata:216                            st.write(f"*Metadata: {doc.metadata}*")217                        st.write("---")218            219            except Exception as e:220                st.error(f"An error occurred: {str(e)}")221    222    def render_content_enhancement_tab(self):223        """Render Content Enhancement tab"""224        st.header("๐Ÿ”ง Content Enhancement")225        st.markdown("Analyze and optimize your content for better AI/LLM performance.")226    227         # Content input228        input_text = st.text_area(229             "Enter content to analyze and enhance:", 230              height=200, 231              key="enhancement_input"232         )233    234       # Analysis options235        col1, col2 = st.columns(2)236        with col1:237             analyze_only = st.checkbox("Analysis only (no rewriting)", value=False)238        with col2:239             include_keywords = st.checkbox("Include keyword suggestions", value=True)240    241       # Submit button242        if st.button("๐Ÿ”ง Analyze & Enhance", key="enhancement_submit"):243            if not input_text.strip():244                st.warning("Please enter some content to analyze.")245                return246        247            try:248                with st.spinner("Analyzing content..."):249                # Run content analysis and optimization250                    result = self.content_optimizer.optimize_content(251                        input_text,252                        analyze_only=analyze_only,253                        include_keywords=include_keywords254                       )255            256                if result.get("error"):257                    st.error(f"Analysis failed: {result['error']}")258                    return259            260                # Display results261                if analyze_only:262                    st.success("Content analysis completed successfully!")  263                    st.markdown("### ๐Ÿ“Š Analysis Results")264            265                    # Show scores266                    scores = result.get("scores", {})267                    if scores:268                        col1, col2, col3 = st.columns(3)269 270                        with col1:271                              clarity = scores.get("clarity", 0)272                              st.metric("Clarity", f"{clarity}/10")273 274                        with col2:275                              structure = scores.get("structuredness", 0)276                              st.metric("Structure", f"{structure}/10")277 278                        with col3:279                             answerability = scores.get("answerability", 0)280                             st.metric("Answerability", f"{answerability}/10")281 282                # Show keywords283                keywords = result.get("keywords", [])284                if keywords:285                    st.markdown("#### ๐Ÿ”‘ Key Terms")286                    st.write(", ".join(keywords))287            288                # Show optimized content289                optimized_text = result.get("optimized_text", "")290                if optimized_text:291                    st.markdown("#### โœจ Optimized Content")292                    st.text_area(293                        "Enhanced version:", 294                         value=optimized_text, 295                         height=200, 296                         key="optimized_output"297                      )   298 299                # โœ… Optional RAG-based Q&A on the analyzed content300                st.markdown("### ๐Ÿ’ฌ Ask a question about the analyzed content:")301                user_query = st.text_input("Enter your question:", key="enhancement_q")302 303                if user_query:304                    from langchain.docstore.document import Document305                    new_doc = Document(page_content=optimized_text or input_text)306                    vectorstore = create_vectorstore_from_text([new_doc], self.embeddings)307                    st.session_state.rag_chain = create_rag_chain(self.llm, vectorstore)308 309                    result = st.session_state.rag_chain.invoke({"query": user_query})310                    st.success("Answer:")311                    st.write(result["result"])312 313                # Export option314                if st.button("๐Ÿ“ฅ Export Results"):315                     export_data = self.result_exporter.export_enhancement_results(result)316                     st.download_button(317                          label="Download Analysis Report",318                          data=json.dumps(export_data, indent=2),319                          file_name=f"content_analysis_{int(time.time())}.json",320                          mime="application/json"321                      )322        323            except Exception as e:324                  st.error(f"An error occurred: {str(e)}")325 326    327    def render_website_analysis_tab(self):328        """Render Website GEO Analysis tab"""329        st.header("๐ŸŒ Website GEO Analysis")330        st.markdown("Analyze websites for Generative Engine Optimization (GEO) performance.")331    332        # URL input333        col1, col2 = st.columns([3, 1])334        with col1:335              website_url = st.text_input("Enter website URL:", placeholder="https://example.com")336        with col2:337             max_pages = st.selectbox("Pages to analyze:", [1, 3, 5], index=0)338    339        # Analysis options340        col1, col2 = st.columns(2)341        with col1:342            include_subpages = st.checkbox("Include subpages", value=False)343        with col2:344            detailed_analysis = st.checkbox("Detailed analysis", value=True)345    346        # Submit button347        if st.button("๐ŸŒ Analyze Website", key="website_analyze"):348            if not website_url.strip():349                st.warning("Please enter a website URL.")350                return351        352            try:353                # Normalize URL354                if not website_url.startswith(('http://', 'https://')):355                    website_url = 'https://' + website_url356            357                with st.spinner(f"Analyzing website: {website_url}"):358                     # Parse website content359                    pages_data = self.webpage_parser.parse_website(360                         website_url, 361                         max_pages=max_pages,362                         include_subpages=include_subpages363                       )364                    if not pages_data:365                        st.error("Could not extract content from the website.")366                        return367                368                    st.success(f"Successfully extracted content from {len(pages_data)} page(s)")369            370                # Analyze GEO scores371                with st.spinner("Calculating GEO scores..."):372                    geo_results = []373                    for i, page_data in enumerate(pages_data):374                        with st.spinner(f"Analyzing page {i+1}/{len(pages_data)}..."):375                            analysis = self.geo_scorer.analyze_page_geo(376                                page_data['content'],377                                page_data['title'],378                                detailed=detailed_analysis379                             )380                        381                            if not analysis.get('error'):382                                analysis['page_data'] = page_data383                                geo_results.append(analysis)384                            else:385                                st.warning(f"Could not analyze page {i+1}: {analysis['error']}")386            387                if not geo_results:388                    st.error("Could not analyze any pages from the website.")389                    return390 391                # Combine all page content for RAG392                combined_content = "\n\n".join([page['content'] for page in pages_data])393                from langchain.docstore.document import Document394                doc = Document(page_content=combined_content)395 396                vectorstore = create_vectorstore_from_text([doc], self.embeddings)397                st.session_state.rag_chain = create_rag_chain(self.llm, vectorstore)398 399                # RAG-based Q&A400                st.markdown("### ๐Ÿ’ฌ Ask a question about the website:")401                user_query = st.text_input("Ask here:", key="website_q")402 403                if user_query:404                     result = st.session_state.rag_chain.invoke({"query": user_query})405                     st.success("Answer:")406                     st.write(result["result"])407 408                # Display results409                self.display_geo_results(geo_results, website_url)410            411                # Export functionality412                st.markdown("### ๐Ÿ“ฅ Export Results")413                if st.button("๐Ÿ“Š Generate Full Report"):414                    report_data = self.result_exporter.export_geo_results(415                           geo_results, 416                           website_url417                      )418                    st.download_button(419                        label="Download GEO Report",420                        data=json.dumps(report_data, indent=2),421                        file_name=f"geo_analysis_{website_url.replace('https://', '').replace('/', '_')}.json",422                        mime="application/json"423                     )424        425            except Exception as e:426                st.error(f"An error occurred during website analysis: {str(e)}")427 428    def render_multilingual_tab(self):429        st.markdown("### ๐ŸŒ Multilingual Translator")430        st.write("Detect language and translate text into a target language.")431 432        text = st.text_area("Enter text:")433        if text:434            detected_lang = detect_language(text)435            st.write(f"Detected Language: **{detected_lang}**")436 437            target = st.selectbox("Select target language", ["en", "fr", "es", "de", "ur", "hi", "zh", "ar", "ru"])438            if st.button("Translate"):439                result = translate_text(text, target)440                st.success("Translation:")441                st.write(result)442 443    444    def display_geo_results(self, geo_results: List[Dict], website_url: str):445        """Display GEO analysis results"""446        st.markdown("## ๐Ÿ“Š GEO Analysis Results")447        448        # Calculate average scores449        avg_scores = self.calculate_average_scores(geo_results)450        overall_avg = sum(avg_scores.values()) / len(avg_scores) if avg_scores else 0451        452        # Main score display453        col1, col2, col3 = st.columns([1, 2, 1])454        with col2:455            st.metric(456                "Overall GEO Score", 457                f"{overall_avg:.1f}/10",458                delta=f"{overall_avg - 7.0:.1f}" if overall_avg != 7.0 else None459            )460        461        # Individual metrics462        st.markdown("### ๐Ÿ“ˆ Detailed GEO Metrics")463        464        # First row of metrics465        col1, col2, col3, col4 = st.columns(4)466        metrics_row1 = [467            ("AI Search Visibility", "ai_search_visibility"),468            ("Query Intent Match", "query_intent_matching"),469            ("Factual Accuracy", "factual_accuracy"),470            ("Conversational Ready", "conversational_readiness")471        ]472        473        for i, (display_name, key) in enumerate(metrics_row1):474            with [col1, col2, col3, col4][i]:475                score = avg_scores.get(key, 0)476                st.metric(display_name, f"{score:.1f}")477        478        # Second row of metrics479        col1, col2, col3, col4 = st.columns(4)480        metrics_row2 = [481            ("Semantic Richness", "semantic_richness"),482            ("Context Complete", "context_completeness"),483            ("Citation Worthy", "citation_worthiness"),484            ("Multi-Query Cover", "multi_query_coverage")485        ]486        487        for i, (display_name, key) in enumerate(metrics_row2):488            with [col1, col2, col3, col4][i]:489                score = avg_scores.get(key, 0)490                st.metric(display_name, f"{score:.1f}")491        492        # Recommendations493        self.display_recommendations(geo_results)494        495        # Detailed page analysis496        with st.expander("๐Ÿ“‹ Detailed Page Analysis"):497            for i, analysis in enumerate(geo_results):498                page_data = analysis.get('page_data', {})499                st.markdown(f"#### Page {i+1}: {page_data.get('title', 'Unknown Title')}")500                st.write(f"**URL**: {page_data.get('url', 'Unknown')}")501                st.write(f"**Word Count**: {page_data.get('word_count', 0)}")502                503                # Show topics and entities if available504                if 'primary_topics' in analysis:505                    st.write(f"**Topics**: {', '.join(analysis['primary_topics'])}")506                507                if 'entities' in analysis:508                    st.write(f"**Entities**: {', '.join(analysis['entities'])}")509                510                # Show page-specific scores511                if 'geo_scores' in analysis:512                    scores = analysis['geo_scores']513                    score_text = ", ".join([f"{k}: {v:.1f}" for k, v in scores.items()])514                    st.write(f"**Scores**: {score_text}")515                516                st.write("---")517    518    519    def display_recommendations(self, geo_results: List[Dict]):520        """Display optimization recommendations"""521        st.markdown("### ๐Ÿ’ก Optimization Recommendations")522        523        # Collect all recommendations524        all_recommendations = []525        all_opportunities = []526        527        for analysis in geo_results:528            all_recommendations.extend(analysis.get('recommendations', []))529            all_opportunities.extend(analysis.get('optimization_opportunities', []))530        531        # Remove duplicates and display532        unique_recommendations = list(set(all_recommendations))533        534        if unique_recommendations:535            for i, rec in enumerate(unique_recommendations[:5], 1):536                st.write(f"**{i}.** {rec}")537        538        # Priority opportunities539        if all_opportunities:540            st.markdown("#### ๐Ÿš€ Priority Optimizations")541            542            high_priority = [opp for opp in all_opportunities if opp.get('priority') == 'high']543            medium_priority = [opp for opp in all_opportunities if opp.get('priority') == 'medium']544            545            if high_priority:546                st.markdown("##### ๐Ÿ”ด High Priority")547                for opp in high_priority[:3]:548                    st.write(f"**{opp.get('type', 'Optimization')}**: {opp.get('description', 'No description')}")549            550            if medium_priority:551                st.markdown("##### ๐ŸŸก Medium Priority")552                for opp in medium_priority[:3]:553                    st.write(f"**{opp.get('type', 'Optimization')}**: {opp.get('description', 'No description')}")554    555    def calculate_average_scores(self, geo_results: List[Dict]) -> Dict[str, float]:556        """Calculate average GEO scores across all pages"""557        if not geo_results:558            return {}559        560        # Get all score keys from the first result561        score_keys = list(geo_results[0].get('geo_scores', {}).keys())562        avg_scores = {}563        564        for key in score_keys:565            scores = [566                result['geo_scores'][key] 567                for result in geo_results 568                if 'geo_scores' in result and key in result['geo_scores']569            ]570            avg_scores[key] = sum(scores) / len(scores) if scores else 0571        572        return avg_scores573    574    def save_uploaded_file(self, uploaded_file) -> str:575        """Save uploaded file to temporary location"""576        with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:577            tmp_file.write(uploaded_file.read())578            return tmp_file.name579 580def main():581    """Main entry point"""582    if "rag_chain" not in st.session_state:583        st.session_state.rag_chain = None584 585    app = GEOSEOApp()586    app.run()587if __name__ == "__main__":588    main()589