File size: 8,019 Bytes
342e0fb
 
0890748
 
342e0fb
 
 
 
 
0890748
 
 
 
02fa899
d392f23
5ec2b90
 
 
d392f23
 
 
 
342e0fb
 
0890748
 
 
 
 
 
 
342e0fb
0890748
 
 
 
 
 
 
 
 
 
 
 
 
342e0fb
 
 
 
 
0890748
342e0fb
 
 
 
 
 
0890748
 
 
 
 
 
 
342e0fb
 
 
 
 
 
0890748
342e0fb
 
 
 
5ec2b90
342e0fb
d392f23
 
342e0fb
 
d392f23
 
342e0fb
 
 
0890748
342e0fb
d392f23
 
 
 
 
 
 
0890748
 
 
 
 
d392f23
342e0fb
0890748
342e0fb
 
 
 
d392f23
342e0fb
 
 
 
 
 
 
 
0890748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342e0fb
0890748
 
342e0fb
0890748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import os
import time
import json
import logging
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

# Setup Logger
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

# Configure OpenAI Client
api_key = os.getenv("OPENROUTER_API_KEY")
MODEL_NAME = os.getenv("OPENROUTER_MODEL", "arcee-ai/trinity-large-preview:free")


client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=api_key
)


def analyze_transcript(transcript):
    """Analyze transcript using OpenRouter via Env Key."""

    prompt = f"""
    You are an expert video editor and viral content strategist. 
    Your task is to identify the most engaging segments from the provided transcript 
    that are suitable for short-form video platforms like TikTok, Reels, and YouTube Shorts.
    
    **STRICT REQUIREMENTS:**
    1. **Duration**: duration MUST be between 60 seconds and 180 seconds (3 minutes)
    2. **Context Preservation**: Each segment must be a complete thought - no abrupt cuts
    3. **Sentence Boundaries**: Start at the beginning of a sentence, end at a natural conclusion
    4. **Meaning Coherence**: The clip must make sense on its own without requiring prior context
    
    **SELECTION CRITERIA:**
    - Strong hooks that grab attention 
    - Emotional moments, humor, or surprising revelations
    - Clear beginning, middle, and satisfying conclusion
    - High shareability potential
    
    **JSON OUTPUT FORMAT (REQUIRED):**
    {{
      "segments": [
        {{
          "start_time": <float, start time in seconds>,
          "end_time": <float, end time in seconds>,
          "duration": <float, duration in seconds (30-180)>,
          "description": "<string, brief summary of the clip content 10 words max>",
          "viral_score": <float, score from 0-10 indicating viral potential>,
          "reason": "<string, explanation of why this segment is engaging>"
        }}
      ]
    }}
    
    **IMPORTANT NOTES:**
    - If no suitable segments are found, return {{ "segments": [] }}
    - Ensure all strings are properly escaped
    - Each segment must be a complete, coherent thought
    - Avoid cutting mid-sentence or mid-thought
    
    Transcript to Analyze:
    {transcript}
    """

    max_retries = 3
    base_delay = 5
    content = None  # FIX: initialize content to avoid UnboundLocalError

    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(
                model=MODEL_NAME,
                messages=[
                    {"role": "system", "content": "You are a helpful assistant that outputs only valid JSON."},
                    {"role": "user", "content": prompt}
                ],
                extra_headers={
                    "HTTP-Referer": "https://github.com/Start-To-End-AI",
                    "X-Title": "Video Clipper AI",
                },
                temperature=0.7,
            )

            content = response.choices[0].message.content
            print(f"πŸ€– AI Raw Response (First 500 chars): {content[:500]}...")

            # Clean Markdown code blocks if present
            if "```json" in content:
                content = content.split("```json")[1].split("```")[0].strip()
            elif "```" in content:
                content = content.split("```")[1].split("```")[0].strip()

            # Validate JSON and log segment count
            data = json.loads(content)
            segments_count = len(data.get("segments", []))
            print(f"πŸ€– AI Response parsed successfully: Found {segments_count} segments.")

            return {"content": content}

        except Exception as e:
            print(f"❌ Error in OpenRouter analysis: {e}")
            if attempt < max_retries - 1:
                wait_time = base_delay * (2 ** attempt)
                print(f"⚠️ Retrying task in {wait_time}s...")
                time.sleep(wait_time)
            else:
                break

    print("❌ All retry attempts failed.")
    return {"content": '{"segments": []}'}


