Update app.py
Browse files
app.py
CHANGED
@@ -4,8 +4,9 @@ from datetime import datetime
|
|
4 |
import os
|
5 |
import asyncio
|
6 |
import nest_asyncio
|
7 |
-
from openai import OpenAI
|
8 |
import traceback
|
|
|
9 |
|
10 |
try:
|
11 |
from agents import Agent, Runner, function_tool, OpenAIChatCompletionsModel
|
@@ -18,8 +19,7 @@ except Exception:
|
|
18 |
nest_asyncio.apply()
|
19 |
|
20 |
# Set up environment variables
|
21 |
-
|
22 |
-
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") # You'll need to add this to HF Spaces secrets
|
23 |
|
24 |
# Get current date for default value
|
25 |
default_date = datetime.now().strftime("%Y-%m-%d")
|
@@ -27,14 +27,40 @@ default_date = datetime.now().strftime("%Y-%m-%d")
|
|
27 |
# Configure OpenAI client
|
28 |
client = OpenAI(api_key=OPENAI_API_KEY)
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
# Direct search function that doesn't depend on the agents package
|
31 |
def direct_news_search(topic, language="English", search_date=None):
|
32 |
"""Search for news articles using DuckDuckGo directly"""
|
33 |
-
# Use provided date or default to current date
|
34 |
if not search_date:
|
35 |
search_date = datetime.now().strftime("%Y-%m")
|
36 |
else:
|
37 |
-
# Convert from date picker format (YYYY-MM-DD) to YYYY-MM format
|
38 |
search_date = search_date[:7] # Just get YYYY-MM portion
|
39 |
|
40 |
print(f"Running DuckDuckGo news search for {topic} in {language} for date {search_date}...")
|
@@ -73,7 +99,7 @@ def direct_news_search(topic, language="English", search_date=None):
|
|
73 |
ddg_api = DDGS()
|
74 |
results = ddg_api.text(search_query, max_results=5)
|
75 |
if results:
|
76 |
-
news_results = "\n\n".join([f"
|
77 |
return news_results
|
78 |
else:
|
79 |
return f"Could not find news results for {topic} in {language} for {search_date}."
|
@@ -111,14 +137,14 @@ if AGENTS_AVAILABLE:
|
|
111 |
# Create agents
|
112 |
news_agent = Agent(
|
113 |
name="News Agent",
|
114 |
-
instructions="You provide the latest news articles for a given topic using DuckDuckGo search. You can search for news in different languages when specified.",
|
115 |
tools=[get_news_articles],
|
116 |
model=model
|
117 |
)
|
118 |
|
119 |
editor_agent = Agent(
|
120 |
name="Editor Assistant",
|
121 |
-
instructions="Rewrite and give me a news article ready for publishing. Each news story should be in a separate section. Maintain the original language of the news stories. If the content is in a language other than English, edit and format in that same language.",
|
122 |
model=model
|
123 |
)
|
124 |
|
@@ -146,12 +172,13 @@ def fetch_and_edit_news(topic, language, search_date):
|
|
146 |
raw_news = news_result.final_output
|
147 |
|
148 |
# Run the editor agent
|
149 |
-
editor_prompt = f"Please edit the following news in {language} language. Maintain the original language: \n\n{raw_news}"
|
150 |
editor_result = Runner.run_sync(editor_agent, editor_prompt)
|
151 |
edited_news = editor_result.final_output
|
152 |
|
153 |
print("Agent-based workflow completed successfully")
|
154 |
-
|
|
|
155 |
|
156 |
except Exception as agent_error:
|
157 |
print(f"Agent-based workflow failed: {agent_error}")
|
@@ -171,14 +198,17 @@ def fetch_and_edit_news(topic, language, search_date):
|
|
171 |
# Step 2: Edit the news with OpenAI
|
172 |
editor_prompt = f"""
|
173 |
Please edit and reformat the following news into a cohesive, publication-ready format.
|
174 |
-
Maintain the original language ({language}).
|
175 |
-
|
|
|
176 |
|
177 |
{raw_news}
|
178 |
"""
|
179 |
|
180 |
edited_news = generate_with_openai(editor_prompt)
|
181 |
-
|
|
|
|
|
182 |
|
183 |
except Exception as e:
|
184 |
error_details = traceback.format_exc()
|
@@ -186,42 +216,56 @@ def fetch_and_edit_news(topic, language, search_date):
|
|
186 |
print(error_details)
|
187 |
return f"Error processing your request: {str(e)}\n\nPlease check that your OpenAI API key is correctly set in the repository secrets."
|
188 |
|
189 |
-
#
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
value="English"
|
208 |
-
)
|
209 |
-
# Use Date input instead of Datepicker
|
210 |
-
date_picker = gr.components.Textbox(
|
211 |
-
label="Search Date",
|
212 |
-
placeholder="YYYY-MM-DD",
|
213 |
-
value=default_date
|
214 |
-
)
|
215 |
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
# Launch the app
|
227 |
if __name__ == "__main__":
|
|
|
4 |
import os
|
5 |
import asyncio
|
6 |
import nest_asyncio
|
7 |
+
from openai import OpenAI
|
8 |
import traceback
|
9 |
+
import re
|
10 |
|
11 |
try:
|
12 |
from agents import Agent, Runner, function_tool, OpenAIChatCompletionsModel
|
|
|
19 |
nest_asyncio.apply()
|
20 |
|
21 |
# Set up environment variables
|
22 |
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
|
|
|
23 |
|
24 |
# Get current date for default value
|
25 |
default_date = datetime.now().strftime("%Y-%m-%d")
|
|
|
27 |
# Configure OpenAI client
|
28 |
client = OpenAI(api_key=OPENAI_API_KEY)
|
29 |
|
30 |
+
# Function to make URLs clickable in Markdown
|
31 |
+
def make_urls_clickable(text):
|
32 |
+
# Find URLs in the text
|
33 |
+
url_pattern = r'(https?://[^\s]+)'
|
34 |
+
|
35 |
+
# Replace URLs with markdown links
|
36 |
+
text_with_links = re.sub(url_pattern, r'[\1](\1)', text)
|
37 |
+
|
38 |
+
return text_with_links
|
39 |
+
|
40 |
+
# Function to format article output with better readability
|
41 |
+
def format_articles(text):
|
42 |
+
# Make URLs clickable
|
43 |
+
text = make_urls_clickable(text)
|
44 |
+
|
45 |
+
# Add better formatting for article titles (lines starting with #)
|
46 |
+
text = re.sub(r'# (.+)', r'## \1', text)
|
47 |
+
|
48 |
+
# Add horizontal rule between articles if not already present
|
49 |
+
if "---" not in text:
|
50 |
+
text = re.sub(r'\n\n(?=# )', r'\n\n---\n\n', text)
|
51 |
+
|
52 |
+
# Enhance description and URL formatting
|
53 |
+
text = re.sub(r'\*\*URL\*\*: (.+)', r'**Source**: \1', text)
|
54 |
+
text = re.sub(r'\*\*Description\*\*:', r'**Summary**:', text)
|
55 |
+
|
56 |
+
return text
|
57 |
+
|
58 |
# Direct search function that doesn't depend on the agents package
|
59 |
def direct_news_search(topic, language="English", search_date=None):
|
60 |
"""Search for news articles using DuckDuckGo directly"""
|
|
|
61 |
if not search_date:
|
62 |
search_date = datetime.now().strftime("%Y-%m")
|
63 |
else:
|
|
|
64 |
search_date = search_date[:7] # Just get YYYY-MM portion
|
65 |
|
66 |
print(f"Running DuckDuckGo news search for {topic} in {language} for date {search_date}...")
|
|
|
99 |
ddg_api = DDGS()
|
100 |
results = ddg_api.text(search_query, max_results=5)
|
101 |
if results:
|
102 |
+
news_results = "\n\n".join([f"# {result['title']}\n**URL**: {result['href']}\n**Description**: {result['body']}" for result in results])
|
103 |
return news_results
|
104 |
else:
|
105 |
return f"Could not find news results for {topic} in {language} for {search_date}."
|
|
|
137 |
# Create agents
|
138 |
news_agent = Agent(
|
139 |
name="News Agent",
|
140 |
+
instructions="You provide the latest news articles for a given topic using DuckDuckGo search. You can search for news in different languages when specified. Format each article with a # heading.",
|
141 |
tools=[get_news_articles],
|
142 |
model=model
|
143 |
)
|
144 |
|
145 |
editor_agent = Agent(
|
146 |
name="Editor Assistant",
|
147 |
+
instructions="Rewrite and give me a news article ready for publishing. Each news story should be in a separate section with a clear headline (use # for headlines). Maintain the original language of the news stories. If the content is in a language other than English, edit and format in that same language. Keep the original URLs and mark them as **URL**: [url]. Use --- to separate articles.",
|
148 |
model=model
|
149 |
)
|
150 |
|
|
|
172 |
raw_news = news_result.final_output
|
173 |
|
174 |
# Run the editor agent
|
175 |
+
editor_prompt = f"Please edit the following news in {language} language. Maintain the original language and URLs. Format with markdown, using # for headlines and --- to separate articles: \n\n{raw_news}"
|
176 |
editor_result = Runner.run_sync(editor_agent, editor_prompt)
|
177 |
edited_news = editor_result.final_output
|
178 |
|
179 |
print("Agent-based workflow completed successfully")
|
180 |
+
# Format the output with better readability
|
181 |
+
return format_articles(edited_news)
|
182 |
|
183 |
except Exception as agent_error:
|
184 |
print(f"Agent-based workflow failed: {agent_error}")
|
|
|
198 |
# Step 2: Edit the news with OpenAI
|
199 |
editor_prompt = f"""
|
200 |
Please edit and reformat the following news into a cohesive, publication-ready format.
|
201 |
+
Maintain the original language ({language}).
|
202 |
+
Format with markdown, using # for headlines and --- to separate articles.
|
203 |
+
Keep the original URLs and mark them as **URL**: [url].
|
204 |
|
205 |
{raw_news}
|
206 |
"""
|
207 |
|
208 |
edited_news = generate_with_openai(editor_prompt)
|
209 |
+
|
210 |
+
# Format the output with better readability
|
211 |
+
return format_articles(edited_news)
|
212 |
|
213 |
except Exception as e:
|
214 |
error_details = traceback.format_exc()
|
|
|
216 |
print(error_details)
|
217 |
return f"Error processing your request: {str(e)}\n\nPlease check that your OpenAI API key is correctly set in the repository secrets."
|
218 |
|
219 |
+
# Read custom CSS from file
|
220 |
+
try:
|
221 |
+
with open('style.css', 'r') as f:
|
222 |
+
custom_css = f.read()
|
223 |
+
except Exception as e:
|
224 |
+
print(f"Warning: Could not read CSS file: {e}")
|
225 |
+
# Fallback minimal CSS if file can't be read
|
226 |
+
custom_css = """
|
227 |
+
.container { max-width: 900px; margin: auto; }
|
228 |
+
.article-output { border: 1px solid #ddd; padding: 20px; }
|
229 |
+
"""
|
230 |
+
|
231 |
+
# Create Gradio interface with a custom theme
|
232 |
+
with gr.Blocks(title="Multilingual AI News Generator", theme=gr.themes.Soft(primary_hue="blue"), css=custom_css) as demo:
|
233 |
+
with gr.Column(elem_classes="container"):
|
234 |
+
with gr.Column(elem_classes="header"):
|
235 |
+
gr.Markdown("# Multilingual AI News Generator")
|
236 |
+
gr.Markdown("Enter a topic, select a language, and choose a date to receive curated and edited news articles")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
|
238 |
+
with gr.Row(elem_classes="search-options"):
|
239 |
+
topic_input = gr.Textbox(
|
240 |
+
label="News Topic",
|
241 |
+
placeholder="Enter a topic (e.g., AI, Climate Change, Sports)"
|
242 |
+
)
|
243 |
+
language_dropdown = gr.Dropdown(
|
244 |
+
choices=[
|
245 |
+
"English", "Hindi", "Spanish", "French", "German",
|
246 |
+
"Japanese", "Chinese", "Russian", "Arabic", "Portuguese",
|
247 |
+
"Italian", "Dutch", "Korean", "Turkish", "Kannada",
|
248 |
+
"Tamil", "Telugu", "Bengali", "Marathi"
|
249 |
+
],
|
250 |
+
label="Language",
|
251 |
+
value="English"
|
252 |
+
)
|
253 |
+
date_picker = gr.Textbox(
|
254 |
+
label="Search Date",
|
255 |
+
placeholder="YYYY-MM-DD",
|
256 |
+
value=default_date
|
257 |
+
)
|
258 |
+
|
259 |
+
submit_btn = gr.Button("Generate News Article", elem_classes="generate-btn")
|
260 |
+
|
261 |
+
# Use Markdown for output to enable clickable links and better formatting
|
262 |
+
output_box = gr.Markdown(elem_classes="article-output")
|
263 |
+
|
264 |
+
submit_btn.click(
|
265 |
+
fn=fetch_and_edit_news,
|
266 |
+
inputs=[topic_input, language_dropdown, date_picker],
|
267 |
+
outputs=output_box
|
268 |
+
)
|
269 |
|
270 |
# Launch the app
|
271 |
if __name__ == "__main__":
|