mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-10 23:08:06 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
826ac586ee | ||
|
|
ec14e42abf | ||
|
|
6708c7481b | ||
|
|
75e11724b4 | ||
|
|
2dd79a66d7 | ||
|
|
b7fa02d91e |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.329 (2025-11-20)
|
||||
|
||||
### PR [#1838](https://github.com/danielmiessler/fabric/pull/1838) by [ksylvan](https://github.com/ksylvan): refactor: implement i18n support for YouTube tool error messages
|
||||
|
||||
- Replace hardcoded error strings with i18n translation calls
|
||||
- Add localization keys for YouTube errors to all locale files
|
||||
- Introduce `extractAndValidateVideoId` helper to reduce code duplication
|
||||
- Update timestamp parsing logic to handle localized error formats
|
||||
- Standardize error handling in `yt-dlp` execution with i18n
|
||||
|
||||
## v1.4.328 (2025-11-18)
|
||||
|
||||
### PR [#1836](https://github.com/danielmiessler/Fabric/pull/1836) by [ksylvan](https://github.com/ksylvan): docs: clarify `--raw` flag behavior for OpenAI and Anthropic providers
|
||||
|
||||
- Update `--raw` flag description across all documentation files
|
||||
- Clarify flag only affects OpenAI-compatible providers behavior
|
||||
- Document Anthropic models use smart parameter selection
|
||||
- Remove outdated reference to system/user role changes
|
||||
- Update help text in CLI flags definition
|
||||
|
||||
## v1.4.327 (2025-11-16)
|
||||
|
||||
### PR [#1831](https://github.com/danielmiessler/Fabric/pull/1831) by [ksylvan](https://github.com/ksylvan): Remove `get_youtube_rss` pattern
|
||||
|
||||
@@ -623,9 +623,10 @@ Application Options:
|
||||
-T, --topp= Set top P (default: 0.9)
|
||||
-s, --stream Stream
|
||||
-P, --presencepenalty= Set presence penalty (default: 0.0)
|
||||
-r, --raw Use the defaults of the model without sending chat options (like
|
||||
temperature etc.) and use the user role instead of the system role for
|
||||
patterns.
|
||||
-r, --raw Use the defaults of the model without sending chat options
|
||||
(temperature, top_p, etc.). Only affects OpenAI-compatible providers.
|
||||
Anthropic models always use smart parameter selection to comply with
|
||||
model-specific requirements.
|
||||
-F, --frequencypenalty= Set frequency penalty (default: 0.0)
|
||||
-l, --listpatterns List all patterns
|
||||
-L, --listmodels List all available models
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.327"
|
||||
var version = "v1.4.329"
|
||||
|
||||
Binary file not shown.
@@ -81,7 +81,7 @@ _fabric() {
|
||||
'(-T --topp)'{-T,--topp}'[Set top P (default: 0.9)]:topp:' \
|
||||
'(-s --stream)'{-s,--stream}'[Stream]' \
|
||||
'(-P --presencepenalty)'{-P,--presencepenalty}'[Set presence penalty (default: 0.0)]:presence penalty:' \
|
||||
'(-r --raw)'{-r,--raw}'[Use the defaults of the model without sending chat options]' \
|
||||
'(-r --raw)'{-r,--raw}'[Use the defaults of the model without sending chat options. Only affects OpenAI-compatible providers. Anthropic models always use smart parameter selection to comply with model-specific requirements.]' \
|
||||
'(-F --frequencypenalty)'{-F,--frequencypenalty}'[Set frequency penalty (default: 0.0)]:frequency penalty:' \
|
||||
'(-l --listpatterns)'{-l,--listpatterns}'[List all patterns]' \
|
||||
'(-L --listmodels)'{-L,--listmodels}'[List all available models]' \
|
||||
|
||||
@@ -105,7 +105,7 @@ function __fabric_register_completions
|
||||
# Boolean flags (no arguments)
|
||||
complete -c $cmd -s S -l setup -d "Run setup for all reconfigurable parts of fabric"
|
||||
complete -c $cmd -s s -l stream -d "Stream"
|
||||
complete -c $cmd -s r -l raw -d "Use the defaults of the model without sending chat options"
|
||||
complete -c $cmd -s r -l raw -d "Use the defaults of the model without sending chat options. Only affects OpenAI-compatible providers. Anthropic models always use smart parameter selection to comply with model-specific requirements."
|
||||
complete -c $cmd -s l -l listpatterns -d "List all patterns"
|
||||
complete -c $cmd -s L -l listmodels -d "List all available models"
|
||||
complete -c $cmd -s x -l listcontexts -d "List all contexts"
|
||||
|
||||
@@ -35,7 +35,7 @@ type Flags struct {
|
||||
TopP float64 `short:"T" long:"topp" yaml:"topp" description:"Set top P" default:"0.9"`
|
||||
Stream bool `short:"s" long:"stream" yaml:"stream" description:"Stream"`
|
||||
PresencePenalty float64 `short:"P" long:"presencepenalty" yaml:"presencepenalty" description:"Set presence penalty" default:"0.0"`
|
||||
Raw bool `short:"r" long:"raw" yaml:"raw" description:"Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns."`
|
||||
Raw bool `short:"r" long:"raw" yaml:"raw" description:"Use the defaults of the model without sending chat options (temperature, top_p, etc.). Only affects OpenAI-compatible providers. Anthropic models always use smart parameter selection to comply with model-specific requirements."`
|
||||
FrequencyPenalty float64 `short:"F" long:"frequencypenalty" yaml:"frequencypenalty" description:"Set frequency penalty" default:"0.0"`
|
||||
ListPatterns bool `short:"l" long:"listpatterns" description:"List all patterns"`
|
||||
ListAllModels bool `short:"L" long:"listmodels" description:"List all available models"`
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "Anbieter %s unterstützt keine Audio-Transkription",
|
||||
"transcription_model_required": "Transkriptionsmodell ist erforderlich (verwende --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube ist nicht konfiguriert, bitte führe das Setup-Verfahren aus",
|
||||
"youtube_api_key_required": "YouTube API-Schlüssel für Kommentare und Metadaten erforderlich. Führe 'fabric --setup' aus, um zu konfigurieren",
|
||||
"youtube_ytdlp_not_found": "yt-dlp wurde nicht in PATH gefunden. Bitte installiere yt-dlp, um die YouTube-Transkript-Funktionalität zu nutzen",
|
||||
"youtube_invalid_url": "ungültige YouTube-URL, kann keine Video- oder Playlist-ID abrufen: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "URL ist eine Playlist, kein Video",
|
||||
"youtube_no_video_id_found": "keine Video-ID in URL gefunden",
|
||||
"youtube_rate_limit_exceeded": "YouTube-Ratenlimit überschritten. Versuche es später erneut oder verwende andere yt-dlp-Argumente wie '--sleep-requests 1', um Anfragen zu verlangsamen.",
|
||||
"youtube_auth_required_bot_detection": "YouTube erfordert Authentifizierung (Bot-Erkennung). Verwende --yt-dlp-args='--cookies-from-browser BROWSER' wobei BROWSER chrome, firefox, brave usw. sein kann.",
|
||||
"youtube_ytdlp_stderr_error": "Fehler beim Lesen von yt-dlp stderr",
|
||||
"youtube_invalid_ytdlp_arguments": "ungültige yt-dlp-Argumente: %v",
|
||||
"youtube_failed_create_temp_dir": "temporäres Verzeichnis konnte nicht erstellt werden: %v",
|
||||
"youtube_no_transcript_content": "kein Transkriptinhalt in VTT-Datei gefunden",
|
||||
"youtube_no_vtt_files_found": "keine VTT-Dateien im Verzeichnis gefunden",
|
||||
"youtube_failed_walk_directory": "Verzeichnis konnte nicht durchlaufen werden: %v",
|
||||
"youtube_error_getting_video_details": "Fehler beim Abrufen der Videodetails: %v",
|
||||
"youtube_invalid_duration_string": "ungültige Dauer-Zeichenfolge: %s",
|
||||
"youtube_error_getting_metadata": "Fehler beim Abrufen der Video-Metadaten: %v",
|
||||
"youtube_error_parsing_duration": "Fehler beim Parsen der Videodauer: %v",
|
||||
"youtube_error_getting_comments": "Fehler beim Abrufen der Kommentare: %v",
|
||||
"youtube_error_saving_csv": "Fehler beim Speichern der Videos in CSV: %v",
|
||||
"youtube_no_video_found_with_id": "kein Video mit ID gefunden: %s",
|
||||
"youtube_invalid_timestamp_format": "ungültiges Zeitstempel-Format: %s",
|
||||
"youtube_empty_seconds_string": "leere Sekunden-Zeichenfolge",
|
||||
"youtube_invalid_seconds_format": "ungültiges Sekundenformat %q: %w",
|
||||
"error_fetching_playlist_videos": "Fehler beim Abrufen der Playlist-Videos: %w",
|
||||
"scraping_not_configured": "Scraping-Funktionalität ist nicht konfiguriert. Bitte richte Jina ein, um Scraping zu aktivieren",
|
||||
"could_not_determine_home_dir": "konnte Benutzer-Home-Verzeichnis nicht bestimmen: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Top P festlegen",
|
||||
"stream_help": "Streaming",
|
||||
"set_presence_penalty": "Präsenzstrafe festlegen",
|
||||
"use_model_defaults_raw_help": "Verwende die Standardwerte des Modells ohne Senden von Chat-Optionen (wie Temperatur usw.) und verwende die Benutzerrolle anstelle der Systemrolle für Muster.",
|
||||
"use_model_defaults_raw_help": "Verwende die Standardwerte des Modells, ohne Chat-Optionen (temperature, top_p usw.) zu senden. Gilt nur für OpenAI-kompatible Anbieter. Anthropic-Modelle verwenden stets eine intelligente Parameterauswahl, um modell-spezifische Anforderungen einzuhalten.",
|
||||
"set_frequency_penalty": "Häufigkeitsstrafe festlegen",
|
||||
"list_all_patterns": "Alle Muster auflisten",
|
||||
"list_all_available_models": "Alle verfügbaren Modelle auflisten",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "vendor %s does not support audio transcription",
|
||||
"transcription_model_required": "transcription model is required (use --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube is not configured, please run the setup procedure",
|
||||
"youtube_api_key_required": "YouTube API key required for comments and metadata. Run 'fabric --setup' to configure",
|
||||
"youtube_ytdlp_not_found": "yt-dlp not found in PATH. Please install yt-dlp to use YouTube transcript functionality",
|
||||
"youtube_invalid_url": "invalid YouTube URL, can't get video or playlist ID: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "URL is a playlist, not a video",
|
||||
"youtube_no_video_id_found": "no video ID found in URL",
|
||||
"youtube_rate_limit_exceeded": "YouTube rate limit exceeded. Try again later or use different yt-dlp arguments like '--sleep-requests 1' to slow down requests.",
|
||||
"youtube_auth_required_bot_detection": "YouTube requires authentication (bot detection). Use --yt-dlp-args='--cookies-from-browser BROWSER' where BROWSER is chrome, firefox, brave, etc.",
|
||||
"youtube_ytdlp_stderr_error": "Error reading yt-dlp stderr",
|
||||
"youtube_invalid_ytdlp_arguments": "invalid yt-dlp arguments: %v",
|
||||
"youtube_failed_create_temp_dir": "failed to create temp directory: %v",
|
||||
"youtube_no_transcript_content": "no transcript content found in VTT file",
|
||||
"youtube_no_vtt_files_found": "no VTT files found in directory",
|
||||
"youtube_failed_walk_directory": "failed to walk directory: %v",
|
||||
"youtube_error_getting_video_details": "error getting video details: %v",
|
||||
"youtube_invalid_duration_string": "invalid duration string: %s",
|
||||
"youtube_error_getting_metadata": "error getting video metadata: %v",
|
||||
"youtube_error_parsing_duration": "error parsing video duration: %v",
|
||||
"youtube_error_getting_comments": "error getting comments: %v",
|
||||
"youtube_error_saving_csv": "error saving videos to CSV: %v",
|
||||
"youtube_no_video_found_with_id": "no video found with ID: %s",
|
||||
"youtube_invalid_timestamp_format": "invalid timestamp format: %s",
|
||||
"youtube_empty_seconds_string": "empty seconds string",
|
||||
"youtube_invalid_seconds_format": "invalid seconds format %q: %w",
|
||||
"error_fetching_playlist_videos": "error fetching playlist videos: %w",
|
||||
"scraping_not_configured": "scraping functionality is not configured. Please set up Jina to enable scraping",
|
||||
"could_not_determine_home_dir": "could not determine user home directory: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Set top P",
|
||||
"stream_help": "Stream",
|
||||
"set_presence_penalty": "Set presence penalty",
|
||||
"use_model_defaults_raw_help": "Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns.",
|
||||
"use_model_defaults_raw_help": "Use the defaults of the model without sending chat options (temperature, top_p, etc.). Only affects OpenAI-compatible providers. Anthropic models always use smart parameter selection to comply with model-specific requirements.",
|
||||
"set_frequency_penalty": "Set frequency penalty",
|
||||
"list_all_patterns": "List all patterns",
|
||||
"list_all_available_models": "List all available models",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "el proveedor %s no admite transcripción de audio",
|
||||
"transcription_model_required": "se requiere un modelo de transcripción (usa --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube no está configurado, por favor ejecuta el procedimiento de configuración",
|
||||
"youtube_api_key_required": "Se requiere clave de API de YouTube para comentarios y metadatos. Ejecuta 'fabric --setup' para configurar",
|
||||
"youtube_ytdlp_not_found": "yt-dlp no encontrado en PATH. Por favor instala yt-dlp para usar la funcionalidad de transcripción de YouTube",
|
||||
"youtube_invalid_url": "URL de YouTube inválida, no se puede obtener ID de video o lista de reproducción: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "La URL es una lista de reproducción, no un video",
|
||||
"youtube_no_video_id_found": "no se encontró ID de video en la URL",
|
||||
"youtube_rate_limit_exceeded": "Límite de tasa de YouTube excedido. Intenta de nuevo más tarde o usa diferentes argumentos de yt-dlp como '--sleep-requests 1' para ralentizar las solicitudes.",
|
||||
"youtube_auth_required_bot_detection": "YouTube requiere autenticación (detección de bot). Usa --yt-dlp-args='--cookies-from-browser BROWSER' donde BROWSER puede ser chrome, firefox, brave, etc.",
|
||||
"youtube_ytdlp_stderr_error": "Error al leer stderr de yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "argumentos de yt-dlp inválidos: %v",
|
||||
"youtube_failed_create_temp_dir": "falló al crear directorio temporal: %v",
|
||||
"youtube_no_transcript_content": "no se encontró contenido de transcripción en el archivo VTT",
|
||||
"youtube_no_vtt_files_found": "no se encontraron archivos VTT en el directorio",
|
||||
"youtube_failed_walk_directory": "falló al recorrer el directorio: %v",
|
||||
"youtube_error_getting_video_details": "error al obtener detalles del video: %v",
|
||||
"youtube_invalid_duration_string": "cadena de duración inválida: %s",
|
||||
"youtube_error_getting_metadata": "error al obtener metadatos del video: %v",
|
||||
"youtube_error_parsing_duration": "error al analizar la duración del video: %v",
|
||||
"youtube_error_getting_comments": "error al obtener comentarios: %v",
|
||||
"youtube_error_saving_csv": "error al guardar videos en CSV: %v",
|
||||
"youtube_no_video_found_with_id": "no se encontró video con ID: %s",
|
||||
"youtube_invalid_timestamp_format": "formato de marca de tiempo inválido: %s",
|
||||
"youtube_empty_seconds_string": "cadena de segundos vacía",
|
||||
"youtube_invalid_seconds_format": "formato de segundos inválido %q: %w",
|
||||
"error_fetching_playlist_videos": "error al obtener videos de la lista de reproducción: %w",
|
||||
"scraping_not_configured": "la funcionalidad de extracción no está configurada. Por favor configura Jina para habilitar la extracción",
|
||||
"could_not_determine_home_dir": "no se pudo determinar el directorio home del usuario: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Establecer top P",
|
||||
"stream_help": "Transmitir",
|
||||
"set_presence_penalty": "Establecer penalización de presencia",
|
||||
"use_model_defaults_raw_help": "Usar los valores predeterminados del modelo sin enviar opciones de chat (como temperatura, etc.) y usar el rol de usuario en lugar del rol del sistema para patrones.",
|
||||
"use_model_defaults_raw_help": "Utiliza los valores predeterminados del modelo sin enviar opciones de chat (temperature, top_p, etc.). Solo afecta a los proveedores compatibles con OpenAI. Los modelos de Anthropic siempre usan una selección inteligente de parámetros para cumplir los requisitos específicos del modelo.",
|
||||
"set_frequency_penalty": "Establecer penalización de frecuencia",
|
||||
"list_all_patterns": "Listar todos los patrones",
|
||||
"list_all_available_models": "Listar todos los modelos disponibles",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "تامینکننده %s از رونویسی صوتی پشتیبانی نمیکند",
|
||||
"transcription_model_required": "مدل رونویسی الزامی است (از --transcribe-model استفاده کنید)",
|
||||
"youtube_not_configured": "یوتیوب پیکربندی نشده است، لطفاً روند تنظیمات را اجرا کنید",
|
||||
"youtube_api_key_required": "کلید API یوتیوب برای دریافت نظرات و متادیتا الزامی است. برای پیکربندی 'fabric --setup' را اجرا کنید",
|
||||
"youtube_ytdlp_not_found": "yt-dlp در PATH یافت نشد. لطفاً yt-dlp را نصب کنید تا از قابلیت رونویسی یوتیوب استفاده کنید",
|
||||
"youtube_invalid_url": "URL یوتیوب نامعتبر است، نمیتوان ID ویدیو یا فهرست پخش را دریافت کرد: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "URL یک فهرست پخش است، نه یک ویدیو",
|
||||
"youtube_no_video_id_found": "هیچ ID ویدیویی در URL یافت نشد",
|
||||
"youtube_rate_limit_exceeded": "محدودیت نرخ یوتیوب فراتر رفته است. بعداً دوباره امتحان کنید یا از آرگومانهای مختلف yt-dlp مانند '--sleep-requests 1' برای کاهش سرعت درخواستها استفاده کنید.",
|
||||
"youtube_auth_required_bot_detection": "یوتیوب احراز هویت میخواهد (تشخیص ربات). از --yt-dlp-args='--cookies-from-browser BROWSER' استفاده کنید که BROWSER میتواند chrome، firefox، brave و غیره باشد.",
|
||||
"youtube_ytdlp_stderr_error": "خطا در خواندن stderr yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "آرگومانهای yt-dlp نامعتبر: %v",
|
||||
"youtube_failed_create_temp_dir": "ایجاد دایرکتوری موقت ناموفق بود: %v",
|
||||
"youtube_no_transcript_content": "محتوای رونوشتی در فایل VTT یافت نشد",
|
||||
"youtube_no_vtt_files_found": "فایلهای VTT در دایرکتوری یافت نشدند",
|
||||
"youtube_failed_walk_directory": "پیمایش دایرکتوری ناموفق بود: %v",
|
||||
"youtube_error_getting_video_details": "خطا در دریافت جزئیات ویدیو: %v",
|
||||
"youtube_invalid_duration_string": "رشته مدت زمان نامعتبر: %s",
|
||||
"youtube_error_getting_metadata": "خطا در دریافت متادیتای ویدیو: %v",
|
||||
"youtube_error_parsing_duration": "خطا در تجزیه مدت زمان ویدیو: %v",
|
||||
"youtube_error_getting_comments": "خطا در دریافت نظرات: %v",
|
||||
"youtube_error_saving_csv": "خطا در ذخیره ویدیوها در CSV: %v",
|
||||
"youtube_no_video_found_with_id": "هیچ ویدیویی با ID یافت نشد: %s",
|
||||
"youtube_invalid_timestamp_format": "فرمت مهر زمانی نامعتبر: %s",
|
||||
"youtube_empty_seconds_string": "رشته ثانیه خالی",
|
||||
"youtube_invalid_seconds_format": "فرمت ثانیه نامعتبر %q: %w",
|
||||
"error_fetching_playlist_videos": "خطا در دریافت ویدیوهای فهرست پخش: %w",
|
||||
"scraping_not_configured": "قابلیت استخراج داده پیکربندی نشده است. لطفاً Jina را برای فعالسازی استخراج تنظیم کنید",
|
||||
"could_not_determine_home_dir": "نتوانست دایرکتوری خانه کاربر را تعیین کند: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "تنظیم top P",
|
||||
"stream_help": "پخش زنده",
|
||||
"set_presence_penalty": "تنظیم جریمه حضور",
|
||||
"use_model_defaults_raw_help": "استفاده از پیشفرضهای مدل بدون ارسال گزینههای گفتگو (مثل دما و غیره) و استفاده از نقش کاربر به جای نقش سیستم برای الگوها.",
|
||||
"use_model_defaults_raw_help": "از مقادیر پیشفرض مدل بدون ارسال گزینههای چت (temperature، top_p و غیره) استفاده میکند. فقط بر ارائهدهندگان سازگار با OpenAI تأثیر میگذارد. مدلهای Anthropic همواره برای رعایت نیازهای خاص هر مدل از انتخاب هوشمند پارامتر استفاده میکنند.",
|
||||
"set_frequency_penalty": "تنظیم جریمه فرکانس",
|
||||
"list_all_patterns": "فهرست تمام الگوها",
|
||||
"list_all_available_models": "فهرست تمام مدلهای موجود",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "le fournisseur %s ne prend pas en charge la transcription audio",
|
||||
"transcription_model_required": "un modèle de transcription est requis (utilisez --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube n'est pas configuré, veuillez exécuter la procédure de configuration",
|
||||
"youtube_api_key_required": "Clé API YouTube requise pour les commentaires et métadonnées. Exécutez 'fabric --setup' pour configurer",
|
||||
"youtube_ytdlp_not_found": "yt-dlp introuvable dans PATH. Veuillez installer yt-dlp pour utiliser la fonctionnalité de transcription YouTube",
|
||||
"youtube_invalid_url": "URL YouTube invalide, impossible d'obtenir l'ID de vidéo ou de liste de lecture : '%s'",
|
||||
"youtube_url_is_playlist_not_video": "L'URL est une liste de lecture, pas une vidéo",
|
||||
"youtube_no_video_id_found": "aucun ID de vidéo trouvé dans l'URL",
|
||||
"youtube_rate_limit_exceeded": "Limite de taux YouTube dépassée. Réessayez plus tard ou utilisez différents arguments yt-dlp comme '--sleep-requests 1' pour ralentir les requêtes.",
|
||||
"youtube_auth_required_bot_detection": "YouTube nécessite une authentification (détection de bot). Utilisez --yt-dlp-args='--cookies-from-browser BROWSER' où BROWSER peut être chrome, firefox, brave, etc.",
|
||||
"youtube_ytdlp_stderr_error": "Erreur lors de la lecture du stderr de yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "arguments yt-dlp invalides : %v",
|
||||
"youtube_failed_create_temp_dir": "échec de création du répertoire temporaire : %v",
|
||||
"youtube_no_transcript_content": "aucun contenu de transcription trouvé dans le fichier VTT",
|
||||
"youtube_no_vtt_files_found": "aucun fichier VTT trouvé dans le répertoire",
|
||||
"youtube_failed_walk_directory": "échec du parcours du répertoire : %v",
|
||||
"youtube_error_getting_video_details": "erreur lors de l'obtention des détails de la vidéo : %v",
|
||||
"youtube_invalid_duration_string": "chaîne de durée invalide : %s",
|
||||
"youtube_error_getting_metadata": "erreur lors de l'obtention des métadonnées de la vidéo : %v",
|
||||
"youtube_error_parsing_duration": "erreur lors de l'analyse de la durée de la vidéo : %v",
|
||||
"youtube_error_getting_comments": "erreur lors de l'obtention des commentaires : %v",
|
||||
"youtube_error_saving_csv": "erreur lors de l'enregistrement des vidéos en CSV : %v",
|
||||
"youtube_no_video_found_with_id": "aucune vidéo trouvée avec l'ID : %s",
|
||||
"youtube_invalid_timestamp_format": "format d'horodatage invalide : %s",
|
||||
"youtube_empty_seconds_string": "chaîne de secondes vide",
|
||||
"youtube_invalid_seconds_format": "format de secondes invalide %q : %w",
|
||||
"error_fetching_playlist_videos": "erreur lors de la récupération des vidéos de la liste de lecture : %w",
|
||||
"scraping_not_configured": "la fonctionnalité de scraping n'est pas configurée. Veuillez configurer Jina pour activer le scraping",
|
||||
"could_not_determine_home_dir": "impossible de déterminer le répertoire home de l'utilisateur : %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Définir le top P",
|
||||
"stream_help": "Streaming",
|
||||
"set_presence_penalty": "Définir la pénalité de présence",
|
||||
"use_model_defaults_raw_help": "Utiliser les valeurs par défaut du modèle sans envoyer d'options de chat (comme la température, etc.) et utiliser le rôle utilisateur au lieu du rôle système pour les motifs.",
|
||||
"use_model_defaults_raw_help": "Utilise les valeurs par défaut du modèle sans envoyer d’options de discussion (temperature, top_p, etc.). N’affecte que les fournisseurs compatibles avec OpenAI. Les modèles Anthropic utilisent toujours une sélection intelligente des paramètres pour respecter les exigences propres à chaque modèle.",
|
||||
"set_frequency_penalty": "Définir la pénalité de fréquence",
|
||||
"list_all_patterns": "Lister tous les motifs",
|
||||
"list_all_available_models": "Lister tous les modèles disponibles",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "il fornitore %s non supporta la trascrizione audio",
|
||||
"transcription_model_required": "è richiesto un modello di trascrizione (usa --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube non è configurato, per favore esegui la procedura di configurazione",
|
||||
"youtube_api_key_required": "Chiave API YouTube richiesta per commenti e metadati. Esegui 'fabric --setup' per configurare",
|
||||
"youtube_ytdlp_not_found": "yt-dlp non trovato in PATH. Per favore installa yt-dlp per usare la funzionalità di trascrizione YouTube",
|
||||
"youtube_invalid_url": "URL YouTube non valido, impossibile ottenere l'ID del video o della playlist: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "L'URL è una playlist, non un video",
|
||||
"youtube_no_video_id_found": "nessun ID video trovato nell'URL",
|
||||
"youtube_rate_limit_exceeded": "Limite di richieste YouTube superato. Riprova più tardi o usa argomenti yt-dlp diversi come '--sleep-requests 1' per rallentare le richieste.",
|
||||
"youtube_auth_required_bot_detection": "YouTube richiede autenticazione (rilevamento bot). Usa --yt-dlp-args='--cookies-from-browser BROWSER' dove BROWSER può essere chrome, firefox, brave, ecc.",
|
||||
"youtube_ytdlp_stderr_error": "Errore durante la lettura dello stderr di yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "argomenti yt-dlp non validi: %v",
|
||||
"youtube_failed_create_temp_dir": "impossibile creare la directory temporanea: %v",
|
||||
"youtube_no_transcript_content": "nessun contenuto di trascrizione trovato nel file VTT",
|
||||
"youtube_no_vtt_files_found": "nessun file VTT trovato nella directory",
|
||||
"youtube_failed_walk_directory": "impossibile esplorare la directory: %v",
|
||||
"youtube_error_getting_video_details": "errore nell'ottenere i dettagli del video: %v",
|
||||
"youtube_invalid_duration_string": "stringa di durata non valida: %s",
|
||||
"youtube_error_getting_metadata": "errore nell'ottenere i metadati del video: %v",
|
||||
"youtube_error_parsing_duration": "errore nell'analizzare la durata del video: %v",
|
||||
"youtube_error_getting_comments": "errore nell'ottenere i commenti: %v",
|
||||
"youtube_error_saving_csv": "errore nel salvare i video in CSV: %v",
|
||||
"youtube_no_video_found_with_id": "nessun video trovato con ID: %s",
|
||||
"youtube_invalid_timestamp_format": "formato timestamp non valido: %s",
|
||||
"youtube_empty_seconds_string": "stringa di secondi vuota",
|
||||
"youtube_invalid_seconds_format": "formato secondi non valido %q: %w",
|
||||
"error_fetching_playlist_videos": "errore nel recupero dei video della playlist: %w",
|
||||
"scraping_not_configured": "la funzionalità di scraping non è configurata. Per favore configura Jina per abilitare lo scraping",
|
||||
"could_not_determine_home_dir": "impossibile determinare la directory home dell'utente: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Imposta top P",
|
||||
"stream_help": "Streaming",
|
||||
"set_presence_penalty": "Imposta penalità di presenza",
|
||||
"use_model_defaults_raw_help": "Usa i valori predefiniti del modello senza inviare opzioni di chat (come temperatura, ecc.) e usa il ruolo utente invece del ruolo sistema per i pattern.",
|
||||
"use_model_defaults_raw_help": "Usa i valori predefiniti del modello senza inviare opzioni della chat (temperature, top_p, ecc.). Si applica solo ai provider compatibili con OpenAI. I modelli Anthropic utilizzano sempre una selezione intelligente dei parametri per rispettare i requisiti specifici del modello.",
|
||||
"set_frequency_penalty": "Imposta penalità di frequenza",
|
||||
"list_all_patterns": "Elenca tutti i pattern",
|
||||
"list_all_available_models": "Elenca tutti i modelli disponibili",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "ベンダー %s は音声転写をサポートしていません",
|
||||
"transcription_model_required": "転写モデルが必要です(--transcribe-model を使用)",
|
||||
"youtube_not_configured": "YouTubeが設定されていません。セットアップ手順を実行してください",
|
||||
"youtube_api_key_required": "コメントとメタデータにはYouTube APIキーが必要です。設定するには 'fabric --setup' を実行してください",
|
||||
"youtube_ytdlp_not_found": "PATHにyt-dlpが見つかりません。YouTubeトランスクリプト機能を使用するにはyt-dlpをインストールしてください",
|
||||
"youtube_invalid_url": "無効なYouTube URL、動画またはプレイリストIDを取得できません: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "URLはプレイリストであり、動画ではありません",
|
||||
"youtube_no_video_id_found": "URLに動画IDが見つかりません",
|
||||
"youtube_rate_limit_exceeded": "YouTubeのレート制限を超えました。後でもう一度試すか、'--sleep-requests 1'のような異なるyt-dlp引数を使用してリクエストを遅くしてください。",
|
||||
"youtube_auth_required_bot_detection": "YouTubeは認証を必要としています(ボット検出)。--yt-dlp-args='--cookies-from-browser BROWSER'を使用してください。BROWSERはchrome、firefox、braveなどです。",
|
||||
"youtube_ytdlp_stderr_error": "yt-dlp stderrの読み取りエラー",
|
||||
"youtube_invalid_ytdlp_arguments": "無効なyt-dlp引数: %v",
|
||||
"youtube_failed_create_temp_dir": "一時ディレクトリの作成に失敗しました: %v",
|
||||
"youtube_no_transcript_content": "VTTファイルにトランスクリプトコンテンツが見つかりません",
|
||||
"youtube_no_vtt_files_found": "ディレクトリにVTTファイルが見つかりません",
|
||||
"youtube_failed_walk_directory": "ディレクトリの走査に失敗しました: %v",
|
||||
"youtube_error_getting_video_details": "動画の詳細取得エラー: %v",
|
||||
"youtube_invalid_duration_string": "無効な長さ文字列: %s",
|
||||
"youtube_error_getting_metadata": "動画のメタデータ取得エラー: %v",
|
||||
"youtube_error_parsing_duration": "動画の長さ解析エラー: %v",
|
||||
"youtube_error_getting_comments": "コメント取得エラー: %v",
|
||||
"youtube_error_saving_csv": "動画のCSV保存エラー: %v",
|
||||
"youtube_no_video_found_with_id": "IDの動画が見つかりません: %s",
|
||||
"youtube_invalid_timestamp_format": "無効なタイムスタンプ形式: %s",
|
||||
"youtube_empty_seconds_string": "空の秒文字列",
|
||||
"youtube_invalid_seconds_format": "無効な秒形式 %q: %w",
|
||||
"error_fetching_playlist_videos": "プレイリスト動画の取得エラー: %w",
|
||||
"scraping_not_configured": "スクレイピング機能が設定されていません。スクレイピングを有効にするためにJinaを設定してください",
|
||||
"could_not_determine_home_dir": "ユーザーのホームディレクトリを特定できませんでした: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Top Pを設定",
|
||||
"stream_help": "ストリーミング",
|
||||
"set_presence_penalty": "プレゼンスペナルティを設定",
|
||||
"use_model_defaults_raw_help": "チャットオプション(温度など)を送信せずにモデルのデフォルトを使用し、パターンにシステムロールではなくユーザーロールを使用します。",
|
||||
"use_model_defaults_raw_help": "チャットオプション(temperature、top_p など)を送信せずにモデルのデフォルトを使用します。OpenAI 互換プロバイダーにのみ適用されます。Anthropic モデルは常に、モデル固有の要件に準拠するためにスマートなパラメーター選択を使用します。",
|
||||
"set_frequency_penalty": "頻度ペナルティを設定",
|
||||
"list_all_patterns": "すべてのパターンを一覧表示",
|
||||
"list_all_available_models": "すべての利用可能なモデルを一覧表示",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "o fornecedor %s não suporta transcrição de áudio",
|
||||
"transcription_model_required": "modelo de transcrição é necessário (use --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube não está configurado, por favor execute o procedimento de configuração",
|
||||
"youtube_api_key_required": "Chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
|
||||
"youtube_ytdlp_not_found": "yt-dlp não encontrado no PATH. Por favor instale o yt-dlp para usar a funcionalidade de transcrição do YouTube",
|
||||
"youtube_invalid_url": "URL do YouTube inválida, não é possível obter o ID do vídeo ou da playlist: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "A URL é uma playlist, não um vídeo",
|
||||
"youtube_no_video_id_found": "nenhum ID de vídeo encontrado na URL",
|
||||
"youtube_rate_limit_exceeded": "Limite de taxa do YouTube excedido. Tente novamente mais tarde ou use argumentos diferentes do yt-dlp como '--sleep-requests 1' para desacelerar as requisições.",
|
||||
"youtube_auth_required_bot_detection": "YouTube requer autenticação (detecção de bot). Use --yt-dlp-args='--cookies-from-browser BROWSER' onde BROWSER pode ser chrome, firefox, brave, etc.",
|
||||
"youtube_ytdlp_stderr_error": "Erro ao ler stderr do yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "argumentos do yt-dlp inválidos: %v",
|
||||
"youtube_failed_create_temp_dir": "falha ao criar diretório temporário: %v",
|
||||
"youtube_no_transcript_content": "nenhum conteúdo de transcrição encontrado no arquivo VTT",
|
||||
"youtube_no_vtt_files_found": "nenhum arquivo VTT encontrado no diretório",
|
||||
"youtube_failed_walk_directory": "falha ao percorrer o diretório: %v",
|
||||
"youtube_error_getting_video_details": "erro ao obter detalhes do vídeo: %v",
|
||||
"youtube_invalid_duration_string": "string de duração inválida: %s",
|
||||
"youtube_error_getting_metadata": "erro ao obter metadados do vídeo: %v",
|
||||
"youtube_error_parsing_duration": "erro ao analisar a duração do vídeo: %v",
|
||||
"youtube_error_getting_comments": "erro ao obter comentários: %v",
|
||||
"youtube_error_saving_csv": "erro ao salvar vídeos em CSV: %v",
|
||||
"youtube_no_video_found_with_id": "nenhum vídeo encontrado com o ID: %s",
|
||||
"youtube_invalid_timestamp_format": "formato de timestamp inválido: %s",
|
||||
"youtube_empty_seconds_string": "string de segundos vazia",
|
||||
"youtube_invalid_seconds_format": "formato de segundos inválido %q: %w",
|
||||
"error_fetching_playlist_videos": "erro ao buscar vídeos da playlist: %w",
|
||||
"scraping_not_configured": "funcionalidade de scraping não está configurada. Por favor configure o Jina para ativar o scraping",
|
||||
"could_not_determine_home_dir": "não foi possível determinar o diretório home do usuário: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Definir top P",
|
||||
"stream_help": "Streaming",
|
||||
"set_presence_penalty": "Definir penalidade de presença",
|
||||
"use_model_defaults_raw_help": "Usar as configurações padrão do modelo sem enviar opções de chat (como temperatura, etc.) e usar o papel de usuário em vez do papel de sistema para padrões.",
|
||||
"use_model_defaults_raw_help": "Usa os padrões do modelo sem enviar opções de chat (temperature, top_p etc.). Afeta apenas provedores compatíveis com o OpenAI. Os modelos da Anthropic sempre utilizam seleção inteligente de parâmetros para cumprir os requisitos específicos de cada modelo.",
|
||||
"set_frequency_penalty": "Definir penalidade de frequência",
|
||||
"list_all_patterns": "Listar todos os padrões/patterns",
|
||||
"list_all_available_models": "Listar todos os modelos disponíveis",
|
||||
@@ -133,4 +156,4 @@
|
||||
"no_description_available": "Nenhuma descrição disponível",
|
||||
"i18n_download_failed": "Falha ao baixar tradução para o idioma '%s': %v",
|
||||
"i18n_load_failed": "Falha ao carregar arquivo de tradução: %v"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "o fornecedor %s não suporta transcrição de áudio",
|
||||
"transcription_model_required": "modelo de transcrição é necessário (use --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube não está configurado, por favor execute o procedimento de configuração",
|
||||
"youtube_api_key_required": "Chave de API do YouTube necessária para comentários e metadados. Execute 'fabric --setup' para configurar",
|
||||
"youtube_ytdlp_not_found": "yt-dlp não encontrado no PATH. Por favor instale o yt-dlp para usar a funcionalidade de transcrição do YouTube",
|
||||
"youtube_invalid_url": "URL do YouTube inválido, não é possível obter o ID do vídeo ou da lista de reprodução: '%s'",
|
||||
"youtube_url_is_playlist_not_video": "O URL é uma lista de reprodução, não um vídeo",
|
||||
"youtube_no_video_id_found": "nenhum ID de vídeo encontrado no URL",
|
||||
"youtube_rate_limit_exceeded": "Limite de taxa do YouTube excedido. Tente novamente mais tarde ou utilize argumentos diferentes do yt-dlp como '--sleep-requests 1' para desacelerar os pedidos.",
|
||||
"youtube_auth_required_bot_detection": "YouTube requer autenticação (deteção de bot). Use --yt-dlp-args='--cookies-from-browser BROWSER' onde BROWSER pode ser chrome, firefox, brave, etc.",
|
||||
"youtube_ytdlp_stderr_error": "Erro ao ler stderr do yt-dlp",
|
||||
"youtube_invalid_ytdlp_arguments": "argumentos do yt-dlp inválidos: %v",
|
||||
"youtube_failed_create_temp_dir": "falha ao criar diretório temporário: %v",
|
||||
"youtube_no_transcript_content": "nenhum conteúdo de transcrição encontrado no ficheiro VTT",
|
||||
"youtube_no_vtt_files_found": "nenhum ficheiro VTT encontrado no diretório",
|
||||
"youtube_failed_walk_directory": "falha ao percorrer o diretório: %v",
|
||||
"youtube_error_getting_video_details": "erro ao obter detalhes do vídeo: %v",
|
||||
"youtube_invalid_duration_string": "cadeia de duração inválida: %s",
|
||||
"youtube_error_getting_metadata": "erro ao obter metadados do vídeo: %v",
|
||||
"youtube_error_parsing_duration": "erro ao analisar a duração do vídeo: %v",
|
||||
"youtube_error_getting_comments": "erro ao obter comentários: %v",
|
||||
"youtube_error_saving_csv": "erro ao guardar vídeos em CSV: %v",
|
||||
"youtube_no_video_found_with_id": "nenhum vídeo encontrado com o ID: %s",
|
||||
"youtube_invalid_timestamp_format": "formato de timestamp inválido: %s",
|
||||
"youtube_empty_seconds_string": "cadeia de segundos vazia",
|
||||
"youtube_invalid_seconds_format": "formato de segundos inválido %q: %w",
|
||||
"error_fetching_playlist_videos": "erro ao obter vídeos da playlist: %w",
|
||||
"scraping_not_configured": "funcionalidade de scraping não está configurada. Por favor configure o Jina para ativar o scraping",
|
||||
"could_not_determine_home_dir": "não foi possível determinar o diretório home do utilizador: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "Definir top P",
|
||||
"stream_help": "Streaming",
|
||||
"set_presence_penalty": "Definir penalidade de presença",
|
||||
"use_model_defaults_raw_help": "Usar as predefinições do modelo sem enviar opções de chat (como temperatura, etc.) e usar o papel de utilizador em vez do papel de sistema para padrões.",
|
||||
"use_model_defaults_raw_help": "Utiliza os valores predefinidos do modelo sem enviar opções de chat (temperature, top_p, etc.). Só afeta fornecedores compatíveis com o OpenAI. Os modelos Anthropic usam sempre uma seleção inteligente de parâmetros para cumprir os requisitos específicos do modelo.",
|
||||
"set_frequency_penalty": "Definir penalidade de frequência",
|
||||
"list_all_patterns": "Listar todos os padrões",
|
||||
"list_all_available_models": "Listar todos os modelos disponíveis",
|
||||
|
||||
@@ -4,6 +4,29 @@
|
||||
"vendor_no_transcription_support": "供应商 %s 不支持音频转录",
|
||||
"transcription_model_required": "需要转录模型(使用 --transcribe-model)",
|
||||
"youtube_not_configured": "YouTube 未配置,请运行设置程序",
|
||||
"youtube_api_key_required": "评论和元数据需要 YouTube API 密钥。运行 'fabric --setup' 进行配置",
|
||||
"youtube_ytdlp_not_found": "在 PATH 中未找到 yt-dlp。请安装 yt-dlp 以使用 YouTube 转录功能",
|
||||
"youtube_invalid_url": "无效的 YouTube URL,无法获取视频或播放列表 ID:'%s'",
|
||||
"youtube_url_is_playlist_not_video": "URL 是播放列表,而不是视频",
|
||||
"youtube_no_video_id_found": "在 URL 中未找到视频 ID",
|
||||
"youtube_rate_limit_exceeded": "超过 YouTube 速率限制。请稍后重试,或使用不同的 yt-dlp 参数(如 '--sleep-requests 1')来减慢请求速度。",
|
||||
"youtube_auth_required_bot_detection": "YouTube 需要身份验证(机器人检测)。使用 --yt-dlp-args='--cookies-from-browser BROWSER',其中 BROWSER 可以是 chrome、firefox、brave 等。",
|
||||
"youtube_ytdlp_stderr_error": "读取 yt-dlp stderr 时出错",
|
||||
"youtube_invalid_ytdlp_arguments": "无效的 yt-dlp 参数:%v",
|
||||
"youtube_failed_create_temp_dir": "创建临时目录失败:%v",
|
||||
"youtube_no_transcript_content": "在 VTT 文件中未找到转录内容",
|
||||
"youtube_no_vtt_files_found": "在目录中未找到 VTT 文件",
|
||||
"youtube_failed_walk_directory": "遍历目录失败:%v",
|
||||
"youtube_error_getting_video_details": "获取视频详情时出错:%v",
|
||||
"youtube_invalid_duration_string": "无效的时长字符串:%s",
|
||||
"youtube_error_getting_metadata": "获取视频元数据时出错:%v",
|
||||
"youtube_error_parsing_duration": "解析视频时长时出错:%v",
|
||||
"youtube_error_getting_comments": "获取评论时出错:%v",
|
||||
"youtube_error_saving_csv": "将视频保存为 CSV 时出错:%v",
|
||||
"youtube_no_video_found_with_id": "未找到 ID 为 %s 的视频",
|
||||
"youtube_invalid_timestamp_format": "无效的时间戳格式:%s",
|
||||
"youtube_empty_seconds_string": "秒数字符串为空",
|
||||
"youtube_invalid_seconds_format": "无效的秒数格式 %q:%w",
|
||||
"error_fetching_playlist_videos": "获取播放列表视频时出错: %w",
|
||||
"scraping_not_configured": "抓取功能未配置。请设置 Jina 以启用抓取功能",
|
||||
"could_not_determine_home_dir": "无法确定用户主目录: %w",
|
||||
@@ -53,7 +76,7 @@
|
||||
"set_top_p": "设置 top P",
|
||||
"stream_help": "流式传输",
|
||||
"set_presence_penalty": "设置存在惩罚",
|
||||
"use_model_defaults_raw_help": "使用模型默认设置,不发送聊天选项(如温度等),对于模式使用用户角色而非系统角色。",
|
||||
"use_model_defaults_raw_help": "在不发送聊天选项(temperature、top_p 等)的情况下使用模型默认值。仅影响兼容 OpenAI 的提供商。Anthropic 模型始终使用智能参数选择以满足特定模型的要求。",
|
||||
"set_frequency_penalty": "设置频率惩罚",
|
||||
"list_all_patterns": "列出所有模式",
|
||||
"list_all_available_models": "列出所有可用模型",
|
||||
|
||||
@@ -26,10 +26,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/danielmiessler/fabric/internal/i18n"
|
||||
debuglog "github.com/danielmiessler/fabric/internal/log"
|
||||
"github.com/danielmiessler/fabric/internal/plugins"
|
||||
"github.com/kballard/go-shellquote"
|
||||
|
||||
debuglog "github.com/danielmiessler/fabric/internal/log"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/youtube/v3"
|
||||
)
|
||||
@@ -85,7 +86,7 @@ type YouTube struct {
|
||||
func (o *YouTube) initService() (err error) {
|
||||
if o.service == nil {
|
||||
if o.ApiKey.Value == "" {
|
||||
err = fmt.Errorf("YouTube API key required for comments and metadata. Run 'fabric --setup' to configure")
|
||||
err = fmt.Errorf("%s", i18n.T("youtube_api_key_required"))
|
||||
return
|
||||
}
|
||||
o.normalizeRegex = regexp.MustCompile(`[^a-zA-Z0-9]+`)
|
||||
@@ -109,41 +110,66 @@ func (o *YouTube) GetVideoOrPlaylistId(url string) (videoId string, playlistId s
|
||||
}
|
||||
|
||||
if videoId == "" && playlistId == "" {
|
||||
err = fmt.Errorf("invalid YouTube URL, can't get video or playlist ID: '%s'", url)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_invalid_url"), url))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *YouTube) GrabTranscriptForUrl(url string, language string) (ret string, err error) {
|
||||
var videoId string
|
||||
// extractAndValidateVideoId extracts a video ID from the given URL and validates
|
||||
// that the URL points to a video rather than a playlist-only resource.
|
||||
// It returns an error if the URL is invalid or contains only playlist information.
|
||||
func (o *YouTube) extractAndValidateVideoId(url string) (videoId string, err error) {
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
return "", err
|
||||
}
|
||||
if videoId == "" && playlistId != "" {
|
||||
return "", fmt.Errorf("%s", i18n.T("youtube_url_is_playlist_not_video"))
|
||||
}
|
||||
if videoId == "" {
|
||||
return "", fmt.Errorf("%s", i18n.T("youtube_no_video_id_found"))
|
||||
}
|
||||
return videoId, nil
|
||||
}
|
||||
|
||||
func (o *YouTube) GrabTranscriptForUrl(url string, language string) (ret string, err error) {
|
||||
var videoId string
|
||||
if videoId, err = o.extractAndValidateVideoId(url); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return o.GrabTranscript(videoId, language)
|
||||
}
|
||||
|
||||
// GrabTranscript retrieves the transcript for the specified video ID using yt-dlp.
|
||||
// The language parameter specifies the preferred subtitle language code (e.g., "en", "es").
|
||||
// It returns the transcript text or an error if the transcript cannot be retrieved.
|
||||
func (o *YouTube) GrabTranscript(videoId string, language string) (ret string, err error) {
|
||||
// Use yt-dlp for reliable transcript extraction
|
||||
return o.GrabTranscriptWithArgs(videoId, language, "")
|
||||
}
|
||||
|
||||
// GrabTranscriptWithArgs retrieves the transcript for the specified video ID using yt-dlp
|
||||
// with custom command-line arguments. The language parameter specifies the preferred subtitle
|
||||
// language code. The additionalArgs parameter allows passing extra yt-dlp options like
|
||||
// "--cookies-from-browser brave" for authentication.
|
||||
// It returns the transcript text or an error if the transcript cannot be retrieved.
|
||||
func (o *YouTube) GrabTranscriptWithArgs(videoId string, language string, additionalArgs string) (ret string, err error) {
|
||||
// Use yt-dlp for reliable transcript extraction
|
||||
return o.tryMethodYtDlp(videoId, language, additionalArgs)
|
||||
}
|
||||
|
||||
// GrabTranscriptWithTimestamps retrieves the transcript with timestamps for the specified
|
||||
// video ID using yt-dlp. The language parameter specifies the preferred subtitle language code.
|
||||
// Each line in the returned transcript is prefixed with a timestamp in [HH:MM:SS] format.
|
||||
// It returns the timestamped transcript text or an error if the transcript cannot be retrieved.
|
||||
func (o *YouTube) GrabTranscriptWithTimestamps(videoId string, language string) (ret string, err error) {
|
||||
// Use yt-dlp for reliable transcript extraction with timestamps
|
||||
return o.GrabTranscriptWithTimestampsWithArgs(videoId, language, "")
|
||||
}
|
||||
|
||||
// GrabTranscriptWithTimestampsWithArgs retrieves the transcript with timestamps for the specified
|
||||
// video ID using yt-dlp with custom command-line arguments. The language parameter specifies the
|
||||
// preferred subtitle language code. The additionalArgs parameter allows passing extra yt-dlp options.
|
||||
// Each line in the returned transcript is prefixed with a timestamp in [HH:MM:SS] format.
|
||||
// It returns the timestamped transcript text or an error if the transcript cannot be retrieved.
|
||||
func (o *YouTube) GrabTranscriptWithTimestampsWithArgs(videoId string, language string, additionalArgs string) (ret string, err error) {
|
||||
// Use yt-dlp for reliable transcript extraction with timestamps
|
||||
return o.tryMethodYtDlpWithTimestamps(videoId, language, additionalArgs)
|
||||
}
|
||||
|
||||
@@ -153,10 +179,10 @@ func detectError(ytOutput io.Reader) error {
|
||||
curLine := scanner.Text()
|
||||
debuglog.Debug(debuglog.Trace, "%s\n", curLine)
|
||||
errorMessages := map[string]string{
|
||||
"429": "YouTube rate limit exceeded. Try again later or use different yt-dlp arguments like '--sleep-requests 1' to slow down requests.",
|
||||
"Too Many Requests": "YouTube rate limit exceeded. Try again later or use different yt-dlp arguments like '--sleep-requests 1' to slow down requests.",
|
||||
"Sign in to confirm you're not a bot": "YouTube requires authentication (bot detection). Use --yt-dlp-args='--cookies-from-browser BROWSER' where BROWSER is chrome, firefox, brave, etc.",
|
||||
"Use --cookies-from-browser": "YouTube requires authentication (bot detection). Use --yt-dlp-args='--cookies-from-browser BROWSER' where BROWSER is chrome, firefox, brave, etc.",
|
||||
"429": i18n.T("youtube_rate_limit_exceeded"),
|
||||
"Too Many Requests": i18n.T("youtube_rate_limit_exceeded"),
|
||||
"Sign in to confirm you're not a bot": i18n.T("youtube_auth_required_bot_detection"),
|
||||
"Use --cookies-from-browser": i18n.T("youtube_auth_required_bot_detection"),
|
||||
}
|
||||
|
||||
for key, message := range errorMessages {
|
||||
@@ -166,7 +192,7 @@ func detectError(ytOutput io.Reader) error {
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fmt.Errorf("Error reading yt-dlp stderr")
|
||||
return fmt.Errorf("%s", i18n.T("youtube_ytdlp_stderr_error"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -192,14 +218,14 @@ func noLangs(args []string) []string {
|
||||
func (o *YouTube) tryMethodYtDlpInternal(videoId string, language string, additionalArgs string, processVTTFileFunc func(filename string) (string, error)) (ret string, err error) {
|
||||
// Check if yt-dlp is available
|
||||
if _, err = exec.LookPath("yt-dlp"); err != nil {
|
||||
err = fmt.Errorf("yt-dlp not found in PATH. Please install yt-dlp to use YouTube transcript functionality")
|
||||
err = fmt.Errorf("%s", i18n.T("youtube_ytdlp_not_found"))
|
||||
return
|
||||
}
|
||||
|
||||
// Create a temporary directory for yt-dlp output (cross-platform)
|
||||
tempDir := filepath.Join(os.TempDir(), "fabric-youtube-"+videoId)
|
||||
if err = os.MkdirAll(tempDir, 0755); err != nil {
|
||||
err = fmt.Errorf("failed to create temp directory: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_failed_create_temp_dir"), err))
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
@@ -231,7 +257,7 @@ func (o *YouTube) tryMethodYtDlpInternal(videoId string, language string, additi
|
||||
if additionalArgs != "" {
|
||||
additionalArgsList, err := shellquote.Split(additionalArgs)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid yt-dlp arguments: %v", err)
|
||||
return "", fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_invalid_ytdlp_arguments"), err))
|
||||
}
|
||||
args = append(args, additionalArgsList...)
|
||||
}
|
||||
@@ -302,7 +328,7 @@ func (o *YouTube) readAndCleanVTTFile(filename string) (ret string, err error) {
|
||||
|
||||
ret = strings.TrimSpace(textBuilder.String())
|
||||
if ret == "" {
|
||||
err = fmt.Errorf("no transcript content found in VTT file")
|
||||
err = fmt.Errorf("%s", i18n.T("youtube_no_transcript_content"))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -372,7 +398,7 @@ func (o *YouTube) readAndFormatVTTWithTimestamps(filename string) (ret string, e
|
||||
|
||||
ret = strings.TrimSpace(textBuilder.String())
|
||||
if ret == "" {
|
||||
err = fmt.Errorf("no transcript content found in VTT file")
|
||||
err = fmt.Errorf("%s", i18n.T("youtube_no_transcript_content"))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -418,7 +444,7 @@ func shouldIncludeRepeat(lastTimestamp, currentTimestamp string) bool {
|
||||
func parseTimestampToSeconds(timestamp string) (int, error) {
|
||||
parts := strings.Split(timestamp, ":")
|
||||
if len(parts) < 2 || len(parts) > 3 {
|
||||
return 0, fmt.Errorf("invalid timestamp format: %s", timestamp)
|
||||
return 0, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_invalid_timestamp_format"), timestamp))
|
||||
}
|
||||
|
||||
var hours, minutes, seconds int
|
||||
@@ -448,20 +474,27 @@ func parseTimestampToSeconds(timestamp string) (int, error) {
|
||||
return hours*3600 + minutes*60 + seconds, nil
|
||||
}
|
||||
|
||||
func parseSeconds(seconds_str string) (int, error) {
|
||||
var seconds int
|
||||
var err error
|
||||
if strings.Contains(seconds_str, ".") {
|
||||
// Handle fractional seconds
|
||||
second_parts := strings.Split(seconds_str, ".")
|
||||
if seconds, err = strconv.Atoi(second_parts[0]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
if seconds, err = strconv.Atoi(seconds_str); err != nil {
|
||||
return 0, err
|
||||
func parseSeconds(secondsStr string) (int, error) {
|
||||
if secondsStr == "" {
|
||||
return 0, fmt.Errorf("%s", i18n.T("youtube_empty_seconds_string"))
|
||||
}
|
||||
|
||||
// Extract integer part (before decimal point if present)
|
||||
intPart := secondsStr
|
||||
if idx := strings.Index(secondsStr, "."); idx != -1 {
|
||||
if idx == 0 {
|
||||
// Handle cases like ".5" -> treat as "0"
|
||||
intPart = "0"
|
||||
} else {
|
||||
intPart = secondsStr[:idx]
|
||||
}
|
||||
}
|
||||
|
||||
seconds, err := strconv.Atoi(intPart)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_invalid_seconds_format"), secondsStr, err))
|
||||
}
|
||||
|
||||
return seconds, nil
|
||||
}
|
||||
|
||||
@@ -497,11 +530,7 @@ func (o *YouTube) GrabDurationForUrl(url string) (ret int, err error) {
|
||||
}
|
||||
|
||||
var videoId string
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
if videoId, err = o.extractAndValidateVideoId(url); err != nil {
|
||||
return
|
||||
}
|
||||
return o.GrabDuration(videoId)
|
||||
@@ -510,7 +539,7 @@ func (o *YouTube) GrabDurationForUrl(url string) (ret int, err error) {
|
||||
func (o *YouTube) GrabDuration(videoId string) (ret int, err error) {
|
||||
var videoResponse *youtube.VideoListResponse
|
||||
if videoResponse, err = o.service.Videos.List([]string{"contentDetails"}).Id(videoId).Do(); err != nil {
|
||||
err = fmt.Errorf("error getting video details: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_getting_video_details"), err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -518,7 +547,7 @@ func (o *YouTube) GrabDuration(videoId string) (ret int, err error) {
|
||||
|
||||
matches := durationRegex.FindStringSubmatch(durationStr)
|
||||
if len(matches) == 0 {
|
||||
return 0, fmt.Errorf("invalid duration string: %s", durationStr)
|
||||
return 0, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_invalid_duration_string"), durationStr))
|
||||
}
|
||||
|
||||
hours, _ := strconv.Atoi(matches[1])
|
||||
@@ -532,11 +561,7 @@ func (o *YouTube) GrabDuration(videoId string) (ret int, err error) {
|
||||
|
||||
func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error) {
|
||||
var videoId string
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
if videoId, err = o.extractAndValidateVideoId(url); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -544,14 +569,14 @@ func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error)
|
||||
|
||||
if options.Metadata {
|
||||
if ret.Metadata, err = o.GrabMetadata(videoId); err != nil {
|
||||
err = fmt.Errorf("error getting video metadata: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_getting_metadata"), err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if options.Duration {
|
||||
if ret.Duration, err = o.GrabDuration(videoId); err != nil {
|
||||
err = fmt.Errorf("error parsing video duration: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_parsing_duration"), err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -559,7 +584,7 @@ func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error)
|
||||
|
||||
if options.Comments {
|
||||
if ret.Comments, err = o.GrabComments(videoId); err != nil {
|
||||
err = fmt.Errorf("error getting comments: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_getting_comments"), err))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -643,12 +668,12 @@ func (o *YouTube) SaveVideosToCSV(filename string, videos []*VideoMeta) (err err
|
||||
func (o *YouTube) FetchAndSavePlaylist(playlistID, filename string) (err error) {
|
||||
var videos []*VideoMeta
|
||||
if videos, err = o.FetchPlaylistVideos(playlistID); err != nil {
|
||||
err = fmt.Errorf("error fetching playlist videos: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("error_fetching_playlist_videos"), err))
|
||||
return
|
||||
}
|
||||
|
||||
if err = o.SaveVideosToCSV(filename, videos); err != nil {
|
||||
err = fmt.Errorf("error saving videos to CSV: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_saving_csv"), err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -659,7 +684,7 @@ func (o *YouTube) FetchAndSavePlaylist(playlistID, filename string) (err error)
|
||||
func (o *YouTube) FetchAndPrintPlaylist(playlistID string) (err error) {
|
||||
var videos []*VideoMeta
|
||||
if videos, err = o.FetchPlaylistVideos(playlistID); err != nil {
|
||||
err = fmt.Errorf("error fetching playlist videos: %v", err)
|
||||
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("error_fetching_playlist_videos"), err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -694,11 +719,11 @@ func (o *YouTube) findVTTFilesWithFallback(dir, requestedLanguage string) ([]str
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to walk directory: %v", err)
|
||||
return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_failed_walk_directory"), err))
|
||||
}
|
||||
|
||||
if len(vttFiles) == 0 {
|
||||
return nil, fmt.Errorf("no VTT files found in directory")
|
||||
return nil, fmt.Errorf("%s", i18n.T("youtube_no_vtt_files_found"))
|
||||
}
|
||||
|
||||
// If no specific language requested, return the first file
|
||||
@@ -769,11 +794,11 @@ func (o *YouTube) GrabMetadata(videoId string) (metadata *VideoMetadata, err err
|
||||
call := o.service.Videos.List([]string{"snippet", "statistics"}).Id(videoId)
|
||||
var response *youtube.VideoListResponse
|
||||
if response, err = call.Do(); err != nil {
|
||||
return nil, fmt.Errorf("error getting video metadata: %v", err)
|
||||
return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_error_getting_metadata"), err))
|
||||
}
|
||||
|
||||
if len(response.Items) == 0 {
|
||||
return nil, fmt.Errorf("no video found with ID: %s", videoId)
|
||||
return nil, fmt.Errorf("%s", fmt.Sprintf(i18n.T("youtube_no_video_found_with_id"), videoId))
|
||||
}
|
||||
|
||||
video := response.Items[0]
|
||||
|
||||
168
internal/tools/youtube/youtube_test.go
Normal file
168
internal/tools/youtube/youtube_test.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package youtube
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseSeconds(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "integer seconds",
|
||||
input: "42",
|
||||
want: 42,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "fractional seconds",
|
||||
input: "42.567",
|
||||
want: 42,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "zero",
|
||||
input: "0",
|
||||
want: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "zero with fraction",
|
||||
input: "0.999",
|
||||
want: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "decimal point at start",
|
||||
input: ".5",
|
||||
want: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
input: "abc",
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
input: "",
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseSeconds(tt.input)
|
||||
|
||||
// Check error condition
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("parseSeconds(%q) expected error but got none", tt.input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check success condition
|
||||
if err != nil {
|
||||
t.Fatalf("parseSeconds(%q) unexpected error: %v", tt.input, err)
|
||||
}
|
||||
|
||||
if got != tt.want {
|
||||
t.Errorf("parseSeconds(%q) = %d, want %d", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractAndValidateVideoId(t *testing.T) {
|
||||
yt := NewYouTube()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
wantId string
|
||||
wantError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "valid video URL",
|
||||
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
wantId: "dQw4w9WgXcQ",
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "valid short URL",
|
||||
url: "https://youtu.be/dQw4w9WgXcQ",
|
||||
wantId: "dQw4w9WgXcQ",
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "video with playlist URL - should extract video",
|
||||
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf",
|
||||
wantId: "dQw4w9WgXcQ",
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "playlist-only URL",
|
||||
url: "https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf",
|
||||
wantId: "",
|
||||
wantError: true,
|
||||
errorMsg: "URL is a playlist, not a video",
|
||||
},
|
||||
{
|
||||
name: "invalid URL",
|
||||
url: "https://example.com",
|
||||
wantId: "",
|
||||
wantError: true,
|
||||
errorMsg: "invalid YouTube URL",
|
||||
},
|
||||
{
|
||||
name: "empty URL",
|
||||
url: "",
|
||||
wantId: "",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "malformed URL",
|
||||
url: "not-a-url",
|
||||
wantId: "",
|
||||
wantError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := yt.extractAndValidateVideoId(tt.url)
|
||||
|
||||
if tt.wantError {
|
||||
if err == nil {
|
||||
t.Errorf("extractAndValidateVideoId(%q) expected error but got none", tt.url)
|
||||
return
|
||||
}
|
||||
if tt.errorMsg != "" && !strings.Contains(err.Error(), tt.errorMsg) {
|
||||
t.Errorf("extractAndValidateVideoId(%q) error = %v, want error containing %q", tt.url, err, tt.errorMsg)
|
||||
}
|
||||
// Verify empty videoId is returned on error
|
||||
if got != "" {
|
||||
t.Errorf("extractAndValidateVideoId(%q) returned videoId %q on error, want empty string", tt.url, got)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("extractAndValidateVideoId(%q) unexpected error = %v", tt.url, err)
|
||||
return
|
||||
}
|
||||
|
||||
if got != tt.wantId {
|
||||
t.Errorf("extractAndValidateVideoId(%q) = %q, want %q", tt.url, got, tt.wantId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
"1.4.327"
|
||||
"1.4.329"
|
||||
|
||||
@@ -316,7 +316,7 @@ Application Options:
|
||||
-T, --topp= Set top P (default: 0.9)
|
||||
-s, --stream Stream
|
||||
-P, --presencepenalty= Set presence penalty (default: 0.0)
|
||||
-r, --raw Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns.
|
||||
-r, --raw Use the defaults of the model without sending chat options (temperature, top_p, etc.). Only affects OpenAI-compatible providers. Anthropic models always use smart parameter selection to comply with model-specific requirements.
|
||||
-F, --frequencypenalty= Set frequency penalty (default: 0.0)
|
||||
-l, --listpatterns List all patterns
|
||||
-L, --listmodels List all available models
|
||||
|
||||
Reference in New Issue
Block a user