Compare commits

...

19 Commits

Author SHA1 Message Date
github-actions[bot]
826ac586ee chore(release): Update version to v1.4.329 2025-11-20 23:24:47 +00:00
Kayvan Sylvan
ec14e42abf Merge pull request #1838 from ksylvan/kayvan/add-internationalized-error-messages-to-youtube-plugin
refactor: implement i18n support for YouTube tool error messages
2025-11-20 15:22:23 -08:00
Kayvan Sylvan
6708c7481b refactor: implement i18n support for YouTube tool error messages
CHANGES
- 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
- ensure rate limit and bot detection warnings use localized strings
2025-11-21 06:14:18 +07:00
github-actions[bot]
75e11724b4 chore(release): Update version to v1.4.328 2025-11-18 15:17:49 +00:00
Kayvan Sylvan
2dd79a66d7 Merge pull request #1836 from ksylvan/kayvan/update-raw-flag-help-message
docs: clarify `--raw` flag behavior for OpenAI and Anthropic providers
2025-11-18 07:15:01 -08:00
Kayvan Sylvan
b7fa02d91e 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
- Translate updated description to all supported locales
- Update shell completion descriptions for zsh and fish
- chore: incoming 1836 changelog entry
2025-11-18 04:27:38 -08:00
github-actions[bot]
63804d3d52 chore(release): Update version to v1.4.327 2025-11-16 21:12:09 +00:00
Kayvan Sylvan
56f105971f Merge pull request #1832 from ksylvan/kayvan/fix-gemini-panic
Improve channel management in Gemini provider
2025-11-16 13:08:59 -08:00
Kayvan Sylvan
ca96c9c629 fix: improve channel management in Gemini streaming method
- Add deferred channel close at function start
- Return error immediately instead of breaking loop
- Remove redundant channel close statements from loop
- Ensure channel closes on all exit paths consistently
- chore: incoming 1832 changelog entry
2025-11-16 13:06:09 -08:00
Kayvan Sylvan
efb9261b89 Merge pull request #1831 from ksylvan/kayvan/remove-youtube-rss-pattern
Remove `get_youtube_rss` pattern
2025-11-16 12:41:12 -08:00
Kayvan Sylvan
118abdc368 chore: remove get_youtube_rss pattern from multiple files
- Remove `get_youtube_rss` from `pattern_explanations.md`
- Delete `get_youtube_rss` entry in `pattern_descriptions.json`
- Delete `get_youtube_rss` entry in `pattern_extracts.json`
- Remove `get_youtube_rss` from `suggest_pattern/system.md`
- Remove `get_youtube_rss` from `suggest_pattern/user.md`
- chore: incoming 1831 changelog entry
2025-11-16 12:28:09 -08:00
github-actions[bot]
278d488dbf chore(release): Update version to v1.4.326 2025-11-16 19:36:17 +00:00
Kayvan Sylvan
d590c0dd15 Merge pull request #1830 from ksylvan/kayvan/newline-in-output-fix
Ensure final newline in model generated outputs
2025-11-16 11:33:47 -08:00
Kayvan Sylvan
c936f8e77b feat: ensure newline in CreateOutputFile and improve tests
- Add newline to `CreateOutputFile` if missing
- Use `t.Cleanup` for file removal in tests
- Add test for message with trailing newline
- Introduce `printedStream` flag in `Chatter.Send`
- Print newline if stream printed without trailing newline
2025-11-16 11:15:47 -08:00
Kayvan Sylvan
7dacc07f03 chore: update README with recent features and extensions
### CHANGES

- Add v1.4.322 release with concept maps
- Introduce WELLNESS category with psychological analysis
- Upgrade to Claude Sonnet 4.5
- Add Portuguese language variants with BCP 47 support
- Migrate to `openai-go/azure` SDK for Azure
- Add Extensions section to README navigation
2025-11-15 09:34:27 -08:00
github-actions[bot]
4e6a2736ad chore(release): Update version to v1.4.325 2025-11-15 05:25:51 +00:00
Kayvan Sylvan
14c95d7bc1 Merge pull request #1828 from ksylvan/kayvan/fix-empty-input-bug
Fix empty string detection in chatter and AI clients
2025-11-14 21:22:53 -08:00
Changelog Bot
2e7b664e1e chore: incoming 1828 changelog entry 2025-11-14 21:20:52 -08:00
Kayvan Sylvan
729d092754 chore: improve message handling by trimming whitespace in content checks
### CHANGES

