File size: 9,569 Bytes
768c740
7d19342
 
b8a6b71
7d19342
 
6784902
20bfd0b
 
 
56f7cbb
7d19342
b8a6b71
7d19342
 
20bfd0b
7d19342
 
20bfd0b
 
7d19342
 
20bfd0b
 
 
 
 
 
 
 
 
 
 
7d19342
 
20bfd0b
 
 
 
7d19342
 
 
 
 
20bfd0b
 
 
 
 
 
 
 
 
 
 
7d19342
 
20bfd0b
 
 
 
7d19342
 
 
 
 
 
 
20bfd0b
7d19342
 
20bfd0b
7d19342
 
 
 
 
 
 
 
b8a6b71
20bfd0b
 
 
 
 
 
 
 
 
 
 
 
 
b8a6b71
20bfd0b
 
7d19342
20bfd0b
768c740
7d19342
 
768c740
20bfd0b
 
 
1d1f3c9
20bfd0b
1d1f3c9
20bfd0b
 
7d19342
20bfd0b
7d19342
20bfd0b
7d19342
 
20bfd0b
 
 
 
768c740
20bfd0b
 
 
 
 
 
 
 
 
210d41a
20bfd0b
 
 
 
210d41a
 
 
 
 
1d1f3c9
 
210d41a
1d1f3c9
 
210d41a
 
20bfd0b
 
210d41a
20bfd0b
1d1f3c9
 
210d41a
 
1d1f3c9
210d41a
 
20bfd0b
 
210d41a
 
 
20bfd0b
 
210d41a
20bfd0b
1d1f3c9
 
20bfd0b
 
 
 
 
 
1d1f3c9
210d41a
 
 
 
1d1f3c9
210d41a
1d1f3c9
 
210d41a
1d1f3c9
210d41a
20bfd0b
 
 
210d41a
 
 
1d1f3c9
210d41a
 
 
1d1f3c9
 
 
210d41a
20bfd0b
 
210d41a
 
20bfd0b
210d41a
20bfd0b
 
210d41a
1d1f3c9
210d41a
1d1f3c9
 
 
210d41a
 
 
1d1f3c9
210d41a
1d1f3c9
 
210d41a
1d1f3c9
210d41a
 
 
1d1f3c9
210d41a
1d1f3c9
 
210d41a
 
20bfd0b
 
b8a6b71
1d1f3c9
20bfd0b
1d1f3c9
 
 
210d41a
1d1f3c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210d41a
 
 
1d1f3c9
 
 
 
7d19342
1d1f3c9
 
 
210d41a
7d19342
20bfd0b
 
 
 
7d19342
768c740
7d19342
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import gradio as gr
import requests
from bs4 import BeautifulSoup
from nltk import download, sent_tokenize
import google.generativeai as genai
import os
import re
import tempfile
import asyncio
import time

# Download NLTK data
download('punkt')
download('punkt_tab')

# Configure Gemini API using environment variable
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
    raise ValueError("GEMINI_API_KEY not found in environment variables. Please set it in your environment.")

genai.configure(api_key=api_key)

# Use gemini-1.5-flash for faster and more accessible text analysis
try:
    model = genai.GenerativeModel('gemini-1.5-flash')
except Exception as e:
    print(f"Error initializing model: {str(e)}")
    print("Available models:")
    for m in genai.list_models():
        print(m.name)
    raise ValueError("Failed to initialize gemini-1.5-flash. Check available models above and update the model name.")

# Prompt for Gemini to analyze text with specified output format
PROMPT = """
You are an AI content reviewer. Analyze the provided text for the following:
1. Grammar Issues: Identify and suggest corrections for grammatical errors.
2. Legal Policy Violations: Flag content that may violate common legal policies (e.g., copyright infringement, defamation, incitement to violence).
3. Crude/Abusive Language: Detect crude, offensive, or abusive language.
4. Sensitive Topics: Identify content related to sensitive topics such as racism, gender bias, or other forms of discrimination.

Return the results in the following markdown format:
# Blog Review Report

## Grammar Corrections
1. [Heading of issue]
   - CONTENT: [Exact line or part of text with the issue]
   - SUGGESTION: [Suggested correction]
   - ISSUE: [Description of the issue]

2. [Heading of next issue]
   - CONTENT: [Exact line or part of text with the issue]
   - SUGGESTION: [Suggested correction]
   - ISSUE: [Description of the issue]

[Continue numbering for additional issues or state "None detected"]

## Legal Policy Violations
- CONTENT: [Exact line or part of text with the issue]
  SUGGESTION: [Suggested action or correction]
  ISSUE: [Description of the legal violation]
[Or state "None detected"]

## Crude/Abusive Language
- [List instances of crude or abusive language or "None detected"]

## Sensitive Topics
- [List instances of sensitive topics or "None detected"]

For each issue, provide the exact text, a suggested correction or action, and a concise explanation. Be precise and ensure the output strictly follows the specified format.
"""

async def fetch_url_content(url):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')
        content = ' '.join([p.get_text(strip=True) for p in soup.find_all(['p', 'article', 'div'])])
        return content if content else "No readable content found on the page."
    except Exception as e:
        return f"Error fetching URL: {str(e)}"

