Skip to content

Commit

Permalink
Merge pull request #40 from ajcwebdev/types
Browse files Browse the repository at this point in the history
Improve Type Strictness
  • Loading branch information
ajcwebdev authored Nov 5, 2024
2 parents 1060b56 + 0fa5b5d commit b7620bf
Show file tree
Hide file tree
Showing 26 changed files with 686 additions and 315 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ dist
NEW.md
TODO.md
nemo_msdd_configs
temp_outputs
temp_outputs
tsconfig.tsbuildinfo
51 changes: 42 additions & 9 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Content and Feed Inputs](#content-and-feed-inputs)
- [Process Single Video URLs](#process-single-video-urls)
- [Process Multiple Videos in YouTube Playlist](#process-multiple-videos-in-youtube-playlist)
- [Process All Videos from a YouTube Channel](#process-all-videos-from-a-youtube-channel)
- [Process Multiple Videos Specified in a URLs File](#process-multiple-videos-specified-in-a-urls-file)
- [Process Single Audio or Video File](#process-single-audio-or-video-file)
- [Process Podcast RSS Feed](#process-podcast-rss-feed)
Expand Down Expand Up @@ -62,11 +63,45 @@ npm run as -- \

### Process All Videos from a YouTube Channel

Process all videos from a YouTube channel (both live and non-live):

```bash
npm run as -- \
--channel "https://www.youtube.com/@ajcwebdev"
```

Process videos starting from the oldest instead of newest:

```bash
npm run as -- \
--channel "https://www.youtube.com/@ajcwebdev" \
--order oldest
```

Skip a certain number of videos before beginning processing (starts from newest by default and can be used with `--order oldest`):

```bash
npm run as -- \
--channel "https://www.youtube.com/@ajcwebdev" \
--skip 1
```

Process a certain number of the most recent videos, for example the last three videos released on the channel:

```bash
npm run as -- \
--channel "https://www.youtube.com/@ajcwebdev" \
--last 3
```

Run on a YouTube channel and generate JSON info file with markdown metadata of each video:

```bash
npm run as -- \
--channel "https://www.youtube.com/@ajcwebdev" \
--info
```

### Process Multiple Videos Specified in a URLs File

Run on an arbitrary list of URLs in `example-urls.md`.
Expand Down Expand Up @@ -102,38 +137,36 @@ npm run as -- \
--rss "https://ajcwebdev.substack.com/feed"
```

Process a certain number of the most recent items, for example the last three episodes released on the feed:
Process RSS feed from oldest to newest:

```bash
npm run as -- \
--rss "https://feeds.transistor.fm/fsjam-podcast/" \
--last 3
--order oldest
```

Process RSS feed from oldest to newest:
Start processing a different episode by selecting a number of episodes to skip:

```bash
npm run as -- \
--rss "https://feeds.transistor.fm/fsjam-podcast/" \
--order oldest
--skip 1
```

Start processing a different episode by selecting a number of episodes to skip:
Process a certain number of the most recent items, for example the last three episodes released on the feed:

```bash
npm run as -- \
--rss "https://feeds.transistor.fm/fsjam-podcast/" \
--skip 1
--last 3
```

Process a single specific episode from a podcast RSS feed by providing the episode's audio URL with the `--item` option:

```bash
npm run as -- \
--rss "https://ajcwebdev.substack.com/feed" \
--item "https://api.substack.com/feed/podcast/36236609/fd1f1532d9842fe1178de1c920442541.mp3" \
--ollama \
--prompt titles summary longChapters takeaways questions
--item "https://api.substack.com/feed/podcast/36236609/fd1f1532d9842fe1178de1c920442541.mp3"
```

Run on a podcast RSS feed and generate JSON info file with markdown metadata of each item:
Expand Down
19 changes: 9 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@
"setup-python": "bash ./scripts/setup-python.sh",
"autoshow": "npm run tsx:base -- src/autoshow.ts",
"as": "npm run tsx:base -- src/autoshow.ts",
"v": "npm run tsx:base -- src/autoshow.ts --video",
"u": "npm run tsx:base -- src/autoshow.ts --urls",
"urls": "npm run tsx:base -- src/autoshow.ts --urls content/urls.md",
"p": "npm run tsx:base -- src/autoshow.ts --playlist",
"f": "npm run tsx:base -- src/autoshow.ts --file",
"r": "npm run tsx:base -- src/autoshow.ts --rss",
"rss-info": "npm run tsx:base -- src/autoshow.ts --info --rss",
"info": "npm run tsx:base -- src/autoshow.ts --info",
"last2": "npm run tsx:base -- src/autoshow.ts --last 2 --rss",
"last3": "npm run tsx:base -- src/autoshow.ts --last 3 --rss",
"v": "npm run as -- --video",
"u": "npm run as -- --urls",
"p": "npm run as -- --playlist",
"f": "npm run as -- --file",
"r": "npm run as -- --rss",
"rss-info": "npm run as -- --info --rss",
"info": "npm run as -- --info",
"last2": "npm run as -- --last 2 --rss",
"last3": "npm run as -- --last 3 --rss",
"docker": "docker compose run --remove-orphans --rm autoshow --whisperDocker",
"docker-up": "docker compose up --build -d --remove-orphans --no-start",
"ds": "docker compose images && docker compose ls",
Expand Down
84 changes: 50 additions & 34 deletions src/autoshow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ import type { ProcessingOptions, HandlerFunction, LLMServices, TranscriptService
// Initialize the command-line interface using Commander.js
const program = new Command()

// Define valid action types
type ValidAction = 'video' | 'playlist' | 'channel' | 'urls' | 'file' | 'rss'

// Define the process handlers with strict typing
const PROCESS_HANDLERS: Record<ValidAction, HandlerFunction> = {
video: processVideo,
playlist: processPlaylist,
channel: processChannel,
urls: processURLs,
file: processFile,
rss: processRSS,
}

// Type guard to check if a string is a valid action
function isValidAction(action: string | undefined): action is ValidAction {
return Boolean(action && action in PROCESS_HANDLERS)
}

/**
* Defines the command-line interface options and descriptions.
* Sets up all available commands and their respective flags
Expand All @@ -48,7 +66,7 @@ program
.option('--order <order>', 'Specify the order for RSS feed processing (newest or oldest)')
.option('--skip <number>', 'Number of items to skip when processing RSS feed', parseInt)
.option('--last <number>', 'Number of most recent items to process (overrides --order and --skip)', parseInt)
.option('--info', 'Generate JSON file with RSS feed or channel information instead of processing items')
.option('--info', 'Skip processing and write metadata to JSON objects (supports --urls, --rss, --playlist, --channel)')
// Transcription service options
.option('--whisper [model]', 'Use Whisper.cpp for transcription with optional model specification')
.option('--whisperDocker [model]', 'Use Whisper.cpp in Docker for transcription with optional model specification')
Expand Down Expand Up @@ -98,34 +116,22 @@ program.action(async (options: ProcessingOptions) => {
l(opts(JSON.stringify(options, null, 2)))
l(``)

// Define mapping of action types to their handler functions
const PROCESS_HANDLERS: Record<string, HandlerFunction> = {
video: processVideo,
playlist: processPlaylist,
channel: processChannel,
urls: processURLs,
file: processFile,
rss: processRSS,
}

// Extract interactive mode flag
const { interactive } = options

// Check if no action option was provided
const noActionProvided = ACTION_OPTIONS.every((opt) => !options[opt as keyof ProcessingOptions])

// If in interactive mode or no action provided, prompt user for input
if (interactive || noActionProvided) {
if (interactive) {
options = await handleInteractivePrompt(options)
}

// Ensure options.item is always an array if provided via command line
if (options.item && !Array.isArray(options.item)) {
options.item = [options.item]
}

// Extract the action values from ACTION_OPTIONS for validation
const actionValues = ACTION_OPTIONS.map((opt) => opt.name)
// Validate and get single options for action, LLM, and transcription
const action = validateOption(ACTION_OPTIONS, options, 'input option')
const action = validateOption(actionValues, options, 'input option')
const llmKey = validateOption(LLM_OPTIONS, options, 'LLM option')
const llmServices = llmKey as LLMServices | undefined
const transcriptKey = validateOption(TRANSCRIPT_OPTIONS, options, 'transcription option')
Expand All @@ -136,24 +142,34 @@ program.action(async (options: ProcessingOptions) => {
options.whisper = 'large-v3-turbo'
}

// Execute the appropriate handler if an action was specified
if (action) {
try {
// Process the content using the selected handler
await PROCESS_HANDLERS[action](
options,
options[action as keyof ProcessingOptions] as string,
llmServices,
transcriptServices
)
l(final(`\n================================================================================================`))
l(final(` ${action} Processing Completed Successfully.`))
l(final(`================================================================================================\n`))
exit(0)
} catch (error) {
err(`Error processing ${action}:`, (error as Error).message)
exit(1)
// Validate action
if (!isValidAction(action)) {
err(`Invalid or missing action`)
exit(1)
}

try {
// Get input value with proper typing
const input = options[action]

// Ensure we have a valid input value
if (!input || typeof input !== 'string') {
throw new Error(`No valid input provided for ${action} processing`)
}

// Get handler with proper typing
const handler = PROCESS_HANDLERS[action]

// Process the content using the selected handler
await handler(options, input, llmServices, transcriptServices)

l(final(`\n================================================================================================`))
l(final(` ${action} Processing Completed Successfully.`))
l(final(`================================================================================================\n`))
exit(0)
} catch (error) {
err(`Error processing ${action}:`, (error as Error).message)
exit(1)
}
})

Expand Down
Loading

0 comments on commit b7620bf

Please sign in to comment.