JaishnaCodz commited on
Commit
8162519
Β·
verified Β·
1 Parent(s): aac72ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -28
app.py CHANGED
@@ -10,6 +10,7 @@ import asyncio
10
 
11
  # Download NLTK data
12
  download('punkt')
 
13
 
14
  # Configure Gemini API using environment variable
15
  api_key = os.environ.get("GEMINI_API_KEY")
@@ -18,8 +19,18 @@ if not api_key:
18
 
19
  genai.configure(api_key=api_key)
20
 
21
- model = genai.GenerativeModel('gemini-1.5-flash')
22
-
 
 
 
 
 
 
 
 
 
 
23
  PROMPT = """
24
  You are an AI content reviewer. Analyze the provided text for the following:
25
  1. *Grammar Issues*: Identify and suggest corrections for grammatical errors.
@@ -33,14 +44,21 @@ Return the results in the following markdown format:
33
  - CONTENT: [Exact line or part of text with the issue]
34
  - SUGGESTION: [Suggested correction]
35
  - ISSUE: [Description of the issue]
 
 
 
 
 
36
  ## Legal Policy Violations
37
  - CONTENT: [Exact line or part of text with the issue]
38
  SUGGESTION: [Suggested action or correction]
39
  ISSUE: [Description of the legal violation]
 
40
  ## Crude/Abusive Language
41
  - [List instances of crude or abusive language or "None detected"]
42
  ## Sensitive Topics
43
  - [List instances of sensitive topics or "None detected"]
 
44
  """
45
 
46
  async def fetch_url_content(url):
@@ -48,41 +66,73 @@ async def fetch_url_content(url):
48
  response = requests.get(url, timeout=10)
49
  response.raise_for_status()
50
  soup = BeautifulSoup(response.text, 'html.parser')
 
51
  content = ' '.join([p.get_text(strip=True) for p in soup.find_all(['p', 'article', 'div'])])
52
  return content if content else "No readable content found on the page."
53
  except Exception as e:
54
  return f"Error fetching URL: {str(e)}"
55
 
56
  async def review_blog(text_input, url_input):
 
 
 
 
57
  if text_input and not url_input:
 
58
  input_text = text_input
59
  elif url_input and not text_input:
60
- input_text = await fetch_url_content(url_input)
61
- if input_text.startswith("Error"):
62
- return "Review Blog", input_text, gr.update(visible=False), ""
63
  else:
64
- return "Review Blog", "Error: Please provide input in either the Text or URL tab, but not both.", gr.update(visible=False), ""
 
 
 
 
65
 
66
  try:
67
- sentences = sent_tokenize(input_text)
68
- analysis_text = "\n".join(sentences)
69
- response = await asyncio.to_thread(model.generate_content, PROMPT + "\n\nText to analyze:\n" + analysis_text)
70
- report = response.text.strip()
71
-
72
- suggestions = re.findall(r'- CONTENT: (.*?)\n\s*SUGGESTION: (.*?)\n\s*ISSUE: (.*?)\n', report, re.DOTALL)
73
- highlighted = input_text
74
- for content, suggestion, issue in suggestions:
75
- highlighted = highlighted.replace(content, f'<span style="background-color: #ffcccc;" title="{issue} | Suggested: {suggestion}">{content}</span>')
76
-
77
- with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False, encoding='utf-8') as temp_file:
78
- temp_file.write(report)
79
- temp_file_path = temp_file.name
80
-
81
- report = f"**Report generated, please scroll down to view.**\n\n{report}"
82
- return "Review Blog", report, gr.update(visible=True, value=temp_file_path), highlighted
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  except asyncio.TimeoutError:
84
- return "Timeout", "Error: Process timed out after 30 seconds.", gr.update(visible=False), ""
85
 
 
86
  custom_css = """
87
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
88
  .gradio-container {
@@ -106,6 +156,22 @@ custom_css = """
106
  opacity: 0.7;
107
  cursor: not-allowed;
