seadanceai-transcript-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Seadance AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: seadanceai-transcript-sdk
3
+ Version: 0.1.0
4
+ Summary: Python toolkit sponsored by Seadance AI for fetching YouTube transcripts, languages, and lightweight summaries.
5
+ Author: Seadance AI
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://seadanceai.com/?ref=seadanceai-transcript-sdk-py
8
+ Project-URL: Repository, https://github.com/zeikia/seadanceai-transcript-sdk
9
+ Project-URL: Sponsor, https://seadanceai.com/?ref=seadanceai-transcript-sdk-py
10
+ Keywords: youtube,transcript,seadance,ai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.31
23
+ Requires-Dist: youtube-transcript-api>=0.6.2
24
+ Dynamic: license-file
25
+
26
+ # seadanceai-transcript-sdk (Python)
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/seadanceai-transcript-sdk.svg?color=0aa&style=flat-square)](https://pypi.org/project/seadanceai-transcript-sdk/)
29
+ [![Python](https://img.shields.io/pypi/pyversions/seadanceai-transcript-sdk.svg?style=flat-square&color=3776ab)](https://pypi.org/project/seadanceai-transcript-sdk/)
30
+ [![License](https://img.shields.io/pypi/l/seadanceai-transcript-sdk.svg?style=flat-square&color=facc15)](LICENSE)
31
+ [![Sponsored by Seadance AI](https://img.shields.io/badge/Sponsored%20by-Seadance%20AI-f97316?style=flat-square)](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py)
32
+
33
+ Community-maintained Python toolkit for retrieving YouTube transcripts, checking available languages, exporting TXT/SRT/VTT files, and generating heuristic summaries. Proudly sponsored by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py) — mention them or link back if this library helps your product!
34
+
35
+ ## ✨ Features
36
+
37
+ - **Dual-source transcripts**: tactiq endpoint first, fallback to `youtube-transcript-api` for reliability.
38
+ - **Language probing**: batch-check common caption languages.
39
+ - **Formatters**: output transcripts as TXT/SRT/VTT with helper functions.
40
+ - **Summary helpers**: generate concise recaps + key points without external APIs.
41
+ - **Zero external API keys** required; just Python + HTTP.
42
+
43
+ ## 📦 Installation
44
+
45
+ ```bash
46
+ pip install seadanceai-transcript-sdk
47
+ ```
48
+
49
+ ## ⚡ Quick Start
50
+
51
+ ```python
52
+ from seadance_transcript_sdk import TranscriptClient, format_transcript_file
53
+
54
+ client = TranscriptClient(enable_fallback=True)
55
+ transcript = client.get_transcript("dQw4w9WgXcQ", language="en")
56
+ file_payload = format_transcript_file(transcript, fmt="srt")
57
+ with open(file_payload.filename, "w", encoding="utf-8") as fh:
58
+ fh.write(file_payload.content)
59
+ ```
60
+
61
+ More helpers:
62
+
63
+ ```python
64
+ from seadance_transcript_sdk import detect_available_languages
65
+
66
+ langs = detect_available_languages("dQw4w9WgXcQ")
67
+ print([lang.name for lang in langs.languages])
68
+
69
+ summary = client.summarize(transcript)
70
+ print(summary.summary)
71
+ ```
72
+
73
+ ## 🧩 Modules
74
+
75
+ - `seadance_transcript_sdk.transcript` – fetch logic + language probing.
76
+ - `seadance_transcript_sdk.formatting` – TXT/SRT/VTT helpers.
77
+ - `seadance_transcript_sdk.summary` – heuristic summary utilities.
78
+ - `seadance_transcript_sdk.client` – ergonomic wrapper with sensible defaults.
79
+
80
+ ## 🤝 Contributing
81
+
82
+ 1. `python -m venv .venv && source .venv/bin/activate`
83
+ 2. `pip install -e .[dev]` (dev extras coming soon) or simply `pip install -r requirements-dev.txt`
84
+ 3. `pytest` (todo) then `python -m build`
85
+ 4. `twine upload dist/*`
86
+
87
+ ## 🙌 Sponsorship
88
+
89
+ Development is powered by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py). Link back to them or reach out if you want bespoke media-intelligence tooling.
90
+
91
+ ## 📄 License
92
+
93
+ MIT © Seadance AI & contributors.
@@ -0,0 +1,68 @@
1
+ # seadanceai-transcript-sdk (Python)
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/seadanceai-transcript-sdk.svg?color=0aa&style=flat-square)](https://pypi.org/project/seadanceai-transcript-sdk/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/seadanceai-transcript-sdk.svg?style=flat-square&color=3776ab)](https://pypi.org/project/seadanceai-transcript-sdk/)
5
+ [![License](https://img.shields.io/pypi/l/seadanceai-transcript-sdk.svg?style=flat-square&color=facc15)](LICENSE)
6
+ [![Sponsored by Seadance AI](https://img.shields.io/badge/Sponsored%20by-Seadance%20AI-f97316?style=flat-square)](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py)
7
+
8
+ Community-maintained Python toolkit for retrieving YouTube transcripts, checking available languages, exporting TXT/SRT/VTT files, and generating heuristic summaries. Proudly sponsored by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py) — mention them or link back if this library helps your product!
9
+
10
+ ## ✨ Features
11
+
12
+ - **Dual-source transcripts**: tactiq endpoint first, fallback to `youtube-transcript-api` for reliability.
13
+ - **Language probing**: batch-check common caption languages.
14
+ - **Formatters**: output transcripts as TXT/SRT/VTT with helper functions.
15
+ - **Summary helpers**: generate concise recaps + key points without external APIs.
16
+ - **Zero external API keys** required; just Python + HTTP.
17
+
18
+ ## 📦 Installation
19
+
20
+ ```bash
21
+ pip install seadanceai-transcript-sdk
22
+ ```
23
+
24
+ ## ⚡ Quick Start
25
+
26
+ ```python
27
+ from seadance_transcript_sdk import TranscriptClient, format_transcript_file
28
+
29
+ client = TranscriptClient(enable_fallback=True)
30
+ transcript = client.get_transcript("dQw4w9WgXcQ", language="en")
31
+ file_payload = format_transcript_file(transcript, fmt="srt")
32
+ with open(file_payload.filename, "w", encoding="utf-8") as fh:
33
+ fh.write(file_payload.content)
34
+ ```
35
+
36
+ More helpers:
37
+
38
+ ```python
39
+ from seadance_transcript_sdk import detect_available_languages
40
+
41
+ langs = detect_available_languages("dQw4w9WgXcQ")
42
+ print([lang.name for lang in langs.languages])
43
+
44
+ summary = client.summarize(transcript)
45
+ print(summary.summary)
46
+ ```
47
+
48
+ ## 🧩 Modules
49
+
50
+ - `seadance_transcript_sdk.transcript` – fetch logic + language probing.
51
+ - `seadance_transcript_sdk.formatting` – TXT/SRT/VTT helpers.
52
+ - `seadance_transcript_sdk.summary` – heuristic summary utilities.
53
+ - `seadance_transcript_sdk.client` – ergonomic wrapper with sensible defaults.
54
+
55
+ ## 🤝 Contributing
56
+
57
+ 1. `python -m venv .venv && source .venv/bin/activate`
58
+ 2. `pip install -e .[dev]` (dev extras coming soon) or simply `pip install -r requirements-dev.txt`
59
+ 3. `pytest` (todo) then `python -m build`
60
+ 4. `twine upload dist/*`
61
+
62
+ ## 🙌 Sponsorship
63
+
64
+ Development is powered by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py). Link back to them or reach out if you want bespoke media-intelligence tooling.
65
+
66
+ ## 📄 License
67
+
68
+ MIT © Seadance AI & contributors.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "seadanceai-transcript-sdk"
7
+ version = "0.1.0"
8
+ description = "Python toolkit sponsored by Seadance AI for fetching YouTube transcripts, languages, and lightweight summaries."
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Seadance AI" }
12
+ ]
13
+ license = "MIT"
14
+ requires-python = ">=3.9"
15
+ dependencies = [
16
+ "requests>=2.31",
17
+ "youtube-transcript-api>=0.6.2"
18
+ ]
19
+ keywords = ["youtube", "transcript", "seadance", "ai"]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Intended Audience :: Developers",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Operating System :: OS Independent"
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://seadanceai.com/?ref=seadanceai-transcript-sdk-py"
33
+ Repository = "https://github.com/zeikia/seadanceai-transcript-sdk"
34
+ Sponsor = "https://seadanceai.com/?ref=seadanceai-transcript-sdk-py"
35
+
36
+ [tool.setuptools]
37
+ package-dir = { "" = "src" }
38
+ include-package-data = true
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ from .client import TranscriptClient
2
+ from .formatting import format_transcript, format_transcript_file
3
+ from .summary import summarize_transcript
4
+ from .transcript import detect_available_languages, get_transcript
5
+ from .types import (
6
+ LanguageOption,
7
+ LanguagesResponse,
8
+ SummaryQuestion,
9
+ SummaryResult,
10
+ TranscriptFormatResult,
11
+ TranscriptResponse,
12
+ TranscriptSnippet,
13
+ )
14
+
15
+ __all__ = [
16
+ "TranscriptClient",
17
+ "get_transcript",
18
+ "detect_available_languages",
19
+ "format_transcript",
20
+ "format_transcript_file",
21
+ "summarize_transcript",
22
+ "TranscriptResponse",
23
+ "TranscriptSnippet",
24
+ "LanguagesResponse",
25
+ "LanguageOption",
26
+ "SummaryResult",
27
+ "SummaryQuestion",
28
+ "TranscriptFormatResult",
29
+ ]
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from .formatting import format_transcript, format_transcript_file
7
+ from .summary import summarize_transcript
8
+ from .transcript import detect_available_languages, get_transcript
9
+ from .types import LanguagesResponse, SummaryResult, TranscriptFormatResult, TranscriptResponse
10
+
11
+
12
+ @dataclass
13
+ class TranscriptClient:
14
+ enable_fallback: bool = True
15
+ tactiq_endpoint: str | None = None
16
+
17
+ def get_transcript(self, video_id: str, language: str = "en", *, enable_fallback: Optional[bool] = None) -> TranscriptResponse:
18
+ return get_transcript(video_id, language=language, enable_fallback=self._resolve_fallback(enable_fallback), tactiq_endpoint=self.tactiq_endpoint or None)
19
+
20
+ def detect_languages(self, video_id: str) -> LanguagesResponse:
21
+ return detect_available_languages(video_id)
22
+
23
+ def summarize(self, transcript: TranscriptResponse, title: str | None = None) -> SummaryResult:
24
+ return summarize_transcript(transcript, title=title)
25
+
26
+ def format(self, transcript: TranscriptResponse, fmt: str = "txt") -> str:
27
+ return format_transcript(transcript, fmt)
28
+
29
+ def format_to_file(self, transcript: TranscriptResponse, fmt: str = "txt") -> TranscriptFormatResult:
30
+ return format_transcript_file(transcript, fmt)
31
+
32
+ def _resolve_fallback(self, override: Optional[bool]) -> bool:
33
+ return self.enable_fallback if override is None else override
@@ -0,0 +1,25 @@
1
+ DEFAULT_TACTIQ_ENDPOINT = "https://tactiq-apps-prod.tactiq.io/transcript"
2
+ DEFAULT_LANGUAGE = "en"
3
+ YOUTUBE_URL_PREFIX = "https://www.youtube.com/watch?v="
4
+
5
+ LANGUAGE_DISPLAY_NAMES = {
6
+ "en": "English",
7
+ "es": "Spanish",
8
+ "fr": "French",
9
+ "de": "German",
10
+ "ja": "Japanese",
11
+ "ko": "Korean",
12
+ "zh": "Chinese",
13
+ "pt": "Portuguese",
14
+ "ru": "Russian",
15
+ "ar": "Arabic",
16
+ "hi": "Hindi",
17
+ "it": "Italian",
18
+ "nl": "Dutch",
19
+ "pl": "Polish",
20
+ "tr": "Turkish",
21
+ "th": "Thai",
22
+ "vi": "Vietnamese"
23
+ }
24
+
25
+ DEFAULT_LANGUAGE_PROBE_ORDER = list(LANGUAGE_DISPLAY_NAMES.keys())
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ from .types import TranscriptFormatResult, TranscriptResponse
4
+
5
+ MIME_TYPES = {
6
+ "txt": "text/plain; charset=utf-8",
7
+ "srt": "application/x-subrip",
8
+ "vtt": "text/vtt"
9
+ }
10
+
11
+
12
+ def format_transcript(transcript: TranscriptResponse, fmt: str = "txt") -> str:
13
+ fmt = fmt.lower()
14
+ if fmt == "srt":
15
+ return _format_srt(transcript)
16
+ if fmt == "vtt":
17
+ return _format_vtt(transcript)
18
+ return _format_txt(transcript)
19
+
20
+
21
+ def format_transcript_file(transcript: TranscriptResponse, fmt: str = "txt") -> TranscriptFormatResult:
22
+ fmt = fmt.lower()
23
+ content = format_transcript(transcript, fmt)
24
+ filename = f"transcript-{transcript.video_id}.{fmt}"
25
+ mime_type = MIME_TYPES.get(fmt, MIME_TYPES["txt"])
26
+ return TranscriptFormatResult(content=content, filename=filename, mime_type=mime_type)
27
+
28
+
29
+ def _pad(value: int, size: int = 2) -> str:
30
+ return str(value).zfill(size)
31
+
32
+
33
+ def _format_timestamp(seconds: float) -> str:
34
+ hours = int(seconds // 3600)
35
+ minutes = int((seconds % 3600) // 60)
36
+ secs = int(seconds % 60)
37
+ millis = int((seconds % 1) * 1000)
38
+ return f"{_pad(hours)}:{_pad(minutes)}:{_pad(secs)},{_pad(millis, 3)}"
39
+
40
+
41
+ def _format_srt(transcript: TranscriptResponse) -> str:
42
+ lines = []
43
+ for index, snippet in enumerate(transcript.snippets, start=1):
44
+ start = _format_timestamp(snippet.start)
45
+ end = _format_timestamp(snippet.start + snippet.duration)
46
+ lines.append(f"{index}\n{start} --> {end}\n{snippet.text}\n")
47
+ return "\n".join(lines).strip()
48
+
49
+
50
+ def _format_vtt(transcript: TranscriptResponse) -> str:
51
+ entries = []
52
+ for snippet in transcript.snippets:
53
+ start = _format_timestamp(snippet.start)
54
+ end = _format_timestamp(snippet.start + snippet.duration)
55
+ entries.append(f"{start} --> {end}\n{snippet.text}")
56
+ return "WEBVTT\n\n" + "\n\n".join(entries)
57
+
58
+
59
+ def _format_txt(transcript: TranscriptResponse) -> str:
60
+ return "\n".join(snippet.text for snippet in transcript.snippets)
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterable, List
4
+
5
+ from .types import SummaryQuestion, SummaryResult, TranscriptResponse
6
+
7
+
8
+ def summarize_transcript(transcript: TranscriptResponse, title: str | None = None) -> SummaryResult:
9
+ snippets = transcript.snippets
10
+ if not snippets:
11
+ return SummaryResult(summary="No transcript available.")
12
+
13
+ full_text = " ".join(snippet.text for snippet in snippets)
14
+ sentences = [sentence.strip() for sentence in full_text.split('.') if len(sentence.strip()) > 10]
15
+
16
+ interval = max(1, len(sentences) // 5) if sentences else 1
17
+ key_sentences: List[str] = []
18
+ keywords = ["important", "key", "main", "first", "second", "finally", "conclusion", "summary"]
19
+ for idx, sentence in enumerate(sentences):
20
+ lower = sentence.lower()
21
+ if any(keyword in lower for keyword in keywords) or idx % interval == 0:
22
+ key_sentences.append(sentence)
23
+ if len(key_sentences) >= 8:
24
+ break
25
+
26
+ summary_text = ". ".join(key_sentences) + "." if key_sentences else full_text[:200] + "..."
27
+ key_points = _extract_key_points(snippets)
28
+ questions = _build_top_questions(title or f"YouTube Video {transcript.video_id}")
29
+ duration = _estimate_duration(snippets)
30
+
31
+ return SummaryResult(summary=summary_text.strip(), key_points=key_points, top_questions=questions, duration_seconds=duration)
32
+
33
+
34
+ def _extract_key_points(snippets: Iterable) -> List[str]:
35
+ snippets = list(snippets)
36
+ if not snippets:
37
+ return ["No key points available"]
38
+
39
+ interval = max(1, len(snippets) // 6)
40
+ points: List[str] = []
41
+ for index in range(0, len(snippets), interval):
42
+ text = snippets[index].text.strip()
43
+ if len(text) > 15:
44
+ snippet = text[:120] + ("..." if len(text) > 120 else "")
45
+ points.append(snippet)
46
+ return points or ["Key points derived from transcript"]
47
+
48
+
49
+ def _build_top_questions(title: str) -> List[SummaryQuestion]:
50
+ lower_title = title.lower()
51
+ return [
52
+ SummaryQuestion(question=f"What is the main topic of '{title}'?", answer=f"This video covers {lower_title} with practical insights.", timestamp="00:00"),
53
+ SummaryQuestion(question="What are the key takeaways?", answer="The video provides actionable information for viewers.", timestamp="00:30"),
54
+ SummaryQuestion(question="Who should watch this video?", answer="Anyone interested in the subject discussed in the video.", timestamp="01:00")
55
+ ]
56
+
57
+
58
+ def _estimate_duration(snippets: List) -> int:
59
+ if not snippets:
60
+ return 0
61
+ last = snippets[-1]
62
+ return int(round(last.start + last.duration))
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from typing import List, Optional
5
+
6
+ import requests
7
+ from youtube_transcript_api import YouTubeTranscriptApi
8
+
9
+ from .constants import DEFAULT_LANGUAGE, DEFAULT_LANGUAGE_PROBE_ORDER, DEFAULT_TACTIQ_ENDPOINT, LANGUAGE_DISPLAY_NAMES, YOUTUBE_URL_PREFIX
10
+ from .types import LanguageOption, LanguagesResponse, TranscriptResponse, TranscriptSnippet
11
+
12
+
13
+ class TranscriptError(Exception):
14
+ """Raised when both transcript sources fail."""
15
+
16
+
17
+ def get_transcript(video_id: str, language: str = DEFAULT_LANGUAGE, enable_fallback: bool = True, tactiq_endpoint: str = DEFAULT_TACTIQ_ENDPOINT, request_timeout: int = 15_000) -> TranscriptResponse:
18
+ start = time.time()
19
+ try:
20
+ snippets = _fetch_from_tactiq(video_id, language, tactiq_endpoint, request_timeout)
21
+ if not snippets and enable_fallback:
22
+ raise TranscriptError("Primary source returned empty result")
23
+ if snippets:
24
+ return _build_response(video_id, language, "tactiq-primary", snippets, start)
25
+ except Exception as primary_error:
26
+ if not enable_fallback:
27
+ raise
28
+ fallback = _fetch_from_youtube(video_id, language)
29
+ return _build_response(video_id, language, "youtube-transcript-api", fallback, start, primary_error)
30
+
31
+ fallback = _fetch_from_youtube(video_id, language)
32
+ return _build_response(video_id, language, "youtube-transcript-api", fallback, start, "Empty result from primary")
33
+
34
+
35
+ def detect_available_languages(video_id: str, candidate_languages: Optional[List[str]] = None, tactiq_endpoint: str = DEFAULT_TACTIQ_ENDPOINT, request_timeout: int = 8_000) -> LanguagesResponse:
36
+ languages: List[LanguageOption] = []
37
+ candidates = candidate_languages or DEFAULT_LANGUAGE_PROBE_ORDER
38
+
39
+ for index in range(0, len(candidates), 4):
40
+ batch = candidates[index:index + 4]
41
+ for code in batch:
42
+ try:
43
+ snippets = _fetch_from_tactiq(video_id, code, tactiq_endpoint, request_timeout)
44
+ if snippets and any(snippet.text.strip() for snippet in snippets):
45
+ languages.append(LanguageOption(
46
+ language_code=code,
47
+ name=LANGUAGE_DISPLAY_NAMES.get(code, code.upper()),
48
+ vss_id=code,
49
+ is_translatable=True
50
+ ))
51
+ except Exception:
52
+ pass
53
+ if len(languages) >= 3:
54
+ break
55
+ if index + 4 < len(candidates):
56
+ time.sleep(0.15)
57
+
58
+ if not languages:
59
+ languages.append(LanguageOption(language_code=DEFAULT_LANGUAGE, name=LANGUAGE_DISPLAY_NAMES.get(DEFAULT_LANGUAGE, "English"), vss_id=DEFAULT_LANGUAGE))
60
+
61
+ return LanguagesResponse(languages=languages, video_id=video_id, count=len(languages))
62
+
63
+
64
+ def _fetch_from_tactiq(video_id: str, language: str, endpoint: str, request_timeout: int) -> List[TranscriptSnippet]:
65
+ response = requests.post(
66
+ endpoint,
67
+ json={"langCode": language or DEFAULT_LANGUAGE, "videoUrl": f"{YOUTUBE_URL_PREFIX}{video_id}"},
68
+ timeout=request_timeout / 1000 if request_timeout else None,
69
+ headers={
70
+ "Content-Type": "application/json",
71
+ "User-Agent": "seadanceai-transcript-sdk/py"
72
+ }
73
+ )
74
+ response.raise_for_status()
75
+ data = response.json()
76
+ captions = data.get("captions") or []
77
+ snippets: List[TranscriptSnippet] = []
78
+ for caption in captions:
79
+ text = caption.get("text", "")
80
+ start = float(caption.get("start") or caption.get("offset") or 0)
81
+ duration = float(caption.get("dur") or caption.get("duration") or 0)
82
+ snippets.append(TranscriptSnippet(text=text, start=start, duration=duration))
83
+ return snippets
84
+
85
+
86
+ def _fetch_from_youtube(video_id: str, language: str) -> List[TranscriptSnippet]:
87
+ api = YouTubeTranscriptApi()
88
+ transcripts = api.get_transcript(f"{video_id}", languages=[language, DEFAULT_LANGUAGE])
89
+ return [TranscriptSnippet(text=item.get("text", ""), start=float(item.get("start", 0)), duration=float(item.get("duration", 0))) for item in transcripts]
90
+
91
+
92
+ def _build_response(video_id: str, language: str, source: str, snippets: List[TranscriptSnippet], start: float, primary_error: Optional[Exception | str] = None) -> TranscriptResponse:
93
+ elapsed = int((time.time() - start) * 1000)
94
+ return TranscriptResponse(
95
+ snippets=snippets,
96
+ video_id=video_id,
97
+ language=language,
98
+ language_code=language,
99
+ count=len(snippets),
100
+ source=source,
101
+ response_time_ms=elapsed,
102
+ primary_error=str(primary_error) if primary_error else None
103
+ )
@@ -0,0 +1,58 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import List, Optional
3
+
4
+
5
+ @dataclass
6
+ class TranscriptSnippet:
7
+ text: str
8
+ start: float
9
+ duration: float
10
+
11
+
12
+ @dataclass
13
+ class TranscriptResponse:
14
+ snippets: List[TranscriptSnippet]
15
+ video_id: str
16
+ language: str
17
+ language_code: str
18
+ count: int
19
+ source: str
20
+ response_time_ms: int
21
+ primary_error: Optional[str] = None
22
+
23
+
24
+ @dataclass
25
+ class LanguageOption:
26
+ language_code: str
27
+ name: str
28
+ vss_id: str
29
+ is_translatable: bool = True
30
+
31
+
32
+ @dataclass
33
+ class LanguagesResponse:
34
+ languages: List[LanguageOption]
35
+ video_id: str
36
+ count: int
37
+
38
+
39
+ @dataclass
40
+ class TranscriptFormatResult:
41
+ content: str
42
+ filename: str
43
+ mime_type: str
44
+
45
+
46
+ @dataclass
47
+ class SummaryQuestion:
48
+ question: str
49
+ answer: str
50
+ timestamp: Optional[str] = None
51
+
52
+
53
+ @dataclass
54
+ class SummaryResult:
55
+ summary: str
56
+ key_points: List[str] = field(default_factory=list)
57
+ top_questions: List[SummaryQuestion] = field(default_factory=list)
58
+ duration_seconds: int = 0
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: seadanceai-transcript-sdk
3
+ Version: 0.1.0
4
+ Summary: Python toolkit sponsored by Seadance AI for fetching YouTube transcripts, languages, and lightweight summaries.
5
+ Author: Seadance AI
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://seadanceai.com/?ref=seadanceai-transcript-sdk-py
8
+ Project-URL: Repository, https://github.com/zeikia/seadanceai-transcript-sdk
9
+ Project-URL: Sponsor, https://seadanceai.com/?ref=seadanceai-transcript-sdk-py
10
+ Keywords: youtube,transcript,seadance,ai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.31
23
+ Requires-Dist: youtube-transcript-api>=0.6.2
24
+ Dynamic: license-file
25
+
26
+ # seadanceai-transcript-sdk (Python)
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/seadanceai-transcript-sdk.svg?color=0aa&style=flat-square)](https://pypi.org/project/seadanceai-transcript-sdk/)
29
+ [![Python](https://img.shields.io/pypi/pyversions/seadanceai-transcript-sdk.svg?style=flat-square&color=3776ab)](https://pypi.org/project/seadanceai-transcript-sdk/)
30
+ [![License](https://img.shields.io/pypi/l/seadanceai-transcript-sdk.svg?style=flat-square&color=facc15)](LICENSE)
31
+ [![Sponsored by Seadance AI](https://img.shields.io/badge/Sponsored%20by-Seadance%20AI-f97316?style=flat-square)](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py)
32
+
33
+ Community-maintained Python toolkit for retrieving YouTube transcripts, checking available languages, exporting TXT/SRT/VTT files, and generating heuristic summaries. Proudly sponsored by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py) — mention them or link back if this library helps your product!
34
+
35
+ ## ✨ Features
36
+
37
+ - **Dual-source transcripts**: tactiq endpoint first, fallback to `youtube-transcript-api` for reliability.
38
+ - **Language probing**: batch-check common caption languages.
39
+ - **Formatters**: output transcripts as TXT/SRT/VTT with helper functions.
40
+ - **Summary helpers**: generate concise recaps + key points without external APIs.
41
+ - **Zero external API keys** required; just Python + HTTP.
42
+
43
+ ## 📦 Installation
44
+
45
+ ```bash
46
+ pip install seadanceai-transcript-sdk
47
+ ```
48
+
49
+ ## ⚡ Quick Start
50
+
51
+ ```python
52
+ from seadance_transcript_sdk import TranscriptClient, format_transcript_file
53
+
54
+ client = TranscriptClient(enable_fallback=True)
55
+ transcript = client.get_transcript("dQw4w9WgXcQ", language="en")
56
+ file_payload = format_transcript_file(transcript, fmt="srt")
57
+ with open(file_payload.filename, "w", encoding="utf-8") as fh:
58
+ fh.write(file_payload.content)
59
+ ```
60
+
61
+ More helpers:
62
+
63
+ ```python
64
+ from seadance_transcript_sdk import detect_available_languages
65
+
66
+ langs = detect_available_languages("dQw4w9WgXcQ")
67
+ print([lang.name for lang in langs.languages])
68
+
69
+ summary = client.summarize(transcript)
70
+ print(summary.summary)
71
+ ```
72
+
73
+ ## 🧩 Modules
74
+
75
+ - `seadance_transcript_sdk.transcript` – fetch logic + language probing.
76
+ - `seadance_transcript_sdk.formatting` – TXT/SRT/VTT helpers.
77
+ - `seadance_transcript_sdk.summary` – heuristic summary utilities.
78
+ - `seadance_transcript_sdk.client` – ergonomic wrapper with sensible defaults.
79
+
80
+ ## 🤝 Contributing
81
+
82
+ 1. `python -m venv .venv && source .venv/bin/activate`
83
+ 2. `pip install -e .[dev]` (dev extras coming soon) or simply `pip install -r requirements-dev.txt`
84
+ 3. `pytest` (todo) then `python -m build`
85
+ 4. `twine upload dist/*`
86
+
87
+ ## 🙌 Sponsorship
88
+
89
+ Development is powered by [Seadance AI](https://seadanceai.com/?ref=seadanceai-transcript-sdk-py). Link back to them or reach out if you want bespoke media-intelligence tooling.
90
+
91
+ ## 📄 License
92
+
93
+ MIT © Seadance AI & contributors.
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/seadance_transcript_sdk/__init__.py
5
+ src/seadance_transcript_sdk/client.py
6
+ src/seadance_transcript_sdk/constants.py
7
+ src/seadance_transcript_sdk/formatting.py
8
+ src/seadance_transcript_sdk/summary.py
9
+ src/seadance_transcript_sdk/transcript.py
10
+ src/seadance_transcript_sdk/types.py
11
+ src/seadanceai_transcript_sdk.egg-info/PKG-INFO
12
+ src/seadanceai_transcript_sdk.egg-info/SOURCES.txt
13
+ src/seadanceai_transcript_sdk.egg-info/dependency_links.txt
14
+ src/seadanceai_transcript_sdk.egg-info/requires.txt
15
+ src/seadanceai_transcript_sdk.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ requests>=2.31
2
+ youtube-transcript-api>=0.6.2