vctx 0.1.0__py3-none-any.whl

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.
Files changed (53) hide show
  1. vctx/__init__.py +5 -0
  2. vctx/app/__init__.py +0 -0
  3. vctx/app/chunk.py +38 -0
  4. vctx/app/credentials.py +55 -0
  5. vctx/app/doctor.py +42 -0
  6. vctx/app/metadata.py +30 -0
  7. vctx/app/prepare.py +804 -0
  8. vctx/app/render.py +69 -0
  9. vctx/app/result.py +112 -0
  10. vctx/chunking.py +75 -0
  11. vctx/cli.py +221 -0
  12. vctx/config.py +552 -0
  13. vctx/errors.py +25 -0
  14. vctx/io.py +60 -0
  15. vctx/models/__init__.py +10 -0
  16. vctx/models/acquisition.py +108 -0
  17. vctx/models/artifacts.py +37 -0
  18. vctx/models/knowledge_flow.py +40 -0
  19. vctx/models/manifest.py +99 -0
  20. vctx/models/media.py +127 -0
  21. vctx/models/metadata.py +18 -0
  22. vctx/models/visual.py +181 -0
  23. vctx/net.py +239 -0
  24. vctx/render/__init__.py +0 -0
  25. vctx/render/bundle.py +107 -0
  26. vctx/render/markdown.py +287 -0
  27. vctx/sources/__init__.py +0 -0
  28. vctx/sources/detect.py +43 -0
  29. vctx/sources/local_file_source.py +80 -0
  30. vctx/sources/ytdlp_source.py +480 -0
  31. vctx/subtitles.py +54 -0
  32. vctx/transcript.py +136 -0
  33. vctx/transforms/__init__.py +0 -0
  34. vctx/transforms/ai_routes.py +205 -0
  35. vctx/transforms/asr.py +291 -0
  36. vctx/transforms/knowledge_flow.py +248 -0
  37. vctx/transforms/model_resolution.py +347 -0
  38. vctx/transforms/planning.py +178 -0
  39. vctx/transforms/text_ai.py +172 -0
  40. vctx/transforms/visual_cases.py +245 -0
  41. vctx/transforms/visual_evidence.py +287 -0
  42. vctx/transforms/visual_execute.py +150 -0
  43. vctx/transforms/visual_frames.py +95 -0
  44. vctx/transforms/visual_ocr.py +81 -0
  45. vctx/transforms/visual_planning.py +344 -0
  46. vctx/transforms/visual_routes.py +150 -0
  47. vctx/transforms/visual_vlm.py +171 -0
  48. vctx/util.py +19 -0
  49. vctx-0.1.0.dist-info/METADATA +25 -0
  50. vctx-0.1.0.dist-info/RECORD +53 -0
  51. vctx-0.1.0.dist-info/WHEEL +4 -0
  52. vctx-0.1.0.dist-info/entry_points.txt +2 -0
  53. vctx-0.1.0.dist-info/licenses/LICENSE +21 -0
