Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from duckduckgo_search import DDGS | |
| from datetime import datetime | |
| import os | |
| import asyncio | |
| import nest_asyncio | |
| from openai import OpenAI | |
| import traceback | |
| import re | |
| try: | |
| from agents import Agent, Runner, function_tool, OpenAIChatCompletionsModel | |
| AGENTS_AVAILABLE = True | |
| except Exception: | |
| print("WARNING: openai-agents package not fully functional, using fallback mode") | |
| AGENTS_AVAILABLE = False | |
| # Apply nest_asyncio to allow nested event loops | |
| nest_asyncio.apply() | |
| # Set up environment variables | |
| OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") | |
| # Get current date for default value | |
| default_date = datetime.now().strftime("%Y-%m-%d") | |
| # Configure OpenAI client | |
| client = OpenAI(api_key=OPENAI_API_KEY) | |
| # Function to make URLs clickable in Markdown | |
| def make_urls_clickable(text): | |
| # Find URLs in the text | |
| url_pattern = r'(https?://[^\s]+)' | |
| # Replace URLs with markdown links | |
| text_with_links = re.sub(url_pattern, r'[\1](\1)', text) | |
| return text_with_links | |
| # Function to format article output with better readability | |
| def format_articles(text): | |
| # Make URLs clickable | |
| text = make_urls_clickable(text) | |
| # Add better formatting for article titles (lines starting with #) | |
| text = re.sub(r'# (.+)', r'## \1', text) | |
| # Add horizontal rule between articles if not already present | |
| if "---" not in text: | |
| text = re.sub(r'\n\n(?=# )', r'\n\n---\n\n', text) | |
| # Enhance description and URL formatting | |
| text = re.sub(r'\*\*URL\*\*: (.+)', r'**Source**: \1', text) | |
| text = re.sub(r'\*\*Description\*\*:', r'**Summary**:', text) | |
| return text | |
| # Direct search function that doesn't depend on the agents package | |
| def direct_news_search(topic, language="English", search_date=None): | |
| """Search for news articles using DuckDuckGo directly""" | |
| if not search_date: | |
| search_date = datetime.now().strftime("%Y-%m") | |
| else: | |
| search_date = search_date[:7] # Just get YYYY-MM portion | |
| print(f"Running DuckDuckGo news search for {topic} in {language} for date {search_date}...") | |
| # Map common languages to their search keywords | |
| language_keywords = { | |
| "English": "", # Default, no special keyword needed | |
| "Hindi": "हिंदी", | |
| "Spanish": "español", | |
| "French": "français", | |
| "German": "deutsch", | |
| "Japanese": "日本語", | |
| "Chinese": "中文", | |
| "Russian": "русский", | |
| "Arabic": "العربية", | |
| "Portuguese": "português", | |
| "Italian": "italiano", | |
| "Dutch": "nederlands", | |
| "Korean": "한국어", | |
| "Turkish": "türkçe", | |
| "Kannada": "ಕನ್ನಡ", | |
| "Tamil": "தமிழ்", | |
| "Telugu": "తెలుగు", | |
| "Bengali": "বাংলা", | |
| "Marathi": "मराठी" | |
| } | |
| # Get language keyword if available | |
| lang_keyword = language_keywords.get(language, language) | |
| # Add language to search query if it's not English | |
| search_query = f"{topic} {lang_keyword} {search_date}" if language != "English" else f"{topic} {search_date}" | |
| try: | |
| # DuckDuckGo search | |
| ddg_api = DDGS() | |
| results = ddg_api.text(search_query, max_results=5) | |
| if results: | |
| news_results = "\n\n".join([f"# {result['title']}\n**URL**: {result['href']}\n**Description**: {result['body']}" for result in results]) | |
| return news_results | |
| else: | |
| return f"Could not find news results for {topic} in {language} for {search_date}." | |
| except Exception as e: | |
| return f"Error searching for news: {str(e)}" | |
| # Direct OpenAI API call | |
| def generate_with_openai(prompt): | |
| """Use OpenAI API directly to generate content""" | |
| try: | |
| response = client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.7, | |
| max_tokens=2000 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"Error with OpenAI API: {str(e)}" | |
| # Try to set up agents if available | |
| if AGENTS_AVAILABLE: | |
| try: | |
| # Define the model | |
| model = OpenAIChatCompletionsModel( | |
| model="gpt-4o-mini", | |
| openai_client=client | |
| ) | |
| # News search tool | |
| def get_news_articles(topic, language="English", search_date=None): | |
| return direct_news_search(topic, language, search_date) | |
| # Create agents | |
| news_agent = Agent( | |
| name="News Agent", | |
| 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.", | |
| tools=[get_news_articles], | |
| model=model | |
| ) | |
| editor_agent = Agent( | |
| name="Editor Assistant", | |
| 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.", | |
| model=model | |
| ) | |
| print("Successfully initialized agent-based workflow") | |
| except Exception as e: | |
| print(f"Failed to initialize agents: {e}") | |
| AGENTS_AVAILABLE = False | |
| # Workflow function for Gradio | |
| def fetch_and_edit_news(topic, language, search_date): | |
| """Process news request using agents if available, otherwise fall back to direct API calls""" | |
| try: | |
| # Try agent-based approach if available | |
| if AGENTS_AVAILABLE: | |
| try: | |
| print("Attempting to use agent-based workflow...") | |
| # Initialize event loop | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| # Run the news agent | |
| news_prompt = f"Get me the news about {topic} in {language} for date {search_date}" | |
| news_result = Runner.run_sync(news_agent, news_prompt) | |
| raw_news = news_result.final_output | |
| # Run the editor agent | |
| 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}" | |
| editor_result = Runner.run_sync(editor_agent, editor_prompt) | |
| edited_news = editor_result.final_output | |
| print("Agent-based workflow completed successfully") | |
| # Format the output with better readability | |
| return format_articles(edited_news) | |
| except Exception as agent_error: | |
| print(f"Agent-based workflow failed: {agent_error}") | |
| print(traceback.format_exc()) | |
| print("Falling back to direct API approach...") | |
| # Fall through to the direct approach | |
| else: | |
| print("Using direct API approach (agents not available)...") | |
| # Direct approach (used when agents fail or aren't available) | |
| # Step 1: Get news directly | |
| raw_news = direct_news_search(topic, language, search_date) | |
| if raw_news.startswith("Error") or raw_news.startswith("Could not find"): | |
| return raw_news | |
| # Step 2: Edit the news with OpenAI | |
| editor_prompt = f""" | |
| Please edit and reformat the following news into a cohesive, publication-ready format. | |
| Maintain the original language ({language}). | |
| Format with markdown, using # for headlines and --- to separate articles. | |
| Keep the original URLs and mark them as **URL**: [url]. | |
| {raw_news} | |
| """ | |
| edited_news = generate_with_openai(editor_prompt) | |
| # Format the output with better readability | |
| return format_articles(edited_news) | |
| except Exception as e: | |
| error_details = traceback.format_exc() | |
| print(f"Error in workflow: {e}") | |
| print(error_details) | |
| return f"Error processing your request: {str(e)}\n\nPlease check that your OpenAI API key is correctly set in the repository secrets." | |
| # Read custom CSS from file | |
| try: | |
| with open('style.css', 'r') as f: | |
| custom_css = f.read() | |
| except Exception as e: | |
| print(f"Warning: Could not read CSS file: {e}") | |
| # Fallback minimal CSS if file can't be read | |
| custom_css = """ | |
| .container { max-width: 900px; margin: auto; } | |
| .article-output { border: 1px solid #ddd; padding: 20px; } | |
| """ | |
| # Create Gradio interface with a custom theme | |
| with gr.Blocks(title="Multilingual AI News Generator", theme=gr.themes.Soft(primary_hue="blue"), css=custom_css) as demo: | |
| with gr.Column(elem_classes="container"): | |
| with gr.Column(elem_classes="header"): | |
| gr.Markdown("# Multilingual AI News Generator") | |
| gr.Markdown("Enter a topic, select a language, and choose a date to receive curated and edited news articles") | |
| with gr.Row(elem_classes="search-options"): | |
| topic_input = gr.Textbox( | |
| label="News Topic", | |
| placeholder="Enter a topic (e.g., AI, Climate Change, Sports)" | |
| ) | |
| language_dropdown = gr.Dropdown( | |
| choices=[ | |
| "English", "Hindi", "Spanish", "French", "German", | |
| "Japanese", "Chinese", "Russian", "Arabic", "Portuguese", | |
| "Italian", "Dutch", "Korean", "Turkish", "Kannada", | |
| "Tamil", "Telugu", "Bengali", "Marathi" | |
| ], | |
| label="Language", | |
| value="English" | |
| ) | |
| date_picker = gr.Textbox( | |
| label="Search Date", | |
| placeholder="YYYY-MM-DD", | |
| value=default_date | |
| ) | |
| submit_btn = gr.Button("Generate News Article", elem_classes="generate-btn") | |
| # Use Markdown for output to enable clickable links and better formatting | |
| output_box = gr.Markdown(elem_classes="article-output") | |
| submit_btn.click( | |
| fn=fetch_and_edit_news, | |
| inputs=[topic_input, language_dropdown, date_picker], | |
| outputs=output_box | |
| ) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo.launch() |