JaishnaCodz's picture
Update app.py
d233c20 verified
raw
history blame
8.64 kB
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
# 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:
# Fallback: List available models if the specified model is not found
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')
# Extract text from common content tags
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):
# Start loading effect immediately
button_text = "Processing..."
# Determine input type based on which field is populated
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)
# Handle empty input
if not input_text:
return "Review Blog", "Error: No input provided.", gr.update(visible=False)
try:
async with asyncio.timeout(30): # 30-second timeout for entire process
# Handle URL input
if input_type == "URL":
button_text = "Fetching content..."
input_text = await fetch_url_content(input_text)
if input_text.startswith("Error"):
return "Review Blog", input_text, gr.update(visible=False)
# Tokenize input for analysis
sentences = sent_tokenize(input_text)
analysis_text = "\n".join(sentences)
# Update button for API call
button_text = "Generating report..."
try:
response = await asyncio.to_thread(model.generate_content, PROMPT + "\n\nText to analyze:\n" + analysis_text)
report = response.text.strip()
# Ensure the response is markdown by removing any code fences
report = re.sub(r'^markdown\n|$', '', report, flags=re.MULTILINE)
except Exception as e:
report = f"Error analyzing content with Gemini: {str(e)}. Please check your API key, network connection, or model availability."
# Fallback: List available models for debugging
print("Available models:")
for m in genai.list_models():
print(m.name)
return "Review Blog", report, gr.update(visible=False)
# Create a temporary file to store the report
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
# Add note to scroll to report
report = f"**Report generated, please scroll down to view.**\n\n{report}"
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)
except asyncio.TimeoutError:
return "Timeout", "Error: Process timed out after 30 seconds.", gr.update(visible=False)
# Custom CSS for hover effect, loading state, and Inter font
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
.gradio-container {
font-family: 'Inter', sans-serif !important;
background-color: #f9f9f9;
}
.review-btn {
transition: all 0.3s ease;
font-weight: 600;
font-size: 16px;
background-color: #1f2937;
color: white;
border-radius: 12px;
padding: 12px 24px;
margin-top: 10px;
}
.review-btn:hover {
background-color: #10b981;
transform: scale(1.03);
}
.review-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.review-btn:disabled::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
border: 3px solid #fff;
border-radius: 50%;
border-top-color: transparent;
animation: spin 1s linear infinite;
margin-right: 8px;
vertical-align: middle;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
input, textarea {
font-family: 'Inter', sans-serif;
font-size: 15px;
padding: 10px;
border-radius: 8px;
}
"""
with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as demo:
gr.Markdown("## πŸ“ AI Blog Reviewer", elem_id="title")
gr.Markdown(
"""
<div style="font-size: 16px; color: #444; line-height: 1.6;">
πŸ“Œ Enter your blog text or a blog URL below.<br>
βœ… The AI will check for grammar, legal issues, crude language, and sensitive content.<br>
🧾 A detailed report will be shown and available to download.
</div>
""",
elem_id="description"
)
with gr.Tabs():
with gr.TabItem("✍️ Text Input"):
text_input = gr.Textbox(
lines=10,
label="Your Blog Content",
placeholder="Paste your blog text here...",
show_label=True
)
with gr.TabItem("🌐 URL Input"):
url_input = gr.Textbox(
lines=1,
label="Blog URL",
placeholder="Enter the blog URL here...",
show_label=True
)
status_button = gr.Button(value="πŸš€ Review Blog", elem_classes=["review-btn"])
gr.Markdown("### πŸ“„ Review Report")
report_output = gr.Markdown(elem_id="report-markdown")
download_btn = gr.File(label="πŸ“₯ Download Markdown Report", visible=False)
# Bind button click
status_button.click(
fn=review_blog,
inputs=[text_input, url_input],
outputs=[status_button, report_output, download_btn]
)
demo.launch()