async def review_blog(text_input, url_input, progress=gr.Progress()):
    if text_input and not url_input:
        input_type = "Text"
        input_text = text_input
    elif url_input and not text_input:
        input_type = "URL"
        input_text = url_input
    else:
        return "Review Blog", "Error: Please provide input in either the Text or URL tab, but not both.", gr.update(visible=False)

    if not input_text:
        return "Review Blog", "Error: No input provided.", gr.update(visible=False)

    if input_type == "URL":
        progress(0, desc="Fetching content...")
        input_text = await fetch_url_content(input_text)
        if input_text.startswith("Error"):
            return "Review Blog", input_text, gr.update(visible=False)

    sentences = sent_tokenize(input_text)
    analysis_text = "\n".join(sentences)

    progress(0, desc="Generating report...")
    start_time = time.time()
    for i in range(1, 10):
        await asyncio.sleep(1)
        progress(i / 10, desc=f"Generating report... ({int(i * 10)}%)")
        if time.time() - start_time > 30:
            return "Review Blog", "Error: API request timed out after 30 seconds.", gr.update(visible=False)

    try:
        response = await asyncio.to_thread(model.generate_content, PROMPT + "\n\nText to analyze:\n" + analysis_text)
        report = response.text.strip()
        report = re.sub(r'^markdown\n|$', '', report, flags=re.MULTILINE)
    except Exception as e:
        report = f"Error analyzing content with Gemini: {str(e)}"
        print("Available models:")
        for m in genai.list_models():
            print(m.name)
        return "Review Blog", report, gr.update(visible=False)

    try:
        with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False, encoding='utf-8') as temp_file:
            temp_file.write(report)
            temp_file_path = temp_file.name
        progress(1.0, desc="Report generated!")
        return "Review Blog", report, gr.update(visible=True, value=temp_file_path)
    except Exception as e:
        return "Review Blog", f"Error creating temporary file: {str(e)}", gr.update(visible=False)

# Enhanced custom CSS for a more attractive and user-friendly UI
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
.gradio-container {
    font-family: 'Inter', sans-serif !important;
    background: linear-gradient(135deg, #f0f4f8 0%, #d9e2ec 100%);
    padding: 30px;
    border-radius: 15px;
    box-shadow: 0 6px 25px rgba(0, 0, 0, 0.15);
    color: #2d3748;
}
h1, h3 {
    color: #2b6cb0;
    text-align: center;
    font-weight: 700;
    margin-bottom: 15px;
    text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
}
.review-btn {
    background: linear-gradient(45deg, #4a90e2, #63b3ed);
    color: white;
    font-weight: 600;
    border: none;
    border-radius: 12px;
    padding: 14px 28px;
    transition: all 0.3s ease;
    box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3);
    cursor: pointer;
}
.review-btn:hover {
    background: linear-gradient(45deg, #63b3ed, #4a90e2);
    transform: translateY(-3px);
    box-shadow: 0 6px 15px rgba(74, 144, 226, 0.4);
}
.review-btn:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}
.review-btn:disabled::after {
    content: ' ⏳';
}
.tab-nav button {
    font-family: 'Inter', sans-serif;
    font-weight: 600;
    background: #edf2f7;
    color: #2d3748;
    border-radius: 10px 10px 0 0;
    padding: 12px 24px;
    transition: all 0.2s ease;
    border: 1px solid #e2e8f0;
}
.tab-nav button:hover {
    background: #4a90e2;
    color: white;
    border-color: #4a90e2;
}
input, textarea {
    font-family: 'Inter', sans-serif;
    border: 2px solid #e2e8f0;
    border-radius: 10px;
    padding: 12px;
    background: #ffffff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
    color: #2d3748;
    font-size: 16px;
}
.gr-textbox textarea {
    resize: vertical;
    min-height: 150px;
}
.gr-progress {
    background: #edf2f7;
    border-radius: 12px;
    overflow: hidden;
    height: 30px;
}
.gr-progress > div {
    background: linear-gradient(90deg, #48bb78, #38a169);
    height: 100%;
    transition: width 0.5s ease;
}
.markdown-container {
    background: #ffffff;
    border-radius: 12px;
    padding: 25px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    margin-top: 20px;
    color: #2d3748;
}
.download-btn {
    background: #48bb78;
    color: white;
    border-radius: 10px;
    padding: 12px 24px;
    font-weight: 600;
    transition: all 0.3s ease;
    cursor: pointer;
}
.download-btn:hover {
    background: #38a169;
    transform: translateY(-3px);
}
"""

# Gradio UI with enhanced layout
with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as demo:
    gr.Markdown(
        """
        # πŸ“ AI Blog Reviewer
        Easily analyze your blog for grammar, legal issues, crude language, and sensitive topics.
        """
    )
    with gr.Row():
        with gr.Column(scale=2):
            with gr.Tabs():
                with gr.TabItem("Text Input"):
                    text_input = gr.Textbox(
                        lines=10,
                        label="Paste Your Blog Content",
                        placeholder="Enter your blog text here...",
                        elem_classes=["input-text"]
                    )
                with gr.TabItem("URL Input"):
                    url_input = gr.Textbox(
                        lines=1,
                        label="Enter Blog URL",
                        placeholder="https://example.com/blog",
                        elem_classes=["input-url"]
                    )
        with gr.Column(scale=1):
            gr.Markdown(
                """
                ### How It Works
                1. **Input**: Paste text or provide a URL.
                2. **Analysis**: AI checks grammar, legal issues, and more.
                3. **Report**: Download a detailed markdown report.
                """
            )
            status_button = gr.Button("Review Blog", elem_classes=["review-btn"])
    
    gr.Markdown("### πŸ“„ Review Report")
    with gr.Row():
        with gr.Column():
            report_output = gr.Markdown(elem_classes=["markdown-container"])
            download_btn = gr.File(label="Download Report", visible=False, elem_classes=["download-btn"])

    status_button.click(
        fn=review_blog,
        inputs=[text_input, url_input],
        outputs=[status_button, report_output, download_btn]
    )

demo.launch()