├── requirements.txt ├── links_test.txt ├── .gitattributes ├── .env-example ├── .gitignore ├── main.py └── helpers.py /requirements.txt: -------------------------------------------------------------------------------- 1 | simplerllm 2 | -------------------------------------------------------------------------------- /links_test.txt: -------------------------------------------------------------------------------- 1 | https://learnwithhasan.com/learn/build-ai-agents/ 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.env-example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY = "sk-proj-XX" 2 | GEMINI_API_KEY = "AIzXXX" 3 | ANTHROPIC_API_KEY = "sk-antXXXX" 4 | 5 | LWH_API_KEY = "sk-u-2-MRBr0XXX" 6 | LWH_USER_ID = 2 7 | 8 | OLLAMA_URL = "http://localhost:11434/" 9 | 10 | RAPIDAPI_API_KEY = "99d728b8e-XXXXX" 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | venv/ 3 | **/__pycache__/ 4 | .pytest_cache/ 5 | /Tests 6 | /my_tests 7 | /old_codes 8 | /dist 9 | /codes 10 | /build 11 | /SimplerLLM/workflow 12 | /SimplerLLM.egg-info 13 | .pypirc 14 | generate_images.py 15 | generate_text.py 16 | chunk_text.py 17 | generate_code.py 18 | generate_embeddings.py 19 | test_embed.py 20 | test_generate.py 21 | test_chunker.py 22 | lib_test.py 23 | /SimplerLLM/tools/web_crawler.py 24 | /SimplerLLM/language/llm_providers/transformers_llm.py 25 | test_agents.py 26 | test_pydantic.py 27 | test_tool.py 28 | /SimplerLLM/tools/predefined_tools.py 29 | /SimplerLLM/agents 30 | test.csv 31 | test_data_agent.py 32 | test_sql_agent.py 33 | vb_ui.py 34 | vd_test.py 35 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | 2 | import streamlit as st 3 | from helpers import free_seo_audit, ai_analysis,api_seo_audit,display_wrapped_json 4 | 5 | 6 | 7 | 8 | def main(): 9 | st.title("Bulk AI SEO Auditor") 10 | 11 | audit_type = st.radio("Choose audit type:", ("Simple Built-in Audit", "Full API Audit")) 12 | 13 | uploaded_file = st.file_uploader("Upload a text file containing URLs (one per line)", type="txt") 14 | 15 | if uploaded_file is not None: 16 | urls = uploaded_file.getvalue().decode("utf-8").splitlines() 17 | st.write(f"Found {len(urls)} URLs in the uploaded file.") 18 | 19 | if st.button("Start Analysis"): 20 | progress_bar = st.progress(0) 21 | status_text = st.empty() 22 | 23 | for i, url in enumerate(urls): 24 | progress = (i + 1) / len(urls) 25 | progress_bar.progress(progress) 26 | status_text.text(f"Analyzing URL {i+1} of {len(urls)}: {url}") 27 | 28 | with st.expander(f"SEO Audit for {url}", expanded=False): 29 | if audit_type == "Simple Built-in Audit": 30 | report = free_seo_audit(url) 31 | else: 32 | report = api_seo_audit(url) 33 | 34 | ai_result = ai_analysis(report) # You'll need to implement this function 35 | 36 | ai_tab, seo_tab = st.tabs(["AI Analysis", "SEO Report"]) 37 | 38 | with ai_tab: 39 | st.subheader("AI Analysis") 40 | st.write(ai_result) 41 | 42 | with seo_tab: 43 | st.subheader("SEO Report") 44 | display_wrapped_json(report) 45 | 46 | status_text.text("Analysis complete!") 47 | progress_bar.progress(1.0) 48 | 49 | if __name__ == "__main__": 50 | main() -------------------------------------------------------------------------------- /helpers.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from urllib.parse import urlparse 3 | from SimplerLLM.language.llm import LLM, LLMProvider 4 | from SimplerLLM.tools.rapid_api import RapidAPIClient 5 | from bs4 import BeautifulSoup 6 | import requests 7 | from textwrap import wrap 8 | import json 9 | import streamlit as st 10 | 11 | llm_instance = LLM.create(provider=LLMProvider.ANTHROPIC,model_name="claude-3-haiku-20240307") 12 | 13 | 14 | def display_wrapped_json(data, width=80): 15 | """ 16 | Display JSON data with text wrapping for improved readability. 17 | """ 18 | def wrap_str(s): 19 | return '\n'.join(wrap(s, width=width)) 20 | 21 | def process_item(item): 22 | if isinstance(item, dict): 23 | return {k: process_item(v) for k, v in item.items()} 24 | elif isinstance(item, list): 25 | return [process_item(i) for i in item] 26 | elif isinstance(item, str): 27 | return wrap_str(item) 28 | else: 29 | return item 30 | 31 | wrapped_data = process_item(data) 32 | st.code(json.dumps(wrapped_data, indent=2), language='json') 33 | 34 | def free_seo_audit(url): 35 | try: 36 | response = requests.get(url) 37 | soup = BeautifulSoup(response.content, "html.parser") 38 | 39 | # Basic HTTP info 40 | audit_result = { 41 | "http": { 42 | "status": response.status_code, 43 | "using_https": url.startswith("https://"), 44 | "response_time": f"{response.elapsed.total_seconds():.2f} seconds", 45 | } 46 | } 47 | 48 | # Metadata 49 | title_tag = soup.find("title") 50 | description_tag = soup.find("meta", {"name": "description"}) 51 | audit_result["metadata"] = { 52 | "title": title_tag.string if title_tag else None, 53 | "title_length": len(title_tag.string) if title_tag else 0, 54 | "description": description_tag["content"] if description_tag else None, 55 | "description_length": len(description_tag["content"]) if description_tag else 0, 56 | } 57 | 58 | # Basic content analysis 59 | text_content = " ".join(soup.stripped_strings) 60 | headings = soup.find_all(["h1", "h2", "h3"]) 61 | audit_result["content"] = { 62 | "word_count": len(text_content.split()), 63 | "h1_count": len([h for h in headings if h.name == "h1"]), 64 | "h2_count": len([h for h in headings if h.name == "h2"]), 65 | "h3_count": len([h for h in headings if h.name == "h3"]), 66 | } 67 | 68 | # Basic link analysis 69 | links = soup.find_all("a") 70 | internal_links = [link.get("href") for link in links if urlparse(link.get("href", "")).netloc == ""] 71 | external_links = [link.get("href") for link in links if urlparse(link.get("href", "")).netloc != ""] 72 | audit_result["links"] = { 73 | "total_links": len(links), 74 | "internal_links": len(internal_links), 75 | "external_links": len(external_links), 76 | } 77 | 78 | # Basic image analysis 79 | images = soup.find_all("img") 80 | audit_result["images"] = { 81 | "total_images": len(images), 82 | "images_without_alt": sum(1 for img in images if not img.get("alt")), 83 | } 84 | 85 | return audit_result 86 | except Exception as ex: 87 | return {"error": str(ex)} 88 | 89 | def ai_analysis(report): 90 | """ 91 | Simulate AI analysis of the SEO audit report. 92 | In a real-world scenario, you'd integrate with an actual AI service. 93 | """ 94 | seo_audit_analysis_prompt = f"""You are an expert in seo analysis. 95 | I will provide you with a [SEO_REPORT] 96 | and your task is to analyze and return a list of optimizations 97 | 98 | [SEO_REPORT]: {report} 99 | 100 | 101 | """ 102 | 103 | ai_response = llm_instance.generate_response(prompt=seo_audit_analysis_prompt,max_tokens=4096) 104 | return ai_response 105 | 106 | def api_seo_audit(url: str): 107 | api_url = "https://website-seo-analyzer.p.rapidapi.com/seo/seo-audit-basic" 108 | api_params = { 109 | 'url': url, 110 | } 111 | api_client = RapidAPIClient() 112 | response = api_client.call_api(api_url, method='GET', params=api_params) 113 | return response --------------------------------------------------------------------------------