vctx/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from vctx.cli import main
4
+
5
+ __all__ = ["main"]
vctx/app/__init__.py ADDED
File without changes
vctx/app/chunk.py ADDED
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from pydantic import ValidationError
6
+
7
+ from vctx.chunking import ChunkOptions, chunk_transcript
8
+ from vctx.errors import InvalidTranscriptError, VctxError
9
+ from vctx.io import model_to_json
10
+ from vctx.transcript import Transcript
11
+
12
+
13
+ class ChunkWriteError(VctxError):
14
+ exit_code = 1
15
+
16
+
17
+ def write_chunk_file(
18
+ transcript_path: Path,
19
+ out_path: Path,
20
+ *,
21
+ max_chars: int = 6000,
22
+ max_seconds: int | None = None,
23
+ ) -> Path:
24
+ try:
25
+ transcript = Transcript.model_validate_json(transcript_path.read_text(encoding="utf-8"))
26
+ except (OSError, ValidationError) as exc:
27
+ raise InvalidTranscriptError(f"invalid transcript file: {transcript_path}") from exc
28
+
29
+ chunks = chunk_transcript(
30
+ transcript,
31
+ ChunkOptions(max_chars=max_chars, max_seconds=max_seconds),
32
+ )
33
+ try:
34
+ out_path.parent.mkdir(parents=True, exist_ok=True)
35
+ out_path.write_text(model_to_json(chunks), encoding="utf-8")
36
+ except OSError as exc:
37
+ raise ChunkWriteError(f"failed to write chunks: {out_path}: {exc}") from exc
38
+ return out_path
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Iterable, Mapping
5
+ from pathlib import Path
6
+
7
+
8
+ class CredentialError(RuntimeError):
9
+ pass
10
+
11
+
12
+ def env_with_credential_presence(
13
+ names: Iterable[str], *, env_files: list[Path], base_env: Mapping[str, str]
14
+ ) -> dict[str, str]:
15
+ env = dict(base_env)
16
+ for name in names:
17
+ if name in env:
18
+ continue
19
+ if any(_read_dotenv_value(env_file, name) for env_file in env_files):
20
+ env[name] = "[present]"
21
+ return env
22
+
23
+
24
+ def resolve_env_credential(name: str | None, *, env_files: list[Path]) -> str:
25
+ if not name:
26
+ raise CredentialError("ASR instance is missing api_key_env")
27
+ value = os.environ.get(name)
28
+ if value:
29
+ return value
30
+ for env_file in env_files:
31
+ dotenv_value = _read_dotenv_value(env_file, name)
32
+ if dotenv_value:
33
+ return dotenv_value
34
+ searched = ", ".join(str(path) for path in env_files) or "no env files"
35
+ raise CredentialError(f"missing credential {name}; searched shell environment and {searched}")
36
+
37
+
38
+ def _read_dotenv_value(path: Path, name: str) -> str | None:
39
+ if not path.exists():
40
+ return None
41
+ for raw_line in path.read_text(encoding="utf-8").splitlines():
42
+ line = raw_line.strip()
43
+ if not line or line.startswith("#") or "=" not in line:
44
+ continue
45
+ key, value = line.split("=", 1)
46
+ if key.strip() != name:
47
+ continue
48
+ return _strip_dotenv_quotes(value.strip())
49
+ return None
50
+
51
+
52
+ def _strip_dotenv_quotes(value: str) -> str:
53
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in {'"', "'"}:
54
+ return value[1:-1]
55
+ return value
vctx/app/doctor.py ADDED
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.metadata
4
+ import shutil
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from vctx.io import build_cache
9
+
10
+
11
+ def doctor_report() -> str:
12
+ lines = [
13
+ f"python: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
14
+ f"vctx: {_package_version('vctx')}",
15
+ f"yt-dlp: {_package_version('yt-dlp')}",
16
+ f"cache: {_cache_status()}",
17
+ f"ffmpeg: {_command_status('ffmpeg')}",
18
+ ]
19
+ return "\n".join(lines) + "\n"
20
+
21
+
22
+ def _package_version(distribution: str) -> str:
23
+ try:
24
+ return importlib.metadata.version(distribution)
25
+ except importlib.metadata.PackageNotFoundError:
26
+ return "missing"
27
+
28
+
29
+ def _cache_status() -> str:
30
+ try:
31
+ cache = build_cache(None)
32
+ probe = Path(cache.root) / ".doctor-write-test"
33
+ probe.write_text("ok", encoding="utf-8")
34
+ probe.unlink(missing_ok=True)
35
+ except OSError as exc:
36
+ return f"error: {exc}"
37
+ return f"writable ({cache.root})"
38
+
39
+
40
+ def _command_status(command: str) -> str:
41
+ path = shutil.which(command)
42
+ return path if path else "missing"
vctx/app/metadata.py ADDED
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from vctx.models.metadata import VideoMetadata
4
+ from vctx.sources.detect import detect_source_adapter
5
+
6
+
7
+ def inspect_metadata(value: str) -> VideoMetadata:
8
+ adapter = detect_source_adapter(value)
9
+ return adapter.extract_metadata(value)
10
+
11
+
12
+ def render_metadata_text(metadata: VideoMetadata) -> str:
13
+ lines: list[str] = [
14
+ f"id: {metadata.id}",
15
+ f"source_type: {metadata.source_type}",
16
+ f"source: {metadata.source.value}",
17
+ ]
18
+ optional_fields = {
19
+ "title": metadata.title,
20
+ "uploader": metadata.uploader,
21
+ "duration_seconds": metadata.duration_seconds,
22
+ "webpage_url": metadata.webpage_url,
23
+ "language": metadata.language,
24
+ "extractor": metadata.extractor,
25
+ "raw_provider": metadata.raw_provider,
26
+ }
27
+ for key, value in optional_fields.items():
28
+ if value is not None:
29
+ lines.append(f"{key}: {value}")
30
+ return "\n".join(lines) + "\n"