bparekh99 commited on
Commit
7e85dc1
Β·
verified Β·
1 Parent(s): 2b2bba7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -114
app.py CHANGED
@@ -1,8 +1,10 @@
1
  import gradio as gr
2
  import requests
 
3
  import logging
4
  import time
5
  from bs4 import BeautifulSoup
 
6
  from google import genai
7
 
8
  # -------------------------------------------------
@@ -16,170 +18,174 @@ logger = logging.getLogger(__name__)
16
 
17
  logger.info("AI Website Review Tool starting up")
18
 
19
- # -------------------------------------------------
20
- # Website Fetching (Safe + Resilient)
21
- # -------------------------------------------------
 
 
 
 
 
 
 
 
 
 
22
  def fetch_website_text(url: str) -> str:
 
 
23
  headers = {
24
- "User-Agent": "Mozilla/5.0 (compatible; AIWebsiteAnalyzer/1.0)"
 
 
 
 
 
 
25
  }
26
 
27
- response = requests.get(url, headers=headers, timeout=15)
 
 
 
 
 
28
  response.raise_for_status()
29
 
30
  soup = BeautifulSoup(response.text, "html.parser")
31
 
32
- # Remove scripts/styles
33
  for tag in soup(["script", "style", "noscript"]):
34
  tag.decompose()
35
 
36
- text = soup.get_text(separator=" ")
37
- return " ".join(text.split())[:8000]
38
 
 
 
 
 
 
 
 
 
 
 
 
39
 
 
 
 
 
40
  def fetch_website_text_safe(url: str) -> str:
41
- logger.info(f"Attempting to fetch: {url}")
42
  try:
43
- logger.info(f"Fetching website content | url={url}")
44
  return fetch_website_text(url)
45
  except Exception as e:
46
- logger.warning(
47
- f"Website fetch failed | url={url} | error={str(e)}"
48
- )
49
- return """
50
  ⚠️ Unable to fully fetch website content.
51
-
52
- Please analyze this website based on:
53
- - URL structure
54
- - Homepage intent
55
- - General UX, SEO, and conversion best practices
56
  """
57
 
58
 
59
- # -------------------------------------------------
60
  # Gemini Analysis
61
- # -------------------------------------------------
62
  def analyze_website(api_key, url, industry, goal):
63
- client = genai.Client(api_key=api_key)
64
- logging.info("Initialized AI client")
65
-
66
- website_text = fetch_website_text_safe(url)
67
-
68
- prompt = f"""
69
- You are an expert AI consultant helping small businesses improve their websites.
70
 
71
- Website URL:
72
- {url}
73
 
74
- Industry:
75
- {industry}
76
-
77
- Primary Business Goal:
78
- {goal}
79
-
80
- Website Content (may be partial):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  {website_text}
82
-
83
- Please provide:
84
- 1. Overall assessment
85
- 2. UX & design improvements
86
- 3. SEO recommendations
87
- 4. Conversion & messaging improvements
88
- 5. AI & automation opportunities
89
- 6. Top 3 prioritized action items
90
-
91
- Be concise, practical, and actionable.
92
  """
93
 
94
- try:
95
  response = client.models.generate_content(
96
  model="gemini-2.5-flash",
97
  contents=prompt,
98
  )
99
- return response.text
100
-
101
- except Exception as e:
102
- logger.exception("Gemini API error")
103
- raise
104
-
105
-
106
- # -------------------------------------------------
107
- # Analysis Wrapper (UX + Logging)
108
- # -------------------------------------------------
109
- def analyze_with_status(api_key, url, industry, goal):
110
- start_time = time.time()
111
- safe_url = url[:120] if url else "EMPTY"
112
-
113
- logger.info(
114
- f"Analysis started | url={safe_url} | industry={industry} | goal={goal}"
115
- )
116
-
117
- # Disable button + show status
118
- yield (
119
- "πŸ” **Analyzing website… please wait**",
120
- "",
121
- gr.update(interactive=False),
122
- )
123
-
124
- try:
125
- logging.info("Starting analysis")
126
- result = analyze_website(api_key, url, industry, goal)
127
-
128
- duration = round(time.time() - start_time, 2)
129
- logger.info(
130
- f"Analysis completed | url={safe_url} | duration={duration}s"
131
- )
132
 
133
- yield (
134
- "βœ… **Analysis complete**",
135
- "## βœ… Website Analysis Complete\n\n" + result,
136
- gr.update(interactive=True),
137
- )
138
 