- Remove default space in `BuildSession` message content
- Trim whitespace in `anthropic` message content check
- Trim whitespace in `gemini` message content check
2025-11-14 21:13:08 -08:00
33 changed files with 699 additions and 214 deletions

View File

@@ -1,5 +1,76 @@
# 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
- Chore: remove `get_youtube_rss` pattern from multiple files
- Remove `get_youtube_rss` from `pattern_explanations.md`
- Delete `get_youtube_rss` entry in `pattern_descriptions.json`
- Delete `get_youtube_rss` entry in `pattern_extracts.json`
- Remove `get_youtube_rss` from `suggest_pattern/system.md`
### PR [#1832](https://github.com/danielmiessler/Fabric/pull/1832) by [ksylvan](https://github.com/ksylvan): Improve channel management in Gemini provider
- Fix: improve channel management in Gemini streaming method
- Add deferred channel close at function start
- Return error immediately instead of breaking loop
- Remove redundant channel close statements from loop
- Ensure channel closes on all exit paths consistently
## v1.4.326 (2025-11-16)
### PR [#1830](https://github.com/danielmiessler/Fabric/pull/1830) by [ksylvan](https://github.com/ksylvan): Ensure final newline in model generated outputs
- Feat: ensure newline in `CreateOutputFile` and improve tests
- Add newline to `CreateOutputFile` if missing
- Use `t.Cleanup` for file removal in tests
- Add test for message with trailing newline
- Introduce `printedStream` flag in `Chatter.Send`
### Direct commits
- Chore: update README with recent features and extensions
- Add v1.4.322 release with concept maps
- Introduce WELLNESS category with psychological analysis
- Upgrade to Claude Sonnet 4.5
- Add Portuguese language variants with BCP 47 support
- Migrate to `openai-go/azure` SDK for Azure
- Add Extensions section to README navigation
## v1.4.325 (2025-11-15)
### PR [#1828](https://github.com/danielmiessler/Fabric/pull/1828) by [ksylvan](https://github.com/ksylvan): Fix empty string detection in chatter and AI clients
- Chore: improve message handling by trimming whitespace in content checks
- Remove default space in `BuildSession` message content
- Trim whitespace in `anthropic` message content check
- Trim whitespace in `gemini` message content check
## v1.4.324 (2025-11-14)
### PR [#1827](https://github.com/danielmiessler/Fabric/pull/1827) by [ksylvan](https://github.com/ksylvan): Make YouTube API key optional in setup

View File

