NoticIA-Col/Generador-Noticias
import os import openai import whisper import tempfile import gradio as gr from pydub import AudioSegment import fitz # PyMuPDF for handling PDFs import docx # For handling .docx files import pandas as pd # For handling .xlsx and .csv files import requests from bs4 import BeautifulSoup from moviepy.editor import VideoFileClip import yt_dlp import logging
Configure logging
logging.basicConfig(level=logging.INFO) logger = logging.getLogger(_name_)
Configure your OpenAI API key
openai.apikey = os.getenv("OPENAIAPI_KEY")
Load the highest quality Whisper model once
model = whisper.load_model("large")
def downloadsocialmediavideo(url): """Downloads a video from social media.""" ydlopts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], 'outtmpl': '%(id)s.%(ext)s', } try: with ytdlp.YoutubeDL(ydlopts) as ydl: infodict = ydl.extractinfo(url, download=True) audiofile = f"{infodict['id']}.mp3" logger.info(f"Video successfully downloaded: {audiofile}") return audiofile except Exception as e: logger.error(f"Error downloading video: {str(e)}") raise
def convertvideotoaudio(videofile): """Converts a video file to audio.""" try: video = VideoFileClip(videofile) with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tempfile: video.audio.writeaudiofile(tempfile.name) logger.info(f"Video converted to audio: {tempfile.name}") return tempfile.name except Exception as e: logger.error(f"Error converting video to audio: {str(e)}") raise
def preprocessaudio(audiofile): """Preprocesses the audio file to improve quality.""" try: audio = AudioSegment.fromfile(audiofile) audio = audio.applygain(-audio.dBFS + (-20)) with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tempfile: audio.export(tempfile.name, format="mp3") logger.info(f"Audio preprocessed: {tempfile.name}") return temp_file.name except Exception as e: logger.error(f"Error preprocessing audio file: {str(e)}") raise
def transcribeaudio(file): """Transcribes an audio or video file.""" try: if isinstance(file, str) and file.startswith('http'): logger.info(f"Downloading social media video: {file}") filepath = downloadsocialmediavideo(file) elif isinstance(file, str) and file.lower().endswith(('.mp4', '.avi', '.mov', '.mkv')): logger.info(f"Converting local video to audio: {file}") filepath = convertvideotoaudio(file) else: logger.info(f"Preprocessing audio file: {file}") filepath = preprocess_audio(file)
logger.info(f"Transcribing audio: {filepath}") result = model.transcribe(filepath) transcription = result.get("text", "Error in transcription") logger.info(f"Transcription completed: {transcription[:50]}...") return transcription except Exception as e: logger.error(f"Error processing file: {str(e)}") return f"Error processing file: {str(e)}"
def readdocument(documentpath): """Reads content from PDF, DOCX, XLSX or CSV documents.""" try: if documentpath.endswith(".pdf"): doc = fitz.open(documentpath) return "\n".join([page.gettext() for page in doc]) elif documentpath.endswith(".docx"): doc = docx.Document(documentpath) return "\n".join([paragraph.text for paragraph in doc.paragraphs]) elif documentpath.endswith(".xlsx"): return pd.readexcel(documentpath).tostring() elif documentpath.endswith(".csv"): return pd.readcsv(documentpath).to_string() else: return "Unsupported file type. Please upload a PDF, DOCX, XLSX or CSV document." except Exception as e: return f"Error reading document: {str(e)}"
def readurl(url): """Reads content from a URL.""" try: response = requests.get(url) response.raiseforstatus() soup = BeautifulSoup(response.content, 'html.parser') return soup.gettext() except Exception as e: return f"Error reading URL: {str(e)}"
def processsocialcontent(url): """Processes content from a social media URL, handling both text and video.""" try: # First, try to read content as text textcontent = readurl(url)
# Then, try to process as video try: videocontent = transcribeaudio(url) except Exception: video_content = None
return { "text": textcontent, "video": videocontent } except Exception as e: logger.error(f"Error processing social content: {str(e)}") return None
def generatenews(instructions, facts, size, tone, *args): """Generates a news article from instructions, facts, URLs, documents, transcriptions, and social media content.""" knowledgebase = { "instructions": instructions, "facts": facts, "documentcontent": [], "audiodata": [], "urlcontent": [], "socialcontent": [] } numaudios = 5 * 3 # 5 audios/videos * 3 fields (file, name, position) numsocialurls = 3 * 3 # 3 social media URLs * 3 fields (URL, name, context) numurls = 5 # 5 general URLs audios = args[:numaudios] socialurls = args[numaudios:numaudios+numsocialurls] urls = args[numaudios+numsocialurls:numaudios+numsocialurls+numurls] documents = args[numaudios+numsocialurls+num_urls:]
for url in urls: if url: knowledgebase["urlcontent"].append(read_url(url))
for document in documents: if document is not None: knowledgebase["documentcontent"].append(read_document(document.name))
for i in range(0, len(audios), 3): audiofile, name, position = audios[i:i+3] if audiofile is not None: knowledgebase["audiodata"].append({"audio": audio_file, "name": name, "position": position})
for i in range(0, len(socialurls), 3): socialurl, socialname, socialcontext = socialurls[i:i+3] if socialurl: socialcontent = processsocialcontent(socialurl) if socialcontent: knowledgebase["socialcontent"].append({ "url": socialurl, "name": socialname, "context": socialcontext, "text": socialcontent["text"], "video": socialcontent["video"] }) logger.info(f"Social media content processed: {social_url}")
transcriptionstext, rawtranscriptions = "", ""
for idx, data in enumerate(knowledgebase["audiodata"]): if data["audio"] is not None: transcription = transcribeaudio(data["audio"]) transcriptiontext = f'"{transcription}" - {data["name"]}, {data["position"]}' rawtranscription = f'[Audio/Video {idx + 1}]: "{transcription}" - {data["name"]}, {data["position"]}' transcriptionstext += transcriptiontext + "\n" rawtranscriptions += raw_transcription + "\n\n"
for data in knowledgebase["socialcontent"]: if data["text"]: transcriptiontext = f'[Social media text]: "{data["text"][:200]}..." - {data["name"]}, {data["context"]}' transcriptionstext += transcriptiontext + "\n" rawtranscriptions += transcriptiontext + "\n\n" if data["video"]: transcriptionvideo = f'[Social media video]: "{data["video"]}" - {data["name"]}, {data["context"]}' transcriptionstext += transcriptionvideo + "\n" rawtranscriptions += transcriptionvideo + "\n\n"
documentcontent = "\n\n".join(knowledgebase["documentcontent"]) urlcontent = "\n\n".join(knowledgebase["urlcontent"])
internal_prompt = """ Instructions for the model:
- Follow news article principles: answer the 5 Ws in the first paragraph (Who?, What?, When?, Where?, Why?).
- Ensure at least 80% of quotes are direct and in quotation marks.
- The remaining 20% can be indirect quotes.
- Don't invent new information.
- Be rigorous with provided facts.
- When processing uploaded documents, extract and highlight important quotes and testimonials from sources.
- When processing uploaded documents, extract and highlight key figures.
- Avoid using the date at the beginning of the news body. Start directly with the 5Ws.
- Include social media content relevantly, citing the source and providing proper context.
- Make sure to relate the provided context for social media content with its corresponding transcription or text. """
prompt = f""" {internalprompt} 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}. Instructions: {knowledgebase["instructions"]} Facts: {knowledgebase["facts"]} Additional content from documents: {documentcontent} Additional content from URLs: {urlcontent} Use the following transcriptions as direct and indirect quotes (without changing or inventing content): {transcriptionstext} """
try: response = openai.ChatCompletion.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.1 ) news = response['choices'][0]['message']['content'] return news, raw_transcriptions except Exception as e: logger.error(f"Error generating news article: {str(e)}") return f"Error generating news article: {str(e)}", ""
with gr.Blocks() as demo: gr.Markdown("## All-in-One News Generator")
# Add tool description and attribution gr.Markdown(""" ### About this tool
This AI-powered news generator helps journalists and content creators produce news articles by processing multiple types of input:
- Audio and video files with automatic transcription
- Social media content
- Documents (PDF, DOCX, XLSX, CSV)
- Web URLs
The tool uses advanced AI to generate well-structured news articles following journalistic principles and maintaining the integrity of source quotes.
Created by Camilo Vega, AI Consultant """)
with gr.Row(): with gr.Column(scale=2): instructions = gr.Textbox(label="News article instructions", lines=2) facts = gr.Textbox(label="Describe the news facts", lines=4) size = gr.Number(label="Content body size (in words)", value=100) tone = gr.Dropdown(label="News tone", choices=["serious", "neutral", "lighthearted"], value="neutral") with gr.Column(scale=3): inputslist = [instructions, facts, size, tone] with gr.Tabs(): for i in range(1, 6): with gr.TabItem(f"Audio/Video {i}"): file = gr.File(label=f"Audio/Video {i}", type="filepath", filetypes=["audio", "video"]) name = gr.Textbox(label="Name", scale=1) position = gr.Textbox(label="Position", scale=1) inputslist.extend([file, name, position]) for i in range(1, 4): with gr.TabItem(f"Social Media {i}"): socialurl = gr.Textbox(label=f"Social media URL {i}", lines=1) socialname = gr.Textbox(label=f"Person/account name {i}", scale=1) socialcontext = gr.Textbox(label=f"Content context {i}", lines=2) inputslist.extend([socialurl, socialname, socialcontext]) for i in range(1, 6): with gr.TabItem(f"URL {i}"): url = gr.Textbox(label=f"URL {i}", lines=1) inputslist.append(url) for i in range(1, 6): with gr.TabItem(f"Document {i}"): document = gr.File(label=f"Document {i}", type="filepath", filecount="single") inputs_list.append(document)
gr.Markdown("---") # Visual separator
with gr.Row(): transcriptions_output = gr.Textbox(label="Transcriptions", lines=10)
gr.Markdown("---") # Visual separator
with gr.Row(): generate = gr.Button("Generate Draft") with gr.Row(): news_output = gr.Textbox(label="Generated Draft", lines=20)
generate.click(fn=generatenews, inputs=inputslist, outputs=[newsoutput, transcriptionsoutput])
Add description about how to use the app
gr.Markdown("""
How to Use This App
- Input your requirements:
- Enter your news article instructions
- Describe the key facts of your news story
- Set the desired word count and tone
- Add your sources:
- Upload audio/video files for automatic transcription
- Add social media URLs to extract content
- Include web URLs for additional information
- Upload documents (PDF, DOCX, XLSX, CSV) to extract relevant data
- Generate your draft:
- Click "Generate Draft" to create your news article
- Review the transcriptions to verify source accuracy
- Use the generated draft as a starting point for your news story
This 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.
Created by Camilo Vega, AI Consultant """)
demo.launch(share=True)