# Smart chunking system for long transcripts
def smart_chunk_transcript(transcript, max_tokens=4000):
    """
    Split transcript into coherent chunks at sentence boundaries
    while preserving context and meaning.
    """
    import json
    # Simple sentence-based chunking
    sentences = transcript.replace('\n', ' ').split('. ')
    chunks = []
    current_chunk = []
    current_length = 0

    for sentence in sentences:
        sentence_length = len(sentence.split())

        if current_length + sentence_length > max_tokens and current_chunk:
            chunk_text = '. '.join(current_chunk) + '.'
            chunks.append(chunk_text.strip())
            current_chunk = [sentence]
            current_length = sentence_length
        else:
            current_chunk.append(sentence)
            current_length += sentence_length

    if current_chunk:
        chunk_text = '. '.join(current_chunk) + '.'
        chunks.append(chunk_text.strip())

    return chunks


def analyze_transcript_with_chunking(transcript):
    """
    Analyze transcript using smart chunking for long content.
    Processes each chunk separately and merges results.
    """
    if len(transcript.split()) > 3000:
        logger.info("πŸ“¦ Transcript too long, using smart chunking...")
        chunks = smart_chunk_transcript(transcript, max_tokens=3000)
        all_segments = []

        for i, chunk in enumerate(chunks):
            logger.info(f"πŸ”„ Processing chunk {i+1}/{len(chunks)}...")
            result = analyze_transcript(chunk)

            try:
                data = json.loads(result['content'])
                if 'segments' in data:
                    all_segments.extend(data['segments'])
            except Exception as e:
                logger.warning(f"⚠️ Failed to parse chunk {i+1}: {e}")
                continue

        if all_segments:
            all_segments.sort(key=lambda x: x.get('viral_score', 0), reverse=True)
            unique_segments = []
            seen_times = set()

            for seg in all_segments:
                time_key = f"{seg.get('start_time', 0):.0f}-{seg.get('end_time', 0):.0f}"
                if time_key not in seen_times:
                    unique_segments.append(seg)
                    seen_times.add(time_key)

            return {"content": json.dumps({"segments": unique_segments[:10]})}

    return analyze_transcript(transcript)


# Testing
if __name__ == "__main__":
    test_transcript = """
    [0.0 - 5.0] Welcome to today's video about productivity hacks that actually work.
    [5.0 - 15.0] The first hack is something I call the 2-minute rule. If something takes less than 2 minutes, do it immediately.
    [15.0 - 30.0] This simple rule has transformed my life. I used to procrastinate on small tasks, but now I handle them right away.
    [30.0 - 45.0] The second hack is batching similar tasks together. Instead of checking email 20 times a day, I check it twice.
    [45.0 - 60.0] This has saved me hours every week. I batch my emails, phone calls, and even errands.
    [60.0 - 90.0] The third hack is the Pomodoro Technique. Work for 25 minutes, then take a 5-minute break.
    [90.0 - 120.0] This technique helps me stay focused and avoid burnout. I get more done in less time.
    """

    logger.info("πŸ§ͺ Testing AI Analysis...")
    result = analyze_transcript_with_chunking(test_transcript)

    try:
        data = json.loads(result['content'])
        segments = data.get('segments', [])
        logger.info(f"βœ… Found {len(segments)} viral segments:")

        for i, seg in enumerate(segments):
            logger.info(f"  #{i+1} [{seg['start_time']:.0f}s-{seg['end_time']:.0f}s] "
                        f"Score: {seg['viral_score']}/10 - {seg['description']}")
    except Exception as e:
        logger.error(f"❌ Error parsing result: {e}")
        logger.info(f"Raw result: {result}")