108
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  .tab-nav button {
110
  font-family: 'Inter', sans-serif;
111
  font-weight: 500;
@@ -115,9 +181,10 @@ input, textarea {
115
  }
116
  """
117
 
 
118
  with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as demo:
119
  gr.Markdown("# πŸ“ AI Blog Reviewer")
120
- gr.Markdown("Enter blog text or a URL to review. Issues will be highlighted in the content and summarized in a downloadable report.")
121
 
122
  with gr.Tabs():
123
  with gr.TabItem("Text"):
@@ -126,16 +193,16 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as demo:
126
  url_input = gr.Textbox(lines=1, label="Blog URL", placeholder="Enter the blog URL here...")
127
 
128
  status_button = gr.Button(value="Review Blog", elem_classes=["review-btn"])
 
129
  gr.Markdown("### πŸ“„ Review Report")
130
  report_output = gr.Markdown()
131
  download_btn = gr.File(label="Download Report", visible=False)
132
- gr.Markdown("### πŸ” Highlighted Blog Content")
133
- highlighted_text = gr.HTML()
134
 
 
135
  status_button.click(
136
  fn=review_blog,
137
  inputs=[text_input, url_input],
138
- outputs=[status_button, report_output, download_btn, highlighted_text]
139
  )
140
 
141
- demo.launch()
 
10
 
11
  # Download NLTK data
12
  download('punkt')
13
+ download('punkt_tab')
14
 
15
  # Configure Gemini API using environment variable
16
  api_key = os.environ.get("GEMINI_API_KEY")
 
19
 
20
  genai.configure(api_key=api_key)
21
 
22
+ # Use gemini-1.5-flash for faster and more accessible text analysis
23
+ try:
24
+ model = genai.GenerativeModel('gemini-1.5-flash')
25
+ except Exception as e:
26
+ # Fallback: List available models if the specified model is not found
27
+ print(f"Error initializing model: {str(e)}")
28
+ print("Available models:")
29
+ for m in genai.list_models():
30
+ print(m.name)
31
+ raise ValueError("Failed to initialize gemini-1.5-flash. Check available models above and update the model name.")
32
+
33
+ # Prompt for Gemini to analyze text with specified output format
34
  PROMPT = """
35
  You are an AI content reviewer. Analyze the provided text for the following:
36
  1. *Grammar Issues*: Identify and suggest corrections for grammatical errors.
 
44
  - CONTENT: [Exact line or part of text with the issue]
45
  - SUGGESTION: [Suggested correction]
46
  - ISSUE: [Description of the issue]
47
+ 2. [Heading of next issue]
48
+ - CONTENT: [Exact line or part of text with the issue]
49
+ - SUGGESTION: [Suggested correction]
50
+ - ISSUE: [Description of the issue]
51
+ [Continue numbering for additional issues or state "None detected"]
52
  ## Legal Policy Violations
53
  - CONTENT: [Exact line or part of text with the issue]
54
  SUGGESTION: [Suggested action or correction]
55
  ISSUE: [Description of the legal violation]
56
+ [Or state "None detected"]
57
  ## Crude/Abusive Language
58
  - [List instances of crude or abusive language or "None detected"]
59
  ## Sensitive Topics
60
  - [List instances of sensitive topics or "None detected"]
61
+ 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.
62
  """
63
 
64
  async def fetch_url_content(url):
 
66
  response = requests.get(url, timeout=10)
67
  response.raise_for_status()
68
  soup = BeautifulSoup(response.text, 'html.parser')
69
+ # Extract text from common content tags
70
  content = ' '.join([p.get_text(strip=True) for p in soup.find_all(['p', 'article', 'div'])])
71
  return content if content else "No readable content found on the page."
72
  except Exception as e:
73
  return f"Error fetching URL: {str(e)}"
74
 
75
  async def review_blog(text_input, url_input):
76
+ # Start loading effect immediately
77
+ button_text = "Processing..."
78
+
79
+ # Determine input type based on which field is populated
80
  if text_input and not url_input:
81
+ input_type = "Text"
82
  input_text = text_input
83
  elif url_input and not text_input:
84
+ input_type = "URL"
85
+ input_text = url_input
 
86
  else:
87
+ return "Review Blog", "Error: Please provide input in either the Text or URL tab, but not both.", gr.update(visible=False)
88
+
89
+ # Handle empty input
90
+ if not input_text:
91
+ return "Review Blog", "Error: No input provided.", gr.update(visible=False)
92
 
93
  try:
94
+ async with asyncio.timeout(30): # 30-second timeout for entire process
95
+ # Handle URL input
96
+ if input_type == "URL":
97
+ button_text = "Fetching content..."
98
+ input_text = await fetch_url_content(input_text)
99
+ if input_text.startswith("Error"):
100
+ return "Review Blog", input_text, gr.update(visible=False)
101
+
102
+ # Tokenize input for analysis
103
+ sentences = sent_tokenize(input_text)
104
+ analysis_text = "\n".join(sentences)
105
+
106
+ # Update button for API call
107
+ button_text = "Generating report..."
108
+ try:
109
+ response = await asyncio.to_thread(model.generate_content, PROMPT + "\n\nText to analyze:\n" + analysis_text)
110
+ report = response.text.strip()
111
+ # Ensure the response is markdown by removing any code fences
112
+ report = re.sub(r'^markdown\n|$', '', report, flags=re.MULTILINE)
113
+ except Exception as e:
114
+ report = f"Error analyzing content with Gemini: {str(e)}. Please check your API key, network connection, or model availability."
115
+ # Fallback: List available models for debugging
116
+ print("Available models:")
117
+ for m in genai.list_models():
118
+ print(m.name)
119
+ return "Review Blog", report, gr.update(visible=False)
120
+
121
+ # Create a temporary file to store the report
122
+ try:
123
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False, encoding='utf-8') as temp_file:
124
+ temp_file.write(report)
125
+ temp_file_path = temp_file.name
126
+ # Add note to scroll to report
127
+ report = f"**Report generated, please scroll down to view.**\n\n{report}"
128
+ return "Review Blog", report, gr.update(visible=True, value=temp_file_path)
129
+ except Exception as e:
130
+ return "Review Blog", f"Error creating temporary file: {str(e)}", gr.update(visible=False)
131
+
132
  except asyncio.TimeoutError:
133
+ return "Timeout", "Error: Process timed out after 30 seconds.", gr.update(visible=False)
134
 
135
+ # Custom CSS for hover effect, loading state, and Inter font
136
  custom_css = """
137
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
138
  .gradio-container {
 
156
  opacity: 0.7;
157
  cursor: not-allowed;
158
  }
159
+ .review-btn:disabled::before {
160
+ content: '';
161
+ display: inline-block;
162
+ width: 16px;
163
+ height: 16px;
164
+ border: 2px solid #fff;
165
+ border-radius: 50%;
166
+ border-top-color: transparent;
167
+ animation: spin 1s linear infinite;
168
+ margin-right: 8px;
169
+ vertical-align: middle;
170
+ }
171
+ @keyframes spin {
172
+ 0% { transform: rotate(0deg); }
173
+ 100% { transform: rotate(360deg); }
174
+ }
175
  .tab-nav button {
176
  font-family: 'Inter', sans-serif;
177
  font-weight: 500;
 
181
  }
182
  """
183
 
184
+ # Gradio UI with Tabs
185
  with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as demo:
186
  gr.Markdown("# πŸ“ AI Blog Reviewer")
187
+ gr.Markdown("Enter blog text or a URL to review for grammar, legal issues, crude language, and sensitive topics. The report is generated in markdown format.")
188
 
189
  with gr.Tabs():
190
  with gr.TabItem("Text"):
 
193
  url_input = gr.Textbox(lines=1, label="Blog URL", placeholder="Enter the blog URL here...")
194
 
195
  status_button = gr.Button(value="Review Blog", elem_classes=["review-btn"])
196
+
197
  gr.Markdown("### πŸ“„ Review Report")
198
  report_output = gr.Markdown()
199
  download_btn = gr.File(label="Download Report", visible=False)
 
 
200
 
201
+ # Bind the review button to process inputs
202
  status_button.click(
203
  fn=review_blog,
204
  inputs=[text_input, url_input],
205
+ outputs=[status_button, report_output, download_btn]
206
  )
207
 
208
+ demo.launch()