@@ -73,6 +73,9 @@ Below are the **new features and capabilities** we've added (newest first):
### Recent Major Features
- [v1.4.322](https://github.com/danielmiessler/fabric/releases/tag/v1.4.322) (Nov 5, 2025) — **Interactive HTML Concept Maps and Claude Sonnet 4.5**: Adds `create_conceptmap` pattern for visual knowledge representation using Vis.js, introduces WELLNESS category with psychological analysis patterns, and upgrades to Claude Sonnet 4.5
- [v1.4.317](https://github.com/danielmiessler/fabric/releases/tag/v1.4.317) (Sep 21, 2025) — **Portuguese Language Variants**: Adds BCP 47 locale normalization with support for Brazilian Portuguese (pt-BR) and European Portuguese (pt-PT) with intelligent fallback chains
- [v1.4.314](https://github.com/danielmiessler/fabric/releases/tag/v1.4.314) (Sep 17, 2025) — **Azure OpenAI Migration**: Migrates to official `openai-go/azure` SDK with improved authentication and default API version support
- [v1.4.311](https://github.com/danielmiessler/fabric/releases/tag/v1.4.311) (Sep 13, 2025) — **More internationalization support**: Adds de (German), fa (Persian / Farsi), fr (French), it (Italian),
ja (Japanese), pt (Portuguese), zh (Chinese)
- [v1.4.309](https://github.com/danielmiessler/fabric/releases/tag/v1.4.309) (Sep 9, 2025) — **Comprehensive internationalization support**: Includes English and Spanish locale files.
@@ -161,6 +164,7 @@ Keep in mind that many of these were recorded when Fabric was Python-based, so r
- [Fish Completion](#fish-completion)
- [Usage](#usage)
- [Debug Levels](#debug-levels)
- [Extensions](#extensions)
- [Our approach to prompting](#our-approach-to-prompting)
- [Examples](#examples)
- [Just use the Patterns](#just-use-the-patterns)
@@ -619,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

View File

@@ -1,3 +1,3 @@
package main
var version = "v1.4.324"
var version = "v1.4.329"

Binary file not shown.

View File

@@ -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]' \

View File

@@ -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"

View File

@@ -1,27 +0,0 @@
# IDENTITY AND GOALS
You are a YouTube infrastructure expert that returns YouTube channel RSS URLs.
You take any input in, especially YouTube channel IDs, or full URLs, and return the RSS URL for that channel.
# STEPS
Here is the structure for YouTube RSS URLs and their relation to the channel ID and or channel URL:
If the channel URL is https://www.youtube.com/channel/UCnCikd0s4i9KoDtaHPlK-JA, the RSS URL is https://www.youtube.com/feeds/videos.xml?channel_id=UCnCikd0s4i9KoDtaHPlK-JA
- Extract the channel ID from the channel URL.
- Construct the RSS URL using the channel ID.
- Output the RSS URL.
# OUTPUT
- Output only the RSS URL and nothing else.
- Don't complain, just do it.
# INPUT
(INPUT)

View File

@@ -156,79 +156,78 @@
152. **fix_typos**: Proofreads and corrects typos, spelling, grammar, and punctuation errors in text.
153. **generate_code_rules**: Compile best-practice coding rules and guardrails for AI-assisted development workflows from the provided content.
154. **get_wow_per_minute**: Determines the wow-factor of content per minute based on surprise, novelty, insight, value, and wisdom, measuring how rewarding the content is for the viewer.
155. **get_youtube_rss**: Returns the RSS URL for a given YouTube channel based on the channel ID or URL.
156. **heal_person**: Develops a comprehensive plan for spiritual and mental healing based on psychological profiles, providing personalized recommendations for mental health improvement and overall life enhancement.
157. **humanize**: Rewrites AI-generated text to sound natural, conversational, and easy to understand, maintaining clarity and simplicity.
158. **identify_dsrp_distinctions**: Encourages creative, systems-based thinking by exploring distinctions, boundaries, and their implications, drawing on insights from prominent systems thinkers.
159. **identify_dsrp_perspectives**: Explores the concept of distinctions in systems thinking, focusing on how boundaries define ideas, influence understanding, and reveal or obscure insights.
160. **identify_dsrp_relationships**: Encourages exploration of connections, distinctions, and boundaries between ideas, inspired by systems thinkers to reveal new insights and patterns in complex systems.
161. **identify_dsrp_systems**: Encourages organizing ideas into systems of parts and wholes, inspired by systems thinkers to explore relationships and how changes in organization impact meaning and understanding.
162. **identify_job_stories**: Identifies key job stories or requirements for roles.
163. **improve_academic_writing**: Refines text into clear, concise academic language while improving grammar, coherence, and clarity, with a list of changes.
164. **improve_prompt**: Improves an LLM/AI prompt by applying expert prompt writing strategies for better results and clarity.
165. **improve_report_finding**: Improves a penetration test security finding by providing detailed descriptions, risks, recommendations, references, quotes, and a concise summary in markdown format.
166. **improve_writing**: Refines text by correcting grammar, enhancing style, improving clarity, and maintaining the original meaning. skills.
167. **judge_output**: Evaluates Honeycomb queries by judging their effectiveness, providing critiques and outcomes based on language nuances and analytics relevance.
168. **label_and_rate**: Labels content with up to 20 single-word tags and rates it based on idea count and relevance to human meaning, AI, and other related themes, assigning a tier (S, A, B, C, D) and a quality score.
169. **md_callout**: Classifies content and generates a markdown callout based on the provided text, selecting the most appropriate type.
170. **model_as_sherlock_freud**: Builds psychological models using detective reasoning and psychoanalytic insight to understand human behavior.
171. **official_pattern_template**: Template to use if you want to create new fabric patterns.
172. **predict_person_actions**: Predicts behavioral responses based on psychological profiles and challenges.
173. **prepare_7s_strategy**: Prepares a comprehensive briefing document from 7S's strategy capturing organizational profile, strategic elements, and market dynamics with clear, concise, and organized content.
174. **provide_guidance**: Provides psychological and life coaching advice, including analysis, recommendations, and potential diagnoses, with a compassionate and honest tone.
175. **rate_ai_response**: Rates the quality of AI responses by comparing them to top human expert performance, assigning a letter grade, reasoning, and providing a 1-100 score based on the evaluation.
176. **rate_ai_result**: Assesses the quality of AI/ML/LLM work by deeply analyzing content, instructions, and output, then rates performance based on multiple dimensions, including coverage, creativity, and interdisciplinary thinking.
177. **rate_content**: Labels content with up to 20 single-word tags and rates it based on idea count and relevance to human meaning, AI, and other related themes, assigning a tier (S, A, B, C, D) and a quality score.
178. **rate_value**: Produces the best possible output by deeply analyzing and understanding the input and its intended purpose.
179. **raw_query**: Fully digests and contemplates the input to produce the best possible result based on understanding the sender's intent.
180. **recommend_artists**: Recommends a personalized festival schedule with artists aligned to your favorite styles and interests, including rationale.
181. **recommend_pipeline_upgrades**: Optimizes vulnerability-checking pipelines by incorporating new information and improving their efficiency, with detailed explanations of changes.
182. **recommend_talkpanel_topics**: Produces a clean set of proposed talks or panel talking points for a person based on their interests and goals, formatted for submission to a conference organizer.
183. **recommend_yoga_practice**: Provides personalized yoga sequences, meditation guidance, and holistic lifestyle advice based on individual profiles.
184. **refine_design_document**: Refines a design document based on a design review by analyzing, mapping concepts, and implementing changes using valid Markdown.
185. **review_design**: Reviews and analyzes architecture design, focusing on clarity, component design, system integrations, security, performance, scalability, and data management.
186. **sanitize_broken_html_to_markdown**: Converts messy HTML into clean, properly formatted Markdown, applying custom styling and ensuring compatibility with Vite.
187. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
188. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
189. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
190. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
191. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
192. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
193. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
194. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
195. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
196. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
197. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
198. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
199. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
200. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
201. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
202. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
203. **t_check_dunning_kruger**: Assess narratives for Dunning-Kruger patterns by contrasting self-perception with demonstrated competence and confidence cues.
204. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
205. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
206. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
207. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
208. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
209. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
210. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
211. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
212. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
213. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
214. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
215. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
216. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
217. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
218. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
219. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
220. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
221. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
222. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
223. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
224. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
225. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
226. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
227. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
228. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
229. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
230. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.
155. **heal_person**: Develops a comprehensive plan for spiritual and mental healing based on psychological profiles, providing personalized recommendations for mental health improvement and overall life enhancement.
156. **humanize**: Rewrites AI-generated text to sound natural, conversational, and easy to understand, maintaining clarity and simplicity.
157. **identify_dsrp_distinctions**: Encourages creative, systems-based thinking by exploring distinctions, boundaries, and their implications, drawing on insights from prominent systems thinkers.
158. **identify_dsrp_perspectives**: Explores the concept of distinctions in systems thinking, focusing on how boundaries define ideas, influence understanding, and reveal or obscure insights.
159. **identify_dsrp_relationships**: Encourages exploration of connections, distinctions, and boundaries between ideas, inspired by systems thinkers to reveal new insights and patterns in complex systems.
160. **identify_dsrp_systems**: Encourages organizing ideas into systems of parts and wholes, inspired by systems thinkers to explore relationships and how changes in organization impact meaning and understanding.
161. **identify_job_stories**: Identifies key job stories or requirements for roles.
162. **improve_academic_writing**: Refines text into clear, concise academic language while improving grammar, coherence, and clarity, with a list of changes.
163. **improve_prompt**: Improves an LLM/AI prompt by applying expert prompt writing strategies for better results and clarity.
164. **improve_report_finding**: Improves a penetration test security finding by providing detailed descriptions, risks, recommendations, references, quotes, and a concise summary in markdown format.
165. **improve_writing**: Refines text by correcting grammar, enhancing style, improving clarity, and maintaining the original meaning. skills.
166. **judge_output**: Evaluates Honeycomb queries by judging their effectiveness, providing critiques and outcomes based on language nuances and analytics relevance.
167. **label_and_rate**: Labels content with up to 20 single-word tags and rates it based on idea count and relevance to human meaning, AI, and other related themes, assigning a tier (S, A, B, C, D) and a quality score.
168. **md_callout**: Classifies content and generates a markdown callout based on the provided text, selecting the most appropriate type.
169. **model_as_sherlock_freud**: Builds psychological models using detective reasoning and psychoanalytic insight to understand human behavior.
170. **official_pattern_template**: Template to use if you want to create new fabric patterns.
171. **predict_person_actions**: Predicts behavioral responses based on psychological profiles and challenges.
172. **prepare_7s_strategy**: Prepares a comprehensive briefing document from 7S's strategy capturing organizational profile, strategic elements, and market dynamics with clear, concise, and organized content.
173. **provide_guidance**: Provides psychological and life coaching advice, including analysis, recommendations, and potential diagnoses, with a compassionate and honest tone.
174. **rate_ai_response**: Rates the quality of AI responses by comparing them to top human expert performance, assigning a letter grade, reasoning, and providing a 1-100 score based on the evaluation.
175. **rate_ai_result**: Assesses the quality of AI/ML/LLM work by deeply analyzing content, instructions, and output, then rates performance based on multiple dimensions, including coverage, creativity, and interdisciplinary thinking.
176. **rate_content**: Labels content with up to 20 single-word tags and rates it based on idea count and relevance to human meaning, AI, and other related themes, assigning a tier (S, A, B, C, D) and a quality score.
177. **rate_value**: Produces the best possible output by deeply analyzing and understanding the input and its intended purpose.
178. **raw_query**: Fully digests and contemplates the input to produce the best possible result based on understanding the sender's intent.
179. **recommend_artists**: Recommends a personalized festival schedule with artists aligned to your favorite styles and interests, including rationale.
180. **recommend_pipeline_upgrades**: Optimizes vulnerability-checking pipelines by incorporating new information and improving their efficiency, with detailed explanations of changes.
181. **recommend_talkpanel_topics**: Produces a clean set of proposed talks or panel talking points for a person based on their interests and goals, formatted for submission to a conference organizer.
182. **recommend_yoga_practice**: Provides personalized yoga sequences, meditation guidance, and holistic lifestyle advice based on individual profiles.
183. **refine_design_document**: Refines a design document based on a design review by analyzing, mapping concepts, and implementing changes using valid Markdown.
184. **review_design**: Reviews and analyzes architecture design, focusing on clarity, component design, system integrations, security, performance, scalability, and data management.
185. **sanitize_broken_html_to_markdown**: Converts messy HTML into clean, properly formatted Markdown, applying custom styling and ensuring compatibility with Vite.
186. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
187. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
188. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
189. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
190. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
191. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
192. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
193. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
194. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
195. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
196. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
197. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
198. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
199. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
200. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
201. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
202. **t_check_dunning_kruger**: Assess narratives for Dunning-Kruger patterns by contrasting self-perception with demonstrated competence and confidence cues.
203. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
204. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
205. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
206. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
207. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
208. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
209. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
210. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
211. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
212. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
213. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
214. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
215. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
216. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
217. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
218. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
219. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
220. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
221. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
222. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
223. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
224. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
225. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
226. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
227. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
228. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
229. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.

View File

@@ -81,13 +81,13 @@ Match the request to one or more of these primary categories:
**CLASSIFICATION**: apply_ul_tags
**CONVERSION**: clean_text, convert_to_markdown, create_graph_from_input, export_data_as_csv, extract_videoid, get_youtube_rss, humanize, md_callout, sanitize_broken_html_to_markdown, to_flashcards, transcribe_minutes, translate, tweet, write_latex
**CONVERSION**: clean_text, convert_to_markdown, create_graph_from_input, export_data_as_csv, extract_videoid, humanize, md_callout, sanitize_broken_html_to_markdown, to_flashcards, transcribe_minutes, translate, tweet, write_latex
**CR THINKING**: capture_thinkers_work, create_idea_compass, create_markmap_visualization, dialog_with_socrates, extract_alpha, extract_controversial_ideas, extract_extraordinary_claims, extract_predictions, extract_primary_problem, extract_wisdom_nometa, find_hidden_message, find_logical_fallacies, summarize_debate, t_analyze_challenge_handling, t_check_dunning_kruger, t_find_blindspots, t_find_negative_thinking, t_find_neglected_goals, t_red_team_thinking
**CREATIVITY**: create_mnemonic_phrases, write_essay
**DEVELOPMENT**: agility_story, analyze_logs, analyze_prose_json, answer_interview_question, ask_secure_by_design_questions, ask_uncle_duke, coding_master, create_coding_feature, create_coding_project, create_command, create_design_document, create_git_diff_commit, create_loe_document, create_mermaid_visualization, create_mermaid_visualization_for_github, create_pattern, create_prd, create_sigma_rules, create_user_story, explain_code, explain_docs, explain_project, export_data_as_csv, extract_algorithm_update_recommendations, extract_mcp_servers, extract_poc, extract_product_features, generate_code_rules, get_youtube_rss, identify_job_stories, improve_prompt, official_pattern_template, recommend_pipeline_upgrades, refine_design_document, review_code, review_design, sanitize_broken_html_to_markdown, suggest_pattern, summarize_git_changes, summarize_git_diff, summarize_pull-requests, write_nuclei_template_rule, write_pull-request, write_semgrep_rule
**DEVELOPMENT**: agility_story, analyze_logs, analyze_prose_json, answer_interview_question, ask_secure_by_design_questions, ask_uncle_duke, coding_master, create_coding_feature, create_coding_project, create_command, create_design_document, create_git_diff_commit, create_loe_document, create_mermaid_visualization, create_mermaid_visualization_for_github, create_pattern, create_prd, create_sigma_rules, create_user_story, explain_code, explain_docs, explain_project, export_data_as_csv, extract_algorithm_update_recommendations, extract_mcp_servers, extract_poc, extract_product_features, generate_code_rules, identify_job_stories, improve_prompt, official_pattern_template, recommend_pipeline_upgrades, refine_design_document, review_code, review_design, sanitize_broken_html_to_markdown, suggest_pattern, summarize_git_changes, summarize_git_diff, summarize_pull-requests, write_nuclei_template_rule, write_pull-request, write_semgrep_rule
**DEVOPS**: analyze_terraform_plan

View File

@@ -942,10 +942,6 @@ Convert content to markdown, preserving original content and structure.
Extract data and convert to CSV, preserving data integrity.
### get_youtube_rss
Generate RSS feed URLs for YouTube channels.
### sanitize_broken_html_to_markdown
Clean/convert malformed HTML to markdown.

View File

@@ -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"`

View File

@@ -29,6 +29,9 @@ func CreateOutputFile(message string, fileName string) (err error) {
return
}
defer file.Close()
if !strings.HasSuffix(message, "\n") {
message += "\n"
}
if _, err = file.WriteString(message); err != nil {
err = fmt.Errorf("%s", fmt.Sprintf(i18n.T("error_writing_to_file"), err))
} else {

View File

@@ -24,5 +24,34 @@ func TestCreateOutputFile(t *testing.T) {
t.Fatalf("CreateOutputFile() error = %v", err)
}
defer os.Remove(fileName)
t.Cleanup(func() { os.Remove(fileName) })
data, err := os.ReadFile(fileName)
if err != nil {
t.Fatalf("failed to read output file: %v", err)
}
expected := message + "\n"
if string(data) != expected {
t.Fatalf("expected file contents %q, got %q", expected, data)
}
}
func TestCreateOutputFileMessageWithTrailingNewline(t *testing.T) {
fileName := "test_output_with_newline.txt"
message := "test message with newline\n"
if err := CreateOutputFile(message, fileName); err != nil {
t.Fatalf("CreateOutputFile() error = %v", err)
}
t.Cleanup(func() { os.Remove(fileName) })
data, err := os.ReadFile(fileName)
if err != nil {
t.Fatalf("failed to read output file: %v", err)
}
if string(data) != message {
t.Fatalf("expected file contents %q, got %q", message, data)
}
}

View File

@@ -69,6 +69,7 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s
responseChan := make(chan string)
errChan := make(chan error, 1)
done := make(chan struct{})
printedStream := false
go func() {
defer close(done)
@@ -81,9 +82,14 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s
message += response
if !opts.SuppressThink {
fmt.Print(response)
printedStream = true
}
}
if printedStream && !opts.SuppressThink && !strings.HasSuffix(message, "\n") {
fmt.Println()
}
// Wait for goroutine to finish
<-done
@@ -175,7 +181,7 @@ func (o *Chatter) BuildSession(request *domain.ChatRequest, raw bool) (session *
if request.Message == nil {
request.Message = &chat.ChatCompletionMessage{
Role: chat.ChatMessageRoleUser,
Content: " ",
Content: "",
}
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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": "فهرست تمام مدل‌های موجود",

View File

@@ -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 doptions de discussion (temperature, top_p, etc.). Naffecte 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",

View File

@@ -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",

View File

@@ -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": "すべての利用可能なモデルを一覧表示",

View File

@@ -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"
}
}

View File

@@ -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",

View File

@@ -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": "列出所有可用模型",

View File

@@ -356,7 +356,7 @@ func (an *Client) toMessages(msgs []*chat.ChatCompletionMessage) (ret []anthropi
lastRoleWasUser := false
for _, msg := range msgs {
if msg.Content == "" {
if strings.TrimSpace(msg.Content) == "" {
continue // Skip empty messages
}

View File

@@ -131,6 +131,8 @@ func (o *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) (err error) {
ctx := context.Background()
defer close(channel)
var client *genai.Client
if client, err = genai.NewClient(ctx, &genai.ClientConfig{
APIKey: o.ApiKey.Value,
@@ -153,8 +155,7 @@ func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha
for response, err := range stream {
if err != nil {
channel <- fmt.Sprintf("Error: %v\n", err)
close(channel)
break
return err
}
text := o.extractTextFromResponse(response)
@@ -162,7 +163,6 @@ func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha
channel <- text
}
}
close(channel)
return
}
@@ -456,7 +456,7 @@ func (o *Client) convertMessages(msgs []*chat.ChatCompletionMessage) []*genai.Co
content.Role = "user"
}
if msg.Content != "" {
if strings.TrimSpace(msg.Content) != "" {
content.Parts = append(content.Parts, &genai.Part{Text: msg.Content})
}

View File

@@ -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]

View 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)
}
})
}
}

View File

@@ -1 +1 @@
"1.4.324"
"1.4.329"

View File

@@ -1101,14 +1101,6 @@
"REVIEW"
]
},
{
"patternName": "get_youtube_rss",
"description": "Generate RSS feed URLs for YouTube channels.",
"tags": [
"CONVERSION",
"DEVELOPMENT"
]
},
{
"patternName": "humanize",
"description": "Transform technical content into approachable language.",

View File

@@ -540,10 +540,6 @@
"patternName": "get_wow_per_minute",
"pattern_extract": "# IDENTITY\n\nYou are an expert at determining the wow-factor of content as measured per minute of content, as determined by the steps below.\n\n# GOALS\n\n- The goal is to determine how densely packed the content is with wow-factor. Note that wow-factor can come from multiple types of wow, such as surprise, novelty, insight, value, and wisdom, and also from multiple types of content such as business, science, art, or philosophy.\n\n- The goal is to determine how rewarding this content will be for a viewer in terms of how often they'll be surprised, learn something new, gain insight, find practical value, or gain wisdom.\n\n# STEPS\n\n- Fully and deeply consume the content at least 319 times, using different interpretive perspectives each time.\n\n- Construct a giant virtual whiteboard in your mind.\n\n- Extract the ideas being presented in the content and place them on your giant virtual whiteboard.\n\n- Extract the novelty of those ideas and place them on your giant virtual whiteboard.\n\n- Extract the insights from those ideas and place them on your giant virtual whiteboard.\n\n- Extract the value of those ideas and place them on your giant virtual whiteboard.\n\n- Extract the wisdom of those ideas and place them on your giant virtual whiteboard."
},
{
"patternName": "get_youtube_rss",
"pattern_extract": "# IDENTITY AND GOALS\n\nYou are a YouTube infrastructure expert that returns YouTube channel RSS URLs.\n\nYou take any input in, especially YouTube channel IDs, or full URLs, and return the RSS URL for that channel.\n\n# STEPS\n\nHere is the structure for YouTube RSS URLs and their relation to the channel ID and or channel URL:\n\nIf the channel URL is https://www.youtube.com/channel/UCnCikd0s4i9KoDtaHPlK-JA, the RSS URL is https://www.youtube.com/feeds/videos.xml?channel_id=UCnCikd0s4i9KoDtaHPlK-JA\n\n- Extract the channel ID from the channel URL.\n\n- Construct the RSS URL using the channel ID.\n\n- Output the RSS URL.\n\n# OUTPUT\n\n- Output only the RSS URL and nothing else.\n\n- Don't complain, just do it.\n\n# INPUT"
},
{
"patternName": "humanize",
"pattern_extract": "# IDENTITY and PURPOSE\n\nYou are a real person whose job is to make text sound natural, conversational, and relatable, just like how an average person talks or writes. Your goal is to rewrite content in a casual, human-like style, prioritizing clarity and simplicity. You should aim for short sentences, an active voice, and everyday language that feels familiar and easy to follow. Avoid long, complex sentences or technical jargon. Instead, focus on breaking ideas into smaller, easy-to-understand parts. Write as though you're explaining something to a friend, keeping it friendly and approachable. Always think step-by-step about how to make the text feel more natural and conversational, using the examples provided as a guide for improvement.\n\nWhile rewriting, ensure the original meaning and tone are preserved. Strive for a consistent style that flows naturally, even if the given text is a mix of AI and human-generated content.\n\n# YOUR TASK\n\nYour task is to rewrite the given AI-generated text to make it sound like it was written by a real person. The rewritten text should be clear, simple, and easy to understand, using everyday language that feels natural and relatable.\n\n- Focus on clarity: Make sure the text is straightforward and avoids unnecessary complexity.\n- Keep it simple: Use common words and phrases that anyone can understand.\n- Prioritize short sentences: Break down long, complicated sentences into smaller, more digestible ones.\n- Maintain context: Ensure that the rewritten text accurately reflects the original meaning and tone.\n- Harmonize mixed content: If the text contains a mix of human and AI styles, edit to ensure a consistent, human-like flow.\n- Iterate if necessary: Revisit and refine the text to enhance its naturalness and readability.\n\nYour goal is to make the text approachable and authentic, capturing the way a real person would write or speak.\n\n# STEPS\n\n1. Carefully read the given text and understand its meaning and tone.\n2. Process the text phrase by phrase, ensuring that you preserve its original intent.\n3. Refer to the **EXAMPLES** section for guidance, avoiding the \"AI Style to Avoid\" and mimicking the \"Human Style to Adopt\" in your rewrites.\n4. If no relevant example exists in the **EXAMPLES** section:"

View File

@@ -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

View File

@@ -1101,14 +1101,6 @@
"REVIEW"
]
},
{
"patternName": "get_youtube_rss",
"description": "Generate RSS feed URLs for YouTube channels.",
"tags": [
"CONVERSION",
"DEVELOPMENT"
]
},
{
"patternName": "humanize",
"description": "Transform technical content into approachable language.",