Skip to content

Commit 8129c44

Browse files
committed
Beta Release
1 parent 1a7dbc9 commit 8129c44

366 files changed

Lines changed: 742482 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.DS_Store

10 KB
Binary file not shown.

.github/workflows/deploy.yml

Whitespace-only changes.

Full E2E Plan.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
This is the detailed report of the finalized **Sai Leela Rahasya** web application, encompassing the structure, features, and design decisions made for all components.
2+
3+
## 📝 Detailed Application Report: Sai Leela Rahasya
4+
5+
### I. Application Mission & Core Philosophy
6+
7+
The application's fundamental mission is to move beyond the simple narrative of Sai Baba's miracles (_Leela_) to uncover the hidden, instructional story (_Bodhakatha_). It aims to deliver "crystal clear knowledge" and "True information related to Sai Baba's life fact's" and convey the "anguish of Sai's heart to every heart".
8+
9+
### II. Interface & Navigation Strategy
10+
11+
The application employs a responsive design ensuring accessibility across all device types.
12+
13+
### I. Interface Design & Navigation Strategy
14+
15+
The app utilizes responsive design principles for optimal user experience:
16+
17+
| **Element** | **Mobile (Portrait)** | **Tablet/Desktop (Landscape)** | **Function** |
18+
| --- | --- | --- | --- |
19+
| **Primary Navigation** | **Footer Tab Bar** | **Left-Hand Sidebar** | Persistent, one-click access to the five core features. |
20+
| --- | --- | --- | --- |
21+
| **Utility Menu** | **Top Right Corner Avatar Icon** (Slide-Out Panel) | **Top Right Corner Avatar Icon** (Slide-Out Panel) | Houses user account actions (Sign In/Profile) and secondary links (FAQ, Donate, Glossary, Contact Us). |
22+
| --- | --- | --- | --- |
23+
| **Entry Point** | **Landing Page** | **Landing Page** | Acts as the spiritual welcome and drives users to explore the content. |
24+
| --- | --- | --- | --- |
25+
26+
#### Entry Point: Landing Page
27+
28+
The app opens with a focused Landing Page that acts as a spiritual welcome mat:
29+
30+
- **Hero Message:** "Sai Leela Rahasya: The Secret of Sai's Plays Revealed."
31+
- **Motto Inclusion:** Features the driving force: "We have believed Sai for years, now let's learn something. It's not our application, Sai, it's your choice."
32+
- **Primary CTA:** Directs users to the core content.
33+
- **Social Integration:** Contains subtle links to the source YouTube Channel, Facebook, and Instagram for audience growth.
34+
35+
#### Primary Navigation (5 Core Features)
36+
37+
The five core features are accessed via persistent navigation:
38+
39+
- **Mobile View:** **Footer Tab Bar** for easy, one-handed access.
40+
- **Tablet/Desktop View:** **Left-Hand Sidebar** for utilizing horizontal space.
41+
42+
| **Feature Page** | **Icon** | **Focus** |
43+
| --- | --- | --- |
44+
| **1\. Leela** | Divine Footprints | Narrative Articles (The "What") |
45+
| --- | --- | --- |
46+
| **2\. Bodhakatha** | Radiant Figure (Instruction) | Instructional Articles (The "Why") |
47+
| --- | --- | --- |
48+
| **3\. Live Stream** | Live Stream Indicator | Real-Time Video Darshan & Library |
49+
| --- | --- | --- |
50+
| **4\. Bhajan/Audio** | Music/Speaker Icon | Auditory Devotion & Library |
51+
| --- | --- | --- |
52+
| **5\. Ask Krishnaji** | Guidance/Question Icon | Personalized Ticket System |
53+
| --- | --- | --- |
54+
55+
## Utility & User Profile Menu (Revised)
56+
57+
#### The Utility Menu is triggered by clicking the User/Avatar icon in the Top Right Corner and slides open from the right
58+
59+
### Menu Content Breakdown
60+
61+
<div class="joplin-table-wrapper"><table><thead><tr><th><h4>User State</h4></th><th><h4>Primary Action (Top of Panel)</h4></th><th><h4>Secondary Links (Below Action)</h4></th></tr><tr><th><h4>Guest User</h4></th><th><h4>Sign In / Register button.</h4></th><th><h4>Glossary | FAQ | Donate | Logout</h4></th></tr></thead></table></div>
62+
63+
#### III. Detailed Feature Implementations
64+
65+
#### 1\. Leela & Bodhakatha Pages (Article Lists)
66+
67+
Both pages display articles in a list view, linking directly to the source YouTube video for content transparency.
68+
69+
- **Leela Page Ordering:** Articles are ordered **Chronologically** by Chapter/Sequence number.
70+
- **Bodhakatha Page Ordering:** Articles are ordered **Semantically** by the Virtue/Theme (e.g., Faith, Saburi) to prioritize instructional wisdom.
71+
72+
#### 2\. Live Streams & Video Darshan Library
73+
74+
This page acts as the central video hub:
75+
76+
- **Priority Placement:** Features a prominently displayed card for the **LIVE NOW** feed, if active.
77+
- **Library:** Lists individual video cards for recorded content (past Aartis, Darshans).
78+
- **Functionality:** Includes an **Upcoming Schedule** section to inform users of the next scheduled stream times.
79+
80+
#### 3\. Bhajan/Audio Page
81+
82+
- **Organization:** Content is structured by function: **Daily Aartis** (Kakad, Madhyan, Dhoop, Shej), **Bhajans**, **Mantras/Chants**, and related **Spiritual Discourses**.
83+
- **User Experience:** Optimized for background listening with a simple interface.
84+
85+
#### 4\. Ask Krishnaji (Personalized Guidance)
86+
87+
This feature is implemented as a professional **Ticket Submission System**.
88+
89+
- **Guest Conversion:** Guests are prompted to **Sign In** to receive personalized answers via email and track their inquiries.
90+
- **Signed-In User Workflow:**
91+
- **New Ticket Submission:** Users submit a detailed question (the "ticket").
92+
- **Ticket History:** Users view a list of all their past requests, filterable by Status (**Open, Answered, Closed**).
93+
- **Ticket Detail:** Displays a chronological log of the original question and the guidance provided by the backend team.
94+
- **Follow-Up:** Users can submit follow-up questions directly within the ticket detail, maintaining a continuous, organized record of their spiritual correspondence.
95+
96+
### IV. Glossary Page
97+
98+
A dedicated utility page for defining key spiritual terms central to the application's mission, including: **Leela**, **Bodhakatha**, **Sai Leela Rahasya**, **Shraddha**, **Saburi**, and **Darshan**.

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Krishnasagar
2+
3+
Krishnasagar is a serverless video localization pipeline that automates transcription, translation, and dubbing of content using Google Cloud AI services.
4+
5+
> **Status:** The **Web Project** is currently in **Beta Release**. All other projects (Cloud Functions, etc.) are in **Dev Locked Mode**.
6+
7+
## Setup & Deployment
8+
9+
gcloud services enable storage.googleapis.com \
10+
cloudfunctions.googleapis.com \
11+
run.googleapis.com \
12+
speech.googleapis.com \
13+
translate.googleapis.com \
14+
texttospeech.googleapis.com \
15+
videointelligence.googleapis.com \
16+
youtube.googleapis.com \
17+
logging.googleapis.com \
18+
monitoring.googleapis.com
19+
20+
21+
gsutil mb -l asia-south1 gs://krishnasagar-videos-raw
22+
gsutil mb -l asia-south1 gs://krishnasagar-videos-processed
23+
gsutil mb -l asia-south1 gs://krishnasagar-videos-final
24+
25+
### extract_audio
26+
gcloud functions deploy krishnasagar-extract-audio \
27+
--runtime python39 \
28+
--trigger-resource krishnasagar-videos-raw \
29+
--trigger-event google.storage.object.finalize \
30+
--entry-point extract_audio \
31+
--memory 512MB \
32+
--region asia-south1 \
33+
--source cloud_functions/extract_audio
34+
35+
### transcribe_audio
36+
gcloud functions deploy krishnasagar-transcribe-audio \
37+
--runtime python39 \
38+
--trigger-resource krishnasagar-videos-processed \
39+
--trigger-event google.storage.object.finalize \
40+
--entry-point transcribe_audio \
41+
--memory 512MB \
42+
--region asia-south1 \
43+
--source cloud_functions/transcribe_audio
44+
45+
### translate_text
46+
gcloud functions deploy krishnasagar-translate-text \
47+
--runtime python39 \
48+
--trigger-resource krishnasagar-videos-processed \
49+
--trigger-event google.storage.object.finalize \
50+
--entry-point translate_text \
51+
--memory 512MB \
52+
--region asia-south1 \
53+
--source cloud_functions/translate_text
54+
55+
### generate_audio
56+
gcloud functions deploy krishnasagar-generate-voice \
57+
--runtime python39 \
58+
--trigger-resource krishnasagar-videos-processed \
59+
--trigger-event google.storage.object.finalize \
60+
--entry-point generate_audio \
61+
--memory 512MB \
62+
--region asia-south1 \
63+
--source cloud_functions/generate_audio
64+
65+
### generate_subtitles
66+
gcloud functions deploy krishnasagar-generate-subtitles \
67+
--runtime python39 \
68+
--trigger-resource krishnasagar-videos-processed \
69+
--trigger-event google.storage.object.finalize \
70+
--entry-point generate_subtitles \
71+
--memory 512MB \
72+
--region asia-south1 \
73+
--source cloud_functions/generate_subtitles
74+
75+
### Build the Docker Image
76+
gcloud builds submit --tag gcr.io/potent-airfoil-454402-e4/krishnasagar-video-merger cloud_run/merge_audio_video
77+
78+
### Deploy the Service
79+
80+
gcloud run deploy krishnasagar-video-merger \
81+
--image gcr.io/potent-airfoil-454402-e4/krishnasagar-video-merger \
82+
--region asia-south1 \
83+
--platform managed \
84+
--allow-unauthenticated
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import logging
2+
import uuid
3+
import subprocess
4+
from google.cloud import storage
5+
6+
# Initialize the Cloud Storage client
7+
storage_client = storage.Client()
8+
9+
def extract_audio(event, context):
10+
"""
11+
Triggered by a change to the 'krishnasagar-videos-raw' bucket.
12+
This function extracts audio from an MP4 video file and saves the extracted
13+
audio as an MP3 file in the 'krishnasagar-videos-processed' bucket.
14+
15+
It uses a unique TRACE_ID for logging to enable end-to-end traceability.
16+
"""
17+
bucket_name = event['bucket']
18+
video_file = event['name']
19+
20+
# Process only .mp4 files
21+
if not video_file.endswith(".mp4"):
22+
logging.info("File is not an MP4. Skipping...")
23+
return
24+
25+
# Generate a unique trace ID for this operation
26+
trace_id = str(uuid.uuid4())
27+
logging.info(f"[TRACE_ID: {trace_id}] Starting audio extraction for file: {video_file}")
28+
29+
# Define local file paths
30+
input_path = f"/tmp/{video_file}"
31+
output_audio = f"/tmp/{video_file.replace('.mp4', '.mp3')}"
32+
33+
try:
34+
# Download the video file from the source bucket
35+
bucket = storage_client.bucket(bucket_name)
36+
blob = bucket.blob(video_file)
37+
blob.download_to_filename(input_path)
38+
logging.info(f"[TRACE_ID: {trace_id}] Downloaded {video_file} to {input_path}")
39+
40+
# Use FFmpeg to extract audio
41+
subprocess.run(
42+
["ffmpeg", "-i", input_path, "-q:a", "0", "-map", "a", output_audio],
43+
check=True
44+
)
45+
logging.info(f"[TRACE_ID: {trace_id}] Audio extraction completed, saved to {output_audio}")
46+
47+
# Upload the extracted audio to the destination bucket
48+
processed_bucket = storage_client.bucket("krishnasagar-videos-processed")
49+
# Processing logic (extract audio)
50+
output_blob = processed_bucket.blob(video_file.replace(".mp4", ".mp3"))
51+
output_blob.upload_from_filename(output_audio)
52+
logging.info(f"[TRACE_ID: {trace_id}] Uploaded extracted audio to krishnasagar-videos-processed bucket")
53+
54+
except Exception as e:
55+
logging.error(f"[TRACE_ID: {trace_id}] Error during audio extraction: {e}")

