File size: 1,653 Bytes
a668326
 
 
 
aa5e3cc
a668326
 
 
aa5e3cc
 
 
 
 
 
 
 
a668326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Small, dependency-free helpers shared across modules."""

from __future__ import annotations

import re
from typing import Iterable, List


def slugify(text: str, fallback: str = "video", max_len: int = 60) -> str:
    """Filesystem-safe, lowercase slug (e.g. for a video id derived from a URL)."""
    text = (text or "").strip().lower()
    slug = re.sub(r"[^a-z0-9]+", "_", text).strip("_")
    slug = slug[:max_len].strip("_")
    return slug or fallback


def format_timestamp(seconds: float) -> str:
    """Return an ``HH:MM:SS`` label for a number of seconds."""
    seconds = max(0, int(round(seconds)))
    h, rem = divmod(seconds, 3600)
    m, s = divmod(rem, 60)
    return f"{h:02d}:{m:02d}:{s:02d}"


def extract_keywords(text: str, domain_terms: Iterable[str]) -> List[str]:
    """Return the domain terms that appear in ``text`` (case-insensitive).

    Multi-word terms are matched as substrings, which is robust to Thai-English
    code-switching where English keywords are embedded inside Thai sentences.
    The result preserves the order in which terms appear in ``domain_terms`` and
    contains no duplicates.
    """
    if not text:
        return []
    lowered = text.lower()
    found: List[str] = []
    for term in domain_terms:
        t = term.lower().strip()
        if t and t in lowered and term not in found:
            found.append(term)
    return found


def contains_any(text: str, phrases: Iterable[str]) -> List[str]:
    """Return every phrase from ``phrases`` that occurs in ``text``."""
    if not text:
        return []
    lowered = text.lower()
    return [p for p in phrases if p.lower() in lowered]