139
  except Exception as e:
140
- duration = round(time.time() - start_time, 2)
141
- logger.exception(
142
- f"Analysis failed | url={safe_url} | duration={duration}s"
143
- )
144
-
145
- yield (
146
- "❌ **Analysis failed**",
147
- "Something went wrong while analyzing this website. Please try again.",
148
- gr.update(interactive=True),
149
- )
150
 
151
 
152
- # -------------------------------------------------
153
  # Gradio UI
154
- # -------------------------------------------------
155
  with gr.Blocks(title="AI Website Review Tool") as demo:
 
156
  gr.Markdown(
157
- """
158
- # πŸ” AI Website Review Tool
159
- AI-powered website audits for small businesses
160
- *Built by Esquire IT*
161
- """
162
  )
163
 
164
  api_key = gr.Textbox(
165
  label="Gemini API Key",
166
- placeholder="Enter your Gemini API key",
167
  type="password",
168
  )
169
 
170
  url = gr.Textbox(
171
  label="Website URL",
172
- placeholder="https://www.example.com",
173
  )
174
 
175
- industry = gr.Textbox(
176
  label="Industry",
177
- placeholder="e.g. Law Firm, Restaurant, SaaS, Consultant",
 
 
 
 
 
 
 
178
  )
179
 
180
- goal = gr.Textbox(
181
- label="Primary Goal",
182
- placeholder="e.g. Get more leads, increase bookings, improve credibility",
 
 
 
 
 
 
183
  )
184
 
185
  analyze_btn = gr.Button("Analyze Website")
@@ -187,13 +193,28 @@ AI-powered website audits for small businesses
187
  status = gr.Markdown("")
188
  output = gr.Markdown()
189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  analyze_btn.click(
191
  fn=analyze_with_status,
192
  inputs=[api_key, url, industry, goal],
193
- outputs=[status, output, analyze_btn],
194
  queue=False,
195
  )
196
 
197
- logger.info("AI Website Review Tool ready")
198
-
199
- demo.launch()
 
1
  import gradio as gr
2
  import requests
3
+ import socket
4
  import logging
5
  import time
6
  from bs4 import BeautifulSoup
7
+ from urllib.parse import urlparse
8
  from google import genai
9
 
10
  # -------------------------------------------------
 
18
 
19
  logger.info("AI Website Review Tool starting up")
20
 
21
+ # -----------------------------
22
+ # URL Normalization
23
+ # -----------------------------
24
+ def normalize_url(url: str) -> str:
25
+ parsed = urlparse(url)
26
+ if not parsed.scheme:
27
+ return "https://" + url
28
+ return url
29
+
30
+
31
+ # -----------------------------
32
+ # Fetch & Parse Website (Hardened)
33
+ # -----------------------------
34
  def fetch_website_text(url: str) -> str:
35
+ socket.setdefaulttimeout(10)
36
+
37
  headers = {
38
+ "User-Agent": (
39
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
40
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
41
+ "Chrome/121.0 Safari/537.36"
42
+ ),
43
+ "Accept": "text/html,application/xhtml+xml",
44
+ "Accept-Language": "en-US,en;q=0.9",
45
  }
46
 
47
+ response = requests.get(
48
+ url,
49
+ headers=headers,
50
+ timeout=10,
51
+ allow_redirects=True,
52
+ )
53
  response.raise_for_status()
54
 
55
  soup = BeautifulSoup(response.text, "html.parser")
56
 
57
+ # Remove noisy tags
58
  for tag in soup(["script", "style", "noscript"]):
59
  tag.decompose()
60
 
61
+ title = soup.title.string.strip() if soup.title else ""
62
+ h1 = soup.find("h1").get_text(strip=True) if soup.find("h1") else ""
63
 
64
+ body_text = " ".join(soup.stripped_strings)
65
+ body_text = body_text[:8000] # token safety
66
+
67
+ return f"""
68
+ PAGE TITLE:
69
+ {title}
70
+ PRIMARY H1:
71
+ {h1}
72
+ VISIBLE CONTENT:
73
+ {body_text}
74
+ """
75
 
76
+
77
+ # -----------------------------
78
+ # Safe Wrapper (Never Crash)
79
+ # -----------------------------
80
  def fetch_website_text_safe(url: str) -> str:
 
81
  try:
 
82
  return fetch_website_text(url)
83
  except Exception as e:
84
+ return f"""
 
 
 
85
  ⚠️ Unable to fully fetch website content.
86
+ Error:
87
+ {str(e)}
88
+ Fallback:
89
+ Analyze based on URL structure, homepage intent, and general best practices.
 
90
  """
91
 
92
 
93
+ # -----------------------------
94
  # Gemini Analysis
95
+ # -----------------------------
96
  def analyze_website(api_key, url, industry, goal):
97
+ if not api_key:
98
+ return "❌ Please enter your Gemini API key."
 
 
 
 
 
99
 
100
+ if not url:
101
+ return "❌ Please enter a website URL."
102
 
103
+ try:
104
+ url = normalize_url(url)
105
+
106
+ client = genai.Client(api_key=api_key)
107
+
108
+ website_text = fetch_website_text_safe(url)
109
+
110
+ prompt = f"""
111
+ You are an AI consultant helping small businesses improve their websites.
112
+ Business context:
113
+ - Industry: {industry}
114
+ - Primary goal: {goal}
115
+ Analyze the website content below and provide recommendations in this structure:
116
+ 1. Messaging Clarity (score 1–10)
117
+ - Main issue
118
+ - 2–3 actionable recommendations
119
+ 2. Conversion Effectiveness (score 1–10)
120
+ - Main issue
121
+ - 2–3 actionable recommendations
122
+ 3. Trust & Credibility (score 1–10)
123
+ - Main issue
124
+ - 2–3 actionable recommendations
125
+ 4. User Experience Issues
126
+ - Bullet list of issues
127
+ 5. AI & Automation Opportunities
128
+ - 3 concrete ideas a small business could implement
129
+ End with:
130
+ - Overall score out of 100
131
+ - Top 3 fixes to prioritize this week
132
+ Use clear, non-technical business language.
133
+ Website content:
134
  {website_text}
 
 
 
 
 
 
 
 
 
 
135
  """
136
 
 
137
  response = client.models.generate_content(
138
  model="gemini-2.5-flash",
139
  contents=prompt,
140
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
142
+ return response.text
 
 
 
 
143
 
144
  except Exception as e:
145
+ return f"❌ Error during analysis: {str(e)}"
 
 
 
 
 
 
 
 
 
146
 
147
 
148
+ # -----------------------------
149
  # Gradio UI
150
+ # -----------------------------
151
  with gr.Blocks(title="AI Website Review Tool") as demo:
152
+ gr.Markdown("## πŸ” AI Website Review Tool")
153
  gr.Markdown(
154
+ "Analyze any website and receive practical, business-focused recommendations."
 
 
 
 
155
  )
156
 
157
  api_key = gr.Textbox(
158
  label="Gemini API Key",
159
+ placeholder="Paste your Gemini API key here",
160
  type="password",
161
  )
162
 
163
  url = gr.Textbox(
164
  label="Website URL",
165
+ placeholder="https://example.com",
166
  )
167
 
168
+ industry = gr.Dropdown(
169
  label="Industry",
170
+ choices=[
171
+ "General SMB",
172
+ "Law Firm",
173
+ "Hospitality",
174
+ "Healthcare",
175
+ "Real Estate",
176
+ ],
177
+ value="General SMB",
178
  )
179
 
180
+ goal = gr.Dropdown(
181
+ label="Primary Website Goal",
182
+ choices=[
183
+ "Generate leads",
184
+ "Sell services",
185
+ "Build credibility",
186
+ "Educate visitors",
187
+ ],
188
+ value="Generate leads",
189
  )
190
 
191
  analyze_btn = gr.Button("Analyze Website")
 
193
  status = gr.Markdown("")
194
  output = gr.Markdown()
195
 
196
+ def analyze_with_status(api_key, url, industry, goal):
197
+ # Disable button + show analyzing status
198
+ yield (
199
+ "πŸ” **Analyzing website… please wait**",
200
+ "",
201
+ gr.update(interactive=False)
202
+ )
203
+
204
+ result = analyze_website(api_key, url, industry, goal)
205
+
206
+ # Re-enable button + show results
207
+ yield (
208
+ "βœ… **Analysis complete**",
209
+ "## βœ… Website Analysis Complete\n\n" + result,
210
+ gr.update(interactive=True)
211
+ )
212
+
213
  analyze_btn.click(
214
  fn=analyze_with_status,
215
  inputs=[api_key, url, industry, goal],
216
+ outputs=[status, output],
217
  queue=False,
218
  )
219
 
220
+ demo.launch()