Video-Summarizer / summarize.py
ziadtarek12's picture
Hosting Ready
13c85db
Raw
History Blame Contribute Delete
7.47 kB
"""
Summarization Module
Uses OpenRouter API to analyze transcript and identify highlights
"""
from openai import OpenAI
import json
import re
def parse_timestamps_from_response(response_text):
"""
Parse timestamps from OpenRouter API response
Expected format: JSON with segments containing start/end times
Args:
response_text: Response text from OpenRouter API
Returns:
List of dictionaries with 'start', 'end', and 'text' keys
"""
try:
# Try to extract JSON from response
# Look for JSON blocks in the response
json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
if json_match:
data = json.loads(json_match.group())
else:
# Try parsing the entire response as JSON
data = json.loads(response_text)
segments = []
# Handle different possible response formats
if isinstance(data, list):
segments = data
elif isinstance(data, dict):
if 'segments' in data:
segments = data['segments']
elif 'highlights' in data:
segments = data['highlights']
elif 'clips' in data:
segments = data['clips']
else:
# Assume the dict itself contains segment info
segments = [data]
# Normalize segment format
normalized_segments = []
for seg in segments:
if isinstance(seg, dict):
start = seg.get('start', seg.get('start_time', seg.get('startTime', 0)))
end = seg.get('end', seg.get('end_time', seg.get('endTime', start + 30)))
text = seg.get('text', seg.get('description', seg.get('summary', '')))
normalized_segments.append({
'start': float(start),
'end': float(end),
'text': text
})
return normalized_segments
except json.JSONDecodeError:
# If JSON parsing fails, try to extract timestamps from text
print("⚠️ Could not parse JSON, attempting to extract timestamps from text...")
return extract_timestamps_from_text(response_text)
except Exception as e:
print(f"❌ Error parsing timestamps: {str(e)}")
print(f"Response text: {response_text[:500]}")
return []
def extract_timestamps_from_text(text):
"""
Fallback: Extract timestamps from plain text response
Looks for patterns like "00:01:23 - 00:01:45" or "1:23 - 1:45"
"""
segments = []
# Pattern for HH:MM:SS - HH:MM:SS
pattern = r'(\d{1,2}):(\d{2}):(\d{2})\s*-\s*(\d{1,2}):(\d{2}):(\d{2})'
matches = re.finditer(pattern, text)
for match in matches:
h1, m1, s1, h2, m2, s2 = map(int, match.groups())
start = h1 * 3600 + m1 * 60 + s1
end = h2 * 3600 + m2 * 60 + s2
# Try to extract text after the timestamp
text_start = match.end()
text_end = text.find('\n', text_start)
if text_end == -1:
text_end = min(text_start + 100, len(text))
segment_text = text[text_start:text_end].strip()
segments.append({
'start': start,
'end': end,
'text': segment_text
})
return segments
def get_highlights_from_openrouter(transcript, num_clips=3, api_key=None, model="kwaipilot/kat-coder-pro:free"):
"""
Use OpenRouter API to identify highlights in the transcript
Args:
transcript: Full transcript text or SRT content
num_clips: Number of highlight clips to generate
api_key: OpenRouter API key
model: Model to use from OpenRouter
Returns:
List of segments with start/end times and descriptions
"""
if api_key is None:
raise ValueError("OpenRouter API key is required")
print(f"🤖 Analyzing transcript with OpenRouter ({model})...")
# Prepare prompt
# Note: Use double curly braces {{ }} to escape them in f-strings
prompt = f"""
You are an intelligent assistant for video analysis. Analyze the following transcript from an Arabic video and identify {num_clips} meaningful moments that each form a coherent segment between **30 and 60 seconds** in duration. These segments should not be arbitrary excerpts — each one must reflect a **complete idea** and help convey the **main concept of the video**, providing meaningful context.
Return the results in **JSON format only**, containing a list of segments.
Each segment should include:
- "start": starting time in seconds (float)
- "end": ending time in seconds (float)
- "text": a concise description of the content in that segment that captures the key idea
The output should be in JSON format only, with no additional commentary.
ExampleOutput:
{{
"segments": [
{{
"start": 10.5,
"end": 42.0,
"text": "Explanation of the core concept and its importance"
}},
{{
"start": 75.0,
"end": 120.0,
"text": "A meaningful real-world example illustrating the main idea"
}}
]
}}
Transcript:
{transcript}
Return **JSON only**, with no additional commentary."""
try:
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=api_key,
)
completion = client.chat.completions.create(
extra_headers={
"HTTP-Referer": "https://github.com/ahmedomahmoud/Video-Summarizer",
"X-Title": "Video Summarizer",
},
model=model,
messages=[
{
"role": "user",
"content": prompt
}
],
temperature=0.7,
max_tokens=2000
)
response_text = completion.choices[0].message.content
print(f"✅ Received response from OpenRouter")
# Parse the response
segments = parse_timestamps_from_response(response_text)
if not segments:
print("⚠️ No segments found in response, using fallback method")
# Fallback: divide video into equal segments
return create_fallback_segments(transcript, num_clips)
# Limit to requested number of clips
segments = segments[:num_clips]
print(f"✅ Identified {len(segments)} highlight segments")
return segments
except Exception as e:
print(f"❌ Error calling OpenRouter API: {str(e)}")
print("⚠️ Using fallback method to create segments")
return create_fallback_segments(transcript, num_clips)
def create_fallback_segments(transcript, num_clips):
"""
Fallback method: Create segments by dividing transcript into equal parts
"""
# This is a simple fallback - in practice, you'd want better logic
# For now, we'll return empty segments and let the UI handle it
print("⚠️ Using fallback segment creation")
return []
def read_srt_file(srt_path):
"""Read SRT file and return transcript text"""
try:
with open(srt_path, 'r', encoding='utf-8') as f:
content = f.read()
return content
except Exception as e:
print(f"❌ Error reading SRT file: {str(e)}")
return ""