03 / 06 Backend Developer live demo below
AI-Enhanced Multilingual Press Release Generator
Crafted an AI-powered tool using Flask and Python to transform PIB press releases into engaging multilingual videos, increasing accessibility. Established a centralized image management system and advanced prompt engineering to streamline video creation workflows, cutting production time by 45% and boosting productivity by 35%.
01 · The constraint
A billion-person audience, a Hindi-only output pipe
The Press Information Bureau publishes 200-odd statements a day across 50+ ministries. The English text reaches the press; the actual audience — including the ~70 % of India that doesn't read English comfortably — is served by manual translators producing a trickle of videos for one or two regional languages.
The throughput gap was the bottleneck this project attacks: not the writing, the delivery of writing as a watchable, listenable artefact in every official language the citizen actually speaks.
02 · Ingestion
A Selenium walker pulls the daily docket
scrape_pib.pyopenspib.gov.in/allRel.aspxheadless, picks today's date, and walks the DOM: ministries → press-release lists → detail pages. Each detail page yields a title, a body, and a list of inline image URLs.The output is an
OriginalPressReleaseper item, written into MongoDB keyed by the upstream PRID. Re-running the scraper is idempotent — PRIDs already in Mongo are skipped before any AI cost is spent.03 · Summarise
GPT turns paragraphs into slide-sized chunks (and image keywords)
Raw press releases are long, dense, and not built for a 30-second video.
DescriptiveContentGeneratorprompts GPT for two things: a list of paragraph-per-slide summaries (≤2000 total chars) and a list of image-search keywords pulled from the news.The keyword list is the bridge to step 4 —
scrape_images.pyqueries Bing for each keyword and merges the results into the sameDescriptiveContentrecord. Slides + relevant images, ready for compose.●Models/DescriptiveContent.pypython 1prompt = f"""Given the press release: "{pr.content}",2generate more descriptive and summarized content...34Result fields:5 descriptive_text: list[str] # one paragraph per slide6 key_words: list[str] # 5-10 image-search terms7 language: "english"8The sum of all descriptive_text chars must not exceed 2000.9Output JSON only."""10response = MetaAI().prompt(prompt)04 · Multilingual fan-out
10 languages in parallel · googletrans + gTTS
convert_to_speech_in_multiple_languages(prId, joined_text, languages)runsgoogletransfor each target language (en, hi, bn, te, mr, ta, ur, gu, ml, kn), thengTTSto render an MP3 per language. The 10 audio files land on disk keyed by{prId}_output_{lang}.mp3.Same upstream the browser demo uses —
/api/ttsproxies Google's translate_tts endpoint to mirror gTTS's behaviour, and/api/translateproxies MyMemory because Google Translate's free API has a stricter quota.●text_to_voice.pypython 1def convert_to_speech_in_multiple_languages(prId, phrase, languages):2 translator = Translator()3 for lang in languages:4 try:5 translated = translator.translate(phrase, dest=lang).text6 tts = gTTS(text=translated, lang=lang)7 tts.save(f"{prId}_output_{lang}.mp3")8 except Exception as e:9 print(f"Error :{e} for language:{lang}")05 · Compose
MoviePy: zoom + blur + fade · title overlay at y=0.05
generate_pr_video.GeneratePRVideois the heavy hitter. For each image: a blurred background clip, a foreground clip scaled to 1.0 → 1.2× over the slide via the customGradualScaleClip, 1 sfadein+fadeout. The translated title sits on a semi-transparent dark box aty_pct=0.05. Slide duration = audio length ÷ image count.Final clip is concatenated, audio attached, written out as
{prId}.mp4at 1920×1080 / 30 fps via libx264. The browser demo paints the same effects (zoom, fade, title overlay) onto Canvas frame-by-frame instead of MoviePy.●generate_pr_video.pypython 1image_clip = VideoFileClip(image_file, audio=False)2image_clip = image_clip.resize(scaling_factor)3scaled_clip = GradualScaleClip(4 image_clip, zoom_factor=1.2,5 duration=duration_per_image, target_fps=video_fps)6fade_in_clip = fadein(scaled_clip, duration=1)7fade_out_clip = fadeout(scaled_clip, duration=1)8text_line = TextClip(translator.translate(pr.title, dest=lan).text,9 font="Segoe-UI", fontsize=40, color="white")06 · Distribute
Firebase Storage + FCM · 45 % less production time
Output MP4 and the ten MP3s go to Firebase Storage under
gs://synth-ai-envoys.appspot.com/. Each newDescriptiveContenttriggers an FCM push to every user subscribed to that ministry —title: "New Press Release", body and thumbnail derived from the record.Net effect on the production team: ~30 videos a day, ten languages each, with the human only intervening for moderation. The 45 % time reduction and 35 % throughput lift in the project description come from this stage replacing all of the previous manual work.
07 · Try it
Run the six stages in your browser
Paste a press-release-style paragraph below. The pipeline runs the same shape as the Flask service — ingest, summarise (paragraph-split here, LLM in prod), translate to all 10 languages in parallel via
/api/translate, speak the chosen language via/api/tts(gTTS upstream), compose a Canvas slideshow with the same zoom + fade + title overlay MoviePy produced, then a simulated upload.
01 · The constraint
A billion-person audience, a Hindi-only output pipe
The Press Information Bureau publishes 200-odd statements a day across 50+ ministries. The English text reaches the press; the actual audience — including the ~70 % of India that doesn't read English comfortably — is served by manual translators producing a trickle of videos for one or two regional languages.
The throughput gap was the bottleneck this project attacks: not the writing, the delivery of writing as a watchable, listenable artefact in every official language the citizen actually speaks.
02 · Ingestion
A Selenium walker pulls the daily docket
scrape_pib.pyopenspib.gov.in/allRel.aspxheadless, picks today's date, and walks the DOM: ministries → press-release lists → detail pages. Each detail page yields a title, a body, and a list of inline image URLs.The output is an
OriginalPressReleaseper item, written into MongoDB keyed by the upstream PRID. Re-running the scraper is idempotent — PRIDs already in Mongo are skipped before any AI cost is spent.03 · Summarise
GPT turns paragraphs into slide-sized chunks (and image keywords)
Raw press releases are long, dense, and not built for a 30-second video.
DescriptiveContentGeneratorprompts GPT for two things: a list of paragraph-per-slide summaries (≤2000 total chars) and a list of image-search keywords pulled from the news.The keyword list is the bridge to step 4 —
scrape_images.pyqueries Bing for each keyword and merges the results into the sameDescriptiveContentrecord. Slides + relevant images, ready for compose.●Models/DescriptiveContent.pypython 1prompt = f"""Given the press release: "{pr.content}",2generate more descriptive and summarized content...34Result fields:5 descriptive_text: list[str] # one paragraph per slide6 key_words: list[str] # 5-10 image-search terms7 language: "english"8The sum of all descriptive_text chars must not exceed 2000.9Output JSON only."""10response = MetaAI().prompt(prompt)04 · Multilingual fan-out
10 languages in parallel · googletrans + gTTS
convert_to_speech_in_multiple_languages(prId, joined_text, languages)runsgoogletransfor each target language (en, hi, bn, te, mr, ta, ur, gu, ml, kn), thengTTSto render an MP3 per language. The 10 audio files land on disk keyed by{prId}_output_{lang}.mp3.Same upstream the browser demo uses —
/api/ttsproxies Google's translate_tts endpoint to mirror gTTS's behaviour, and/api/translateproxies MyMemory because Google Translate's free API has a stricter quota.●text_to_voice.pypython 1def convert_to_speech_in_multiple_languages(prId, phrase, languages):2 translator = Translator()3 for lang in languages:4 try:5 translated = translator.translate(phrase, dest=lang).text6 tts = gTTS(text=translated, lang=lang)7 tts.save(f"{prId}_output_{lang}.mp3")8 except Exception as e:9 print(f"Error :{e} for language:{lang}")05 · Compose
MoviePy: zoom + blur + fade · title overlay at y=0.05
generate_pr_video.GeneratePRVideois the heavy hitter. For each image: a blurred background clip, a foreground clip scaled to 1.0 → 1.2× over the slide via the customGradualScaleClip, 1 sfadein+fadeout. The translated title sits on a semi-transparent dark box aty_pct=0.05. Slide duration = audio length ÷ image count.Final clip is concatenated, audio attached, written out as
{prId}.mp4at 1920×1080 / 30 fps via libx264. The browser demo paints the same effects (zoom, fade, title overlay) onto Canvas frame-by-frame instead of MoviePy.●generate_pr_video.pypython 1image_clip = VideoFileClip(image_file, audio=False)2image_clip = image_clip.resize(scaling_factor)3scaled_clip = GradualScaleClip(4 image_clip, zoom_factor=1.2,5 duration=duration_per_image, target_fps=video_fps)6fade_in_clip = fadein(scaled_clip, duration=1)7fade_out_clip = fadeout(scaled_clip, duration=1)8text_line = TextClip(translator.translate(pr.title, dest=lan).text,9 font="Segoe-UI", fontsize=40, color="white")06 · Distribute
Firebase Storage + FCM · 45 % less production time
Output MP4 and the ten MP3s go to Firebase Storage under
gs://synth-ai-envoys.appspot.com/. Each newDescriptiveContenttriggers an FCM push to every user subscribed to that ministry —title: "New Press Release", body and thumbnail derived from the record.Net effect on the production team: ~30 videos a day, ten languages each, with the human only intervening for moderation. The 45 % time reduction and 35 % throughput lift in the project description come from this stage replacing all of the previous manual work.
07 · Try it
Run the six stages in your browser
Paste a press-release-style paragraph below. The pipeline runs the same shape as the Flask service — ingest, summarise (paragraph-split here, LLM in prod), translate to all 10 languages in parallel via
/api/translate, speak the chosen language via/api/tts(gTTS upstream), compose a Canvas slideshow with the same zoom + fade + title overlay MoviePy produced, then a simulated upload.
Built with.
Senior backend and platform roles, hard systems problems, or an argument about thread pools.
Open a connectionRecruiter mode