cloud_functions/extract_audio/requirements.txt

Whitespace-only changes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import logging
2+
from google.cloud import texttospeech, storage
3+
4+
# Initialize clients for Storage and Text-to-Speech
5+
storage_client = storage.Client()
6+
tts_client = texttospeech.TextToSpeechClient()
7+
8+
def generate_audio(event, context):
9+
"""
10+
Triggered when a new translated text file (_en.txt) is uploaded.
11+
Converts the English text into speech using WaveNet and saves the output as an .mp3 file.
12+
"""
13+
bucket_name = event['bucket']
14+
text_file = event['name']
15+
16+
# Process only _en.txt files
17+
if not text_file.endswith("_en.txt"):
18+
logging.info("File is not a translated transcript (_en.txt). Skipping...")
19+
return
20+
21+
logging.info(f"Processing translated transcript: {text_file} in bucket: {bucket_name}")
22+
23+
# Read the translated English text from the file
24+
bucket = storage_client.bucket(bucket_name)
25+
blob = bucket.blob(text_file)
26+
english_text = blob.download_as_text()
27+
28+
# Configure the TTS request using a WaveNet voice
29+
synthesis_input = texttospeech.SynthesisInput(text=english_text)
30+
voice = texttospeech.VoiceSelectionParams(
31+
language_code="en-US",
32+
name="en-US-Wavenet-D", # Change the voice if desired
33+
ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
34+
)
35+
audio_config = texttospeech.AudioConfig(
36+
audio_encoding=texttospeech.AudioEncoding.MP3,
37+
pitch=0.0,
38+
speaking_rate=1.0
39+
)
40+
41+
try:
42+
response = tts_client.synthesize_speech(
43+
input=synthesis_input,
44+
voice=voice,
45+
audio_config=audio_config
46+
)
47+
logging.info("Text-to-Speech synthesis completed successfully.")
48+
except Exception as e:
49+
logging.error(f"Error during TTS synthesis: {str(e)}")
50+
return
51+
52+
# Save the generated audio as an .mp3 file
53+
output_filename = text_file.replace("_en.txt", ".mp3")
54+
output_blob = bucket.blob(output_filename)
55+
output_blob.upload_from_string(response.audio_content)
56+
57+
logging.info(f"Generated audio saved as {output_filename}")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
google-cloud-storage
2+
google-cloud-texttospeech
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import logging
2+
from google.cloud import videointelligence, storage
3+
4+
# Initialize clients for Cloud Storage and Video Intelligence
5+
storage_client = storage.Client()
6+
video_client = videointelligence.VideoIntelligenceServiceClient()
7+
8+
def generate_subtitles(event, context):
9+
"""
10+
Triggered when a new .mp3 file is uploaded to the krishnasagar-videos-processed bucket.
11+
This function uses the Video Intelligence API to generate subtitles (SRT format)
12+
and saves the output in the krishnasagar-videos-final bucket.
13+
"""
14+
bucket_name = event['bucket']
15+
audio_file = event['name']
16+
17+
# Process only .mp3 files
18+
if not audio_file.endswith(".mp3"):
19+
logging.info("File is not an mp3. Skipping...")
20+
return
21+
22+
logging.info(f"Processing audio file for subtitles: {audio_file}")
23+
24+
# Construct GCS URI for the audio file
25+
gcs_uri = f"gs://{bucket_name}/{audio_file}"
26+
27+
# Configure the transcription request for subtitles
28+
features = [videointelligence.Feature.SPEECH_TRANSCRIPTION]
29+
speech_config = videointelligence.SpeechTranscriptionConfig(
30+
language_code="en-US",
31+
enable_automatic_punctuation=True
32+
)
33+
video_context = videointelligence.VideoContext(speech_transcription_config=speech_config)
34+
35+
# Initiate the asynchronous video annotation request
36+
operation = video_client.annotate_video(
37+
request={"features": features, "input_uri": gcs_uri, "video_context": video_context}
38+
)
39+
logging.info("Waiting for subtitle generation operation to complete...")
40+
result = operation.result(timeout=600)
41+
42+
# Process the results and create SRT content
43+
srt_lines = []
44+
index = 1
45+
for transcription in result.annotation_results[0].speech_transcriptions:
46+
# Use the first alternative only
47+
for alternative in transcription.alternatives:
48+
for word_info in alternative.words:
49+
start_time = word_info.start_time
50+
end_time = word_info.end_time
51+
text = word_info.word
52+
53+
# Format timestamps as hh:mm:ss,ms (SRT format)
54+
start = f"{int(start_time.seconds // 3600):02}:{int((start_time.seconds % 3600) // 60):02}:{int(start_time.seconds % 60):02},{int(start_time.nanos/1000000):03}"
55+
end = f"{int(end_time.seconds // 3600):02}:{int((end_time.seconds % 3600) // 60):02}:{int(end_time.seconds % 60):02},{int(end_time.nanos/1000000):03}"
56+
57+
srt_lines.append(f"{index}\n{start} --> {end}\n{text}\n")
58+
index += 1
59+
60+
srt_content = "\n".join(srt_lines)
61+
62+
# Save the SRT file to the krishnasagar-videos-final bucket
63+
output_bucket = storage_client.bucket("krishnasagar-videos-final")
64+
srt_filename = audio_file.replace(".mp3", ".srt")
65+
output_blob = output_bucket.blob(srt_filename)
66+
output_blob.upload_from_string(srt_content)
67+
logging.info(f"Subtitles saved as {srt_filename}")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
google-cloud-storage
2+
google-cloud-videointelligence

0 commit comments

Comments
 (0)