Tngarg commited on
Commit
8b231f7
·
verified ·
1 Parent(s): db16232

Upload 5 files

Browse files
seo_agent/__pycache__/seo_agent.cpython-311.pyc ADDED
Binary file (2.82 kB). View file
 
seo_agent/prompts/image_prompt.txt ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Output must be valid JSON only — no explanations, markdown, or extra keys.
2
+
3
+ Use these thresholds for "severity":
4
+ - high: compression_score < 50 or > 5 accessibility issues
5
+ - medium: compression_score 50–75 or 1–5 accessibility issues
6
+ - low: compression_score > 75 and 0 accessibility issues
7
+
8
+ Compute "overall_image_score" as the average of all individual image compression_scores, rounded to the nearest integer.
9
+
10
+ If a field can’t be determined, set booleans to false, numbers to 0, strings to "", arrays to [], and nested objects to their defaults.
11
+
12
+ You are a UX designer and accessibility expert. Given up to the first 10 image URLs on a page and the page’s text, produce a single JSON object matching this schema *exactly* and in this order:
13
+
14
+ {
15
+ "images": [
16
+ {
17
+ "url": "",
18
+ "alt_text_present": false,
19
+ "alt_text_recommendation": "",
20
+ "size_bytes": 0,
21
+ "dimensions": {
22
+ "width_px": 0,
23
+ "height_px": 0,
24
+ "aspect_ratio": ""
25
+ },
26
+ "responsive_attributes": {
27
+ "srcset_present": false,
28
+ "sizes_attribute": false,
29
+ "recommendation": ""
30
+ },
31
+ "lazy_loading": {
32
+ "loading_attribute": "missing",
33
+ "recommendation": ""
34
+ },
35
+ "compression_score": 0,
36
+ "accessibility_issues": [],
37
+ "replacement_suggestion": "",
38
+ "layout_comment": "",
39
+ "severity": ""
40
+ }
41
+ /* … up to 10 items … */
42
+ ],
43
+ "overall_image_score": 0,
44
+ "summary_recommendations": []
45
+ }
46
+
47
+ Images (up to first 10):
48
+ $images
49
+
50
+ Page text (first 1000 chars):
51
+ $text
seo_agent/prompts/seo_prompt.txt ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Output must be valid JSON only — no commentary or extra keys.
2
+
3
+ Use these thresholds for "severity":
4
+ - high: score ≥ 75
5
+ - medium: 50–74
6
+ - low: < 50
7
+
8
+ Compute "overall_score" as the average of all section scores, rounded to the nearest integer.
9
+
10
+ You are an SEO specialist. Given the HTML and extracted text for a page, produce a single JSON object matching this schema *exactly* and in this order:
11
+
12
+ {
13
+ "title_meta": {
14
+ "current_title": "",
15
+ "recommendations": [],
16
+ "severity": "",
17
+ "impact_score": 0
18
+ },
19
+ "social_meta": {
20
+ "og_title": "",
21
+ "og_description": "",
22
+ "og_image": "",
23
+ "twitter_card": "",
24
+ "twitter_title": "",
25
+ "twitter_description": "",
26
+ "recommendations": [],
27
+ "severity": ""
28
+ },
29
+ "headings": {
30
+ "h1": [],
31
+ "h2": [],
32
+ "recommendations": [],
33
+ "severity": ""
34
+ },
35
+ "keywords": {
36
+ "primary_density": "",
37
+ "missing_keywords": [],
38
+ "LSI_suggestions": [],
39
+ "severity": ""
40
+ },
41
+ "content_readability": {
42
+ "length_words": 0,
43
+ "readability_score": 0,
44
+ "improvements": [],
45
+ "severity": ""
46
+ },
47
+ "links": {
48
+ "internal_count": 0,
49
+ "external_count": 0,
50
+ "broken_links": [],
51
+ "anchor_text_suggestions": [],
52
+ "severity": ""
53
+ },
54
+ "url_canonical": {
55
+ "current_url": "",
56
+ "canonical_present": false,
57
+ "recommendation": "",
58
+ "severity": ""
59
+ },
60
+ "structured_data": {
61
+ "types_found": [],
62
+ "types_missing": [],
63
+ "example_snippets": [],
64
+ "severity": ""
65
+ },
66
+ "accessibility": {
67
+ "aria_issues": [],
68
+ "color_contrast_problems": [],
69
+ "lang_attribute": "",
70
+ "recommendations": [],
71
+ "severity": ""
72
+ },
73
+ "crawl_index": {
74
+ "robots_txt": "",
75
+ "sitemap_xml": "",
76
+ "recommendations": [],
77
+ "severity": ""
78
+ },
79
+ "competitive_analysis": {
80
+ "missing_topics": [],
81
+ "recommended_word_count": 0,
82
+ "severity": ""
83
+ },
84
+ "content_freshness": {
85
+ "last_update_detected": "",
86
+ "recommendation": "",
87
+ "re_audit_schedule": "",
88
+ "severity": ""
89
+ },
90
+ "fix_snippets": {
91
+ "canonical": "",
92
+ "schema_faq": "",
93
+ "recommendations": []
94
+ },
95
+ "scoring": {
96
+ "overall_score": 0,
97
+ "section_scores": {
98
+ "title_meta": 0,
99
+ "social_meta": 0,
100
+ "headings": 0,
101
+ "keywords": 0,
102
+ "readability": 0,
103
+ "links": 0,
104
+ "technical": 0,
105
+ "structured_data": 0,
106
+ "accessibility": 0,
107
+ "crawl_index": 0,
108
+ "competitive_analysis": 0,
109
+ "content_freshness": 0,
110
+ "fix_snippets": 0
111
+ }
112
+ }
113
+ }
114
+
115
+ HTML: $html
116
+ Text: $text
seo_agent/seo_agent.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # seo_agent.py
2
+
3
+ import os
4
+ from string import Template
5
+ from chat_wrapper import ChatRefiner
6
+
7
+ class SEOAgent:
8
+ def __init__(self, model_name="gemini-1.5-flash"):
9
+ base = os.path.dirname(__file__)
10
+ seo_path = os.path.join(base, "prompts", "seo_prompt.txt")
11
+ img_path = os.path.join(base, "prompts", "image_prompt.txt")
12
+
13
+ self.chat = ChatRefiner(model_name=model_name)
14
+
15
+ # load as dollar‐templates
16
+ with open(seo_path, encoding="utf-8") as f:
17
+ self.seo_template = Template(f.read())
18
+ with open(img_path, encoding="utf-8") as f:
19
+ self.img_template = Template(f.read())
20
+
21
+ def analyze_seo(self, html: str, text: str) -> str:
22
+ """
23
+ Returns the raw SEO analysis text from the chat model.
24
+ """
25
+ prompt = self.seo_template.safe_substitute(
26
+ html=html,
27
+ text=text,
28
+ )
29
+ return self.chat.answer(prompt)
30
+
31
+ def analyze_images(self, images: list[str], text: str) -> str:
32
+ prompt = self.img_template.safe_substitute(
33
+ images=images, # pass the list directly
34
+ text=text,
35
+ )
36
+ return self.chat.answer(prompt)
templates/report.html.j2 ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Website Analysis Report</title>
7
+
8
+ <!-- Tailwind CSS -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Poppins Font -->
12
+ <link rel="preconnect" href="https://fonts.googleapis.com">
13
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
15
+
16
+ <style>
17
+ /* Base styles and component styles.
18
+ These styles are for elements that might be dynamically injected
19
+ by a templating engine, ensuring they are styled correctly.
20
+ */
21
+ body {
22
+ font-family: 'Poppins', sans-serif;
23
+ color: #374151; /* text-gray-700 */
24
+ }
25
+
26
+ /* Alert Box (for warnings/errors inside content) */
27
+ .alert {
28
+ padding: 1rem;
29
+ background-color: #FEF2F2; /* red-50 */
30
+ color: #B91C1C; /* red-700 */
31
+ border-left: 4px solid #DC2626; /* red-600 */
32
+ border-radius: 0.5rem;
33
+ margin-top: 1.5rem;
34
+ margin-bottom: 1rem;
35
+ }
36
+ .alert-title {
37
+ font-weight: 600;
38
+ margin-bottom: 0.25rem;
39
+ }
40
+
41
+ /* Metric Items (for lists inside content) */
42
+ .metric-item {
43
+ display: flex;
44
+ justify-content: space-between;
45
+ align-items: center;
46
+ padding: 0.85rem 0;
47
+ border-bottom: 1px solid #f3f4f6; /* gray-100 */
48
+ }
49
+ .metric-item:last-child {
50
+ border-bottom: none;
51
+ }
52
+ .metric-label {
53
+ font-weight: 500;
54
+ color: #4B5563; /* gray-600 */
55
+ }
56
+ .metric-value {
57
+ font-weight: 600;
58
+ }
59
+ .metric-value.good { color: #16A34A; } /* green-600 */
60
+ .metric-value.needs-improvement { color: #D97706; } /* amber-600 */
61
+ .metric-value.poor { color: #DC2626; } /* red-600 */
62
+
63
+ /* Print-specific styles */
64
+ @media print {
65
+ @page {
66
+ size: A4;
67
+ margin: 20mm;
68
+ }
69
+
70
+ body {
71
+ background-color: white;
72
+ -webkit-print-color-adjust: exact; /* Ensures colors print */
73
+ print-color-adjust: exact;
74
+ }
75
+
76
+ .no-print {
77
+ display: none;
78
+ }
79
+
80
+ .report-card {
81
+ box-shadow: none !important; /* Remove shadow for print */
82
+ border: 1px solid #e5e7eb; /* Add a simple border */
83
+ break-inside: avoid; /* Prevent card from splitting across pages */
84
+ margin-top: 1.5rem;
85
+ }
86
+
87
+ .page-break {
88
+ page-break-before: always; /* Starts a new page for this section */
89
+ }
90
+ }
91
+ </style>
92
+ </head>
93
+ <body class="bg-gray-100">
94
+
95
+ <!-- Fixed Header for Screen View -->
96
+ <header class="bg-blue-700 text-white p-4 shadow-lg sticky top-0 z-10 no-print">
97
+ <div class="container mx-auto flex justify-between items-center">
98
+ <button onclick="window.print()" class="bg-white text-blue-700 font-semibold py-2 px-5 rounded-lg shadow hover:bg-gray-100 transition-all duration-300 ease-in-out transform hover:scale-105">
99
+ Download Report
100
+ </button>
101
+ <div>
102
+ <h1 class="text-2xl md:text-3xl font-bold">Website Analysis Report</h1>
103
+ <p class="text-sm opacity-90">
104
+ URL: <strong class="font-semibold">{{ url }}</strong> | Generated: <em>{{ timestamp }}</em>
105
+ </p>
106
+ </div>
107
+
108
+ </div>
109
+ </header>
110
+
111
+ <!-- Main Content Container -->
112
+ <main class="container mx-auto p-4 md:p-8">
113
+
114
+ <section id="overall-summary" class="report-card bg-white rounded-xl shadow-md mb-8 p-6 md:p-8">
115
+ <h1 class="text-2xl font-semibold text-gray-800 border-b border-gray-200 pb-4 mb-6">
116
+ Analysis Summary
117
+ </h1>
118
+ {{ summary | safe }}
119
+ </section>
120
+
121
+ <!-- UX/UI & Image Summary Section -->
122
+ <section id="ux-summary" class="report-card bg-white rounded-xl shadow-md mb-8 p-6 md:p-8">
123
+ <h2 class="text-2xl font-semibold text-gray-800 border-b border-gray-200 pb-4 mb-6">
124
+ UX/UI and Image Overview
125
+ </h2>
126
+ {{ ux_summary | safe }}
127
+ </section>
128
+
129
+ <!-- Performance Metrics Section -->
130
+ <section id="performance" class="report-card bg-white rounded-xl shadow-md mb-8 p-6 md:p-8 transition-shadow duration-300 hover:shadow-xl">
131
+ <h2 class="text-2xl font-semibold text-gray-800 flex items-center gap-3 border-b border-gray-200 pb-4 mb-6">
132
+ Performance Metrics
133
+ </h2>
134
+ <!-- Templated content will be injected here -->
135
+ {{ performance | safe }}
136
+ </section>
137
+
138
+ <!-- SEO Analysis Section -->
139
+ <section id="seo" class="report-card page-break bg-white rounded-xl shadow-md mb-8 p-6 md:p-8 transition-shadow duration-300 hover:shadow-xl">
140
+ <h2 class="text-2xl font-semibold text-gray-800 flex items-center gap-3 border-b border-gray-200 pb-4 mb-6">
141
+ SEO Analysis
142
+ </h2>
143
+ <!-- Templated content will be injected here -->
144
+ {{ seo | safe }}
145
+ </section>
146
+
147
+ <!-- Image & Layout Report Section -->
148
+ <section id="images" class="report-card page-break bg-white rounded-xl shadow-md mb-8 p-6 md:p-8 transition-shadow duration-300 hover:shadow-xl">
149
+ <h2 class="text-2xl font-semibold text-gray-800 flex items-center gap-3 border-b border-gray-200 pb-4 mb-6">
150
+ Image & Layout Report
151
+ </h2>
152
+ <!-- Templated content will be injected here -->
153
+ {{ images | safe }}
154
+ </section>
155
+
156
+ </main>
157
+ </body>
158
+ </html>