bulk commit changes!
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Configurable provider priority
|
||||
The system SHALL support configuring image provider order via `ROYALTY_IMAGE_PROVIDERS` environment variable.
|
||||
|
||||
#### Scenario: Custom provider order
|
||||
- **WHEN** `ROYALTY_IMAGE_PROVIDERS=unsplash,pexels,pixabay,wikimedia,picsum`
|
||||
- **THEN** system tries providers in order: Unsplash → Pexels → Pixabay → Wikimedia → Picsum
|
||||
|
||||
#### Scenario: Default provider order
|
||||
- **WHEN** `ROYALTY_IMAGE_PROVIDERS` is not set or empty
|
||||
- **THEN** system uses default order: `pixabay,unsplash,pexels,wikimedia,picsum`
|
||||
|
||||
#### Scenario: Single provider configured
|
||||
- **WHEN** `ROYALTY_IMAGE_PROVIDERS=pexels`
|
||||
- **THEN** system only tries Pexels provider
|
||||
- **AND** returns `(None, None)` if Pexels fails or is not configured
|
||||
|
||||
### Requirement: Sequential fallback execution
|
||||
The system SHALL try providers sequentially until one returns a valid image.
|
||||
|
||||
#### Scenario: First provider succeeds
|
||||
- **WHEN** provider chain is `pixabay,unsplash,pexels` AND Pixabay returns valid image
|
||||
- **THEN** system returns Pixabay image immediately
|
||||
- **AND** does NOT call Unsplash or Pexels APIs
|
||||
|
||||
#### Scenario: First provider fails, second succeeds
|
||||
- **WHEN** provider chain is `pixabay,unsplash,pexels` AND Pixabay returns no results AND Unsplash returns valid image
|
||||
- **THEN** system returns Unsplash image
|
||||
- **AND** does NOT call Pexels API
|
||||
|
||||
#### Scenario: All providers fail
|
||||
- **WHEN** all configured providers return `(None, None)`
|
||||
- **THEN** system returns `(None, None)` as final result
|
||||
- **AND** caller handles fallback to article image or placeholder
|
||||
|
||||
### Requirement: MCP endpoint override
|
||||
The existing `ROYALTY_IMAGE_MCP_ENDPOINT` SHALL take priority over the provider chain when configured.
|
||||
|
||||
#### Scenario: MCP endpoint configured
|
||||
- **WHEN** `ROYALTY_IMAGE_MCP_ENDPOINT` is set to valid URL
|
||||
- **THEN** system tries MCP endpoint first before provider chain
|
||||
- **AND** falls back to provider chain only if MCP endpoint fails
|
||||
|
||||
#### Scenario: MCP endpoint not configured
|
||||
- **WHEN** `ROYALTY_IMAGE_MCP_ENDPOINT` is empty or unset
|
||||
- **THEN** system skips MCP endpoint and proceeds directly to provider chain
|
||||
|
||||
### Requirement: Provider skip on missing credentials
|
||||
Providers without required API keys SHALL be skipped silently.
|
||||
|
||||
#### Scenario: Skip unconfigured provider
|
||||
- **WHEN** provider chain includes `pixabay` AND `PIXABAY_API_KEY` is not set
|
||||
- **THEN** Pixabay is skipped without error
|
||||
- **AND** chain continues to next provider
|
||||
|
||||
#### Scenario: All providers skipped
|
||||
- **WHEN** no providers in chain have valid API keys configured
|
||||
- **THEN** system falls back to Wikimedia (no key required) or Picsum (always available)
|
||||
@@ -0,0 +1,71 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Keyword extraction from headline
|
||||
The system SHALL extract relevant keywords from article headlines for image search.
|
||||
|
||||
#### Scenario: Extract keywords from standard headline
|
||||
- **WHEN** headline is "OpenAI Announces GPT-5 with Revolutionary Reasoning Capabilities"
|
||||
- **THEN** extracted query is "OpenAI GPT-5 Revolutionary Reasoning"
|
||||
- **AND** stop words like "Announces", "with", "Capabilities" are removed
|
||||
|
||||
#### Scenario: Handle short headline
|
||||
- **WHEN** headline is "AI Breakthrough"
|
||||
- **THEN** extracted query is "AI Breakthrough"
|
||||
- **AND** no keywords are removed (headline too short)
|
||||
|
||||
#### Scenario: Handle headline with special characters
|
||||
- **WHEN** headline is "Tesla's Self-Driving AI: 99.9% Accuracy Achieved!"
|
||||
- **THEN** extracted query is "Tesla Self-Driving AI Accuracy"
|
||||
- **AND** special characters like apostrophes, colons, and punctuation are normalized
|
||||
|
||||
### Requirement: Stop word removal
|
||||
The system SHALL remove common English stop words from search queries.
|
||||
|
||||
#### Scenario: Remove articles and prepositions
|
||||
- **WHEN** headline is "The Future of AI in the Healthcare Industry"
|
||||
- **THEN** extracted query is "Future AI Healthcare Industry"
|
||||
- **AND** "The", "of", "in", "the" are removed
|
||||
|
||||
#### Scenario: Preserve technical terms
|
||||
- **WHEN** headline is "How Machine Learning Models Learn from Data"
|
||||
- **THEN** extracted query is "Machine Learning Models Learn Data"
|
||||
- **AND** technical terms "Machine", "Learning", "Models" are preserved
|
||||
|
||||
### Requirement: Query length limit
|
||||
The system SHALL limit search query length to optimize API results.
|
||||
|
||||
#### Scenario: Truncate long query
|
||||
- **WHEN** extracted keywords exceed 10 words
|
||||
- **THEN** query is limited to first 5 most significant keywords
|
||||
- **AND** remaining keywords are dropped
|
||||
|
||||
#### Scenario: Preserve short query
|
||||
- **WHEN** extracted keywords are 5 words or fewer
|
||||
- **THEN** all keywords are included in query
|
||||
- **AND** no truncation occurs
|
||||
|
||||
### Requirement: URL-safe query encoding
|
||||
The system SHALL URL-encode queries before sending to provider APIs.
|
||||
|
||||
#### Scenario: Encode spaces and special characters
|
||||
- **WHEN** query is "AI Machine Learning"
|
||||
- **THEN** encoded query is "AI+Machine+Learning" or "AI%20Machine%20Learning"
|
||||
- **AND** query is safe for HTTP GET parameters
|
||||
|
||||
#### Scenario: Handle Unicode characters
|
||||
- **WHEN** query contains Unicode like "AI für Deutschland"
|
||||
- **THEN** Unicode characters are properly percent-encoded
|
||||
- **AND** API request succeeds without encoding errors
|
||||
|
||||
### Requirement: Empty query handling
|
||||
The system SHALL handle edge cases where no keywords can be extracted.
|
||||
|
||||
#### Scenario: Headline with only stop words
|
||||
- **WHEN** headline is "The and a or but"
|
||||
- **THEN** system uses fallback query "news technology"
|
||||
- **AND** image search proceeds with generic query
|
||||
|
||||
#### Scenario: Empty headline
|
||||
- **WHEN** headline is empty string or whitespace only
|
||||
- **THEN** system uses fallback query "news technology"
|
||||
- **AND** image search proceeds with generic query
|
||||
@@ -0,0 +1,79 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Pixabay image retrieval
|
||||
The system SHALL support retrieving images from Pixabay API when `PIXABAY_API_KEY` is configured.
|
||||
|
||||
#### Scenario: Successful Pixabay image search
|
||||
- **WHEN** Pixabay is enabled in provider chain AND query is "artificial intelligence breakthrough"
|
||||
- **THEN** system sends GET request to `https://pixabay.com/api/?key={key}&q=artificial+intelligence+breakthrough&image_type=photo&per_page=3&safesearch=true`
|
||||
- **AND** returns first hit's `webformatURL` as image URL
|
||||
- **AND** returns credit as `"Photo by {user} on Pixabay"`
|
||||
|
||||
#### Scenario: Pixabay returns no results
|
||||
- **WHEN** Pixabay search returns empty `hits` array
|
||||
- **THEN** system returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
|
||||
#### Scenario: Pixabay API key not configured
|
||||
- **WHEN** `PIXABAY_API_KEY` environment variable is empty or unset
|
||||
- **THEN** Pixabay provider is skipped in the fallback chain
|
||||
|
||||
### Requirement: Unsplash image retrieval
|
||||
The system SHALL support retrieving images from Unsplash API when `UNSPLASH_ACCESS_KEY` is configured.
|
||||
|
||||
#### Scenario: Successful Unsplash image search
|
||||
- **WHEN** Unsplash is enabled in provider chain AND query is "machine learning robot"
|
||||
- **THEN** system sends GET request to `https://api.unsplash.com/search/photos?query=machine+learning+robot&per_page=3` with header `Authorization: Client-ID {key}`
|
||||
- **AND** returns first result's `urls.regular` as image URL
|
||||
- **AND** returns credit as `"Photo by {user.name} on Unsplash"`
|
||||
|
||||
#### Scenario: Unsplash returns no results
|
||||
- **WHEN** Unsplash search returns empty `results` array
|
||||
- **THEN** system returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
|
||||
#### Scenario: Unsplash API key not configured
|
||||
- **WHEN** `UNSPLASH_ACCESS_KEY` environment variable is empty or unset
|
||||
- **THEN** Unsplash provider is skipped in the fallback chain
|
||||
|
||||
### Requirement: Pexels image retrieval
|
||||
The system SHALL support retrieving images from Pexels API when `PEXELS_API_KEY` is configured.
|
||||
|
||||
#### Scenario: Successful Pexels image search
|
||||
- **WHEN** Pexels is enabled in provider chain AND query is "tech startup office"
|
||||
- **THEN** system sends GET request to `https://api.pexels.com/v1/search?query=tech+startup+office&per_page=3` with header `Authorization: {key}`
|
||||
- **AND** returns first photo's `src.large` as image URL
|
||||
- **AND** returns credit as `"Photo by {photographer} on Pexels"`
|
||||
|
||||
#### Scenario: Pexels returns no results
|
||||
- **WHEN** Pexels search returns empty `photos` array
|
||||
- **THEN** system returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
|
||||
#### Scenario: Pexels API key not configured
|
||||
- **WHEN** `PEXELS_API_KEY` environment variable is empty or unset
|
||||
- **THEN** Pexels provider is skipped in the fallback chain
|
||||
|
||||
### Requirement: Provider timeout handling
|
||||
Each provider API call SHALL timeout after 15 seconds.
|
||||
|
||||
#### Scenario: Provider request timeout
|
||||
- **WHEN** provider API does not respond within 15 seconds
|
||||
- **THEN** system logs timeout warning
|
||||
- **AND** returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
|
||||
### Requirement: Provider error handling
|
||||
The system SHALL gracefully handle provider API errors without crashing.
|
||||
|
||||
#### Scenario: Provider returns HTTP error
|
||||
- **WHEN** provider API returns 4xx or 5xx status code
|
||||
- **THEN** system logs error with status code
|
||||
- **AND** returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
|
||||
#### Scenario: Provider returns malformed response
|
||||
- **WHEN** provider API returns invalid JSON or unexpected schema
|
||||
- **THEN** system logs parsing error
|
||||
- **AND** returns `(None, None)` for this provider
|
||||
- **AND** fallback chain continues to next provider
|
||||
Reference in New Issue
Block a user