NoticIA-Col/Generador-Noticias
1
1import os2import openai3import whisper4import tempfile5import gradio as gr6from pydub import AudioSegment7import fitz # PyMuPDF for handling PDFs8import docx # For handling .docx files9import pandas as pd # For handling .xlsx and .csv files10import requests11from bs4 import BeautifulSoup12from moviepy.editor import VideoFileClip13import yt_dlp14import logging15 16# Configure logging17logging.basicConfig(level=logging.INFO)18logger = logging.getLogger(__name__)19 20# Configure your OpenAI API key21openai.api_key = os.getenv("OPENAI_API_KEY")22 23# Load the highest quality Whisper model once24model = whisper.load_model("large")25 26def download_social_media_video(url):27 """Downloads a video from social media."""28 ydl_opts = {29 'format': 'bestaudio/best',30 'postprocessors': [{31 'key': 'FFmpegExtractAudio',32 'preferredcodec': 'mp3',33 'preferredquality': '192',34 }],35 'outtmpl': '%(id)s.%(ext)s',36 }37 try:38 with yt_dlp.YoutubeDL(ydl_opts) as ydl:39 info_dict = ydl.extract_info(url, download=True)40 audio_file = f"{info_dict['id']}.mp3"41 logger.info(f"Video successfully downloaded: {audio_file}")42 return audio_file43 except Exception as e:44 logger.error(f"Error downloading video: {str(e)}")45 raise46 47def convert_video_to_audio(video_file):48 """Converts a video file to audio."""49 try:50 video = VideoFileClip(video_file)51 with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:52 video.audio.write_audiofile(temp_file.name)53 logger.info(f"Video converted to audio: {temp_file.name}")54 return temp_file.name55 except Exception as e:56 logger.error(f"Error converting video to audio: {str(e)}")57 raise58 59def preprocess_audio(audio_file):60 """Preprocesses the audio file to improve quality."""61 try:62 audio = AudioSegment.from_file(audio_file)63 audio = audio.apply_gain(-audio.dBFS + (-20))64 with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:65 audio.export(temp_file.name, format="mp3")66 logger.info(f"Audio preprocessed: {temp_file.name}")67 return temp_file.name68 except Exception as e:69 logger.error(f"Error preprocessing audio file: {str(e)}")70 raise71 72def transcribe_audio(file):73 """Transcribes an audio or video file."""74 try:75 if isinstance(file, str) and file.startswith('http'):76 logger.info(f"Downloading social media video: {file}")77 file_path = download_social_media_video(file)78 elif isinstance(file, str) and file.lower().endswith(('.mp4', '.avi', '.mov', '.mkv')):79 logger.info(f"Converting local video to audio: {file}")80 file_path = convert_video_to_audio(file)81 else:82 logger.info(f"Preprocessing audio file: {file}")83 file_path = preprocess_audio(file)84 85 logger.info(f"Transcribing audio: {file_path}")86 result = model.transcribe(file_path)87 transcription = result.get("text", "Error in transcription")88 logger.info(f"Transcription completed: {transcription[:50]}...")89 return transcription90 except Exception as e:91 logger.error(f"Error processing file: {str(e)}")92 return f"Error processing file: {str(e)}"93 94def read_document(document_path):95 """Reads content from PDF, DOCX, XLSX or CSV documents."""96 try:97 if document_path.endswith(".pdf"):98 doc = fitz.open(document_path)99 return "\n".join([page.get_text() for page in doc])100 elif document_path.endswith(".docx"):101 doc = docx.Document(document_path)102 return "\n".join([paragraph.text for paragraph in doc.paragraphs])103 elif document_path.endswith(".xlsx"):104 return pd.read_excel(document_path).to_string()105 elif document_path.endswith(".csv"):106 return pd.read_csv(document_path).to_string()107 else:108 return "Unsupported file type. Please upload a PDF, DOCX, XLSX or CSV document."109 except Exception as e:110 return f"Error reading document: {str(e)}"111 112def read_url(url):113 """Reads content from a URL."""114 try:115 response = requests.get(url)116 response.raise_for_status()117 soup = BeautifulSoup(response.content, 'html.parser')118 return soup.get_text()119 except Exception as e:120 return f"Error reading URL: {str(e)}"121 122def process_social_content(url):123 """Processes content from a social media URL, handling both text and video."""124 try:125 # First, try to read content as text126 text_content = read_url(url)127 128 # Then, try to process as video129 try:130 video_content = transcribe_audio(url)131 except Exception:132 video_content = None133 134 return {135 "text": text_content,136 "video": video_content137 }138 except Exception as e:139 logger.error(f"Error processing social content: {str(e)}")140 return None141 142def generate_news(instructions, facts, size, tone, *args):143 """Generates a news article from instructions, facts, URLs, documents, transcriptions, and social media content."""144 knowledge_base = {145 "instructions": instructions,146 "facts": facts,147 "document_content": [],148 "audio_data": [],149 "url_content": [],150 "social_content": []151 }152 num_audios = 5 * 3 # 5 audios/videos * 3 fields (file, name, position)153 num_social_urls = 3 * 3 # 3 social media URLs * 3 fields (URL, name, context)154 num_urls = 5 # 5 general URLs155 audios = args[:num_audios]156 social_urls = args[num_audios:num_audios+num_social_urls]157 urls = args[num_audios+num_social_urls:num_audios+num_social_urls+num_urls]158 documents = args[num_audios+num_social_urls+num_urls:]159 160 for url in urls:161 if url:162 knowledge_base["url_content"].append(read_url(url))163 164 for document in documents:165 if document is not None:166 knowledge_base["document_content"].append(read_document(document.name))167 168 for i in range(0, len(audios), 3):169 audio_file, name, position = audios[i:i+3]170 if audio_file is not None:171 knowledge_base["audio_data"].append({"audio": audio_file, "name": name, "position": position})172 173 for i in range(0, len(social_urls), 3):174 social_url, social_name, social_context = social_urls[i:i+3]175 if social_url:176 social_content = process_social_content(social_url)177 if social_content:178 knowledge_base["social_content"].append({179 "url": social_url,180 "name": social_name,181 "context": social_context,182 "text": social_content["text"],183 "video": social_content["video"]184 })185 logger.info(f"Social media content processed: {social_url}")186 187 transcriptions_text, raw_transcriptions = "", ""188 189 for idx, data in enumerate(knowledge_base["audio_data"]):190 if data["audio"] is not None:191 transcription = transcribe_audio(data["audio"])192 transcription_text = f'"{transcription}" - {data["name"]}, {data["position"]}'193 raw_transcription = f'[Audio/Video {idx + 1}]: "{transcription}" - {data["name"]}, {data["position"]}'194 transcriptions_text += transcription_text + "\n"195 raw_transcriptions += raw_transcription + "\n\n"196 197 for data in knowledge_base["social_content"]:198 if data["text"]:199 transcription_text = f'[Social media text]: "{data["text"][:200]}..." - {data["name"]}, {data["context"]}'200 transcriptions_text += transcription_text + "\n"201 raw_transcriptions += transcription_text + "\n\n"202 if data["video"]:203 transcription_video = f'[Social media video]: "{data["video"]}" - {data["name"]}, {data["context"]}'204 transcriptions_text += transcription_video + "\n"205 raw_transcriptions += transcription_video + "\n\n"206 207 document_content = "\n\n".join(knowledge_base["document_content"])208 url_content = "\n\n".join(knowledge_base["url_content"])209 210 internal_prompt = """211 Instructions for the model:212 - Follow news article principles: answer the 5 Ws in the first paragraph (Who?, What?, When?, Where?, Why?).213 - Ensure at least 80% of quotes are direct and in quotation marks.214 - The remaining 20% can be indirect quotes.215 - Don't invent new information.216 - Be rigorous with provided facts.217 - When processing uploaded documents, extract and highlight important quotes and testimonials from sources.218 - When processing uploaded documents, extract and highlight key figures.219 - Avoid using the date at the beginning of the news body. Start directly with the 5Ws.220 - Include social media content relevantly, citing the source and providing proper context.221 - Make sure to relate the provided context for social media content with its corresponding transcription or text.222 """223 224 prompt = f"""225 {internal_prompt}226 Write a news article with the following information, including a title, a 15-word hook (additional information that complements the title), and the content body with {size} words. The tone should be {tone}.227 Instructions: {knowledge_base["instructions"]}228 Facts: {knowledge_base["facts"]}229 Additional content from documents: {document_content}230 Additional content from URLs: {url_content}231 Use the following transcriptions as direct and indirect quotes (without changing or inventing content):232 {transcriptions_text}233 """234 235 try:236 response = openai.ChatCompletion.create(237 model="gpt-4o-mini",238 messages=[{"role": "user", "content": prompt}],239 temperature=0.1240 )241 news = response['choices'][0]['message']['content']242 return news, raw_transcriptions243 except Exception as e:244 logger.error(f"Error generating news article: {str(e)}")245 return f"Error generating news article: {str(e)}", ""246 247with gr.Blocks() as demo:248 gr.Markdown("## All-in-One News Generator")249 250 # Add tool description and attribution251 gr.Markdown("""252 ### About this tool253 254 This AI-powered news generator helps journalists and content creators produce news articles by processing multiple types of input:255 - Audio and video files with automatic transcription256 - Social media content257 - Documents (PDF, DOCX, XLSX, CSV)258 - Web URLs259 260 The tool uses advanced AI to generate well-structured news articles following journalistic principles and maintaining the integrity of source quotes.261 262 Created by [Camilo Vega](https://www.linkedin.com/in/camilo-vega-169084b1/), AI Consultant263 """)264 265 with gr.Row():266 with gr.Column(scale=2):267 instructions = gr.Textbox(label="News article instructions", lines=2)268 facts = gr.Textbox(label="Describe the news facts", lines=4)269 size = gr.Number(label="Content body size (in words)", value=100)270 tone = gr.Dropdown(label="News tone", choices=["serious", "neutral", "lighthearted"], value="neutral")271 with gr.Column(scale=3):272 inputs_list = [instructions, facts, size, tone]273 with gr.Tabs():274 for i in range(1, 6):275 with gr.TabItem(f"Audio/Video {i}"):276 file = gr.File(label=f"Audio/Video {i}", type="filepath", file_types=["audio", "video"])277 name = gr.Textbox(label="Name", scale=1)278 position = gr.Textbox(label="Position", scale=1)279 inputs_list.extend([file, name, position])280 for i in range(1, 4):281 with gr.TabItem(f"Social Media {i}"):282 social_url = gr.Textbox(label=f"Social media URL {i}", lines=1)283 social_name = gr.Textbox(label=f"Person/account name {i}", scale=1)284 social_context = gr.Textbox(label=f"Content context {i}", lines=2)285 inputs_list.extend([social_url, social_name, social_context])286 for i in range(1, 6):287 with gr.TabItem(f"URL {i}"):288 url = gr.Textbox(label=f"URL {i}", lines=1)289 inputs_list.append(url)290 for i in range(1, 6):291 with gr.TabItem(f"Document {i}"):292 document = gr.File(label=f"Document {i}", type="filepath", file_count="single")293 inputs_list.append(document)294 295 gr.Markdown("---") # Visual separator296 297 with gr.Row():298 transcriptions_output = gr.Textbox(label="Transcriptions", lines=10)299 300 gr.Markdown("---") # Visual separator301 302 with gr.Row():303 generate = gr.Button("Generate Draft")304 with gr.Row():305 news_output = gr.Textbox(label="Generated Draft", lines=20)306 307 generate.click(fn=generate_news, inputs=inputs_list, outputs=[news_output, transcriptions_output])308 309# Add description about how to use the app310gr.Markdown("""311### How to Use This App312 3131. **Input your requirements:**314 - Enter your news article instructions315 - Describe the key facts of your news story316 - Set the desired word count and tone317 3182. **Add your sources:**319 - Upload audio/video files for automatic transcription320 - Add social media URLs to extract content321 - Include web URLs for additional information322 - Upload documents (PDF, DOCX, XLSX, CSV) to extract relevant data323 3243. **Generate your draft:**325 - Click "Generate Draft" to create your news article326 - Review the transcriptions to verify source accuracy327 - Use the generated draft as a starting point for your news story328 329This tool helps streamline the news writing process by automatically gathering, organizing, and synthesizing information from multiple sources into a cohesive article that follows journalistic best practices.330 331Created by [Camilo Vega](https://www.linkedin.com/in/camilo-vega-169084b1/), AI Consultant332""")333 334demo.launch(share=True)