Skip to content

Conversation

@Orinks
Copy link
Owner

@Orinks Orinks commented Dec 11, 2025

No description provided.

Orinks added 30 commits December 7, 2025 21:44
- Add AIExplainer module with OpenRouter API integration
- Add AI settings to AppSettings (enable_ai_explanations, openrouter_api_key, ai_model_preference, ai_explanation_style, ai_cache_ttl)
- Add explanation dialog with accessibility support (ARIA labels, focus management)
- Add AI settings tab to settings dialog
- Add event handler for explain weather button
- Implement caching for explanations (5-minute TTL)
- Implement cost estimation and session usage tracking
- Add comprehensive test suite with property-based tests (47 tests)

Implements tasks 1-16 of the AI weather explanations spec.

Requirements validated:
- Property 1: Button visibility follows AI enablement setting
- Property 2: Model selection matches configuration
- Property 3: Cache prevents duplicate API calls
- Property 4: Settings persistence round-trip
- Property 5: Prompt includes all required weather fields
- Property 6: Alerts included when present
- Property 7: Markdown formatting follows HTML setting
- Property 8: Most recent data source selected
- Property 9: Error messages are user-friendly
- Property 13: Session usage accumulates correctly
- Property 14: Free model cost display
- Add 'Explain Weather' button to weather display section in ui_builder.py
- Initialize AI explanation cache in app_initialization.py
- Add dynamic button visibility updates in app.py refresh_runtime_settings()
- Button appears conditionally based on enable_ai_explanations setting
- Supports real-time show/hide when settings change without app restart
- Integrates with existing AI handlers and accessibility features

Completes task 10 from ai-weather-explanations spec implementation plan.
OpenRouter requires authentication for ALL API requests, including free models.
The :free suffix only means no charges, not no authentication.

Updated error message to guide users to get a free API key at openrouter.ai/keys
and clarify that free models won't charge their account.
- Add 'Validate API Key' button to AI settings tab (similar to Visual Crossing)
- Implement validate_openrouter_api_key() in settings_operations.py
- Uses OpenRouter's /api/v1/models endpoint for lightweight validation
- Includes retry logic with backoff for transient failures
- Shows clear success/error messages with guidance
- Update label to clarify API key is required (not optional)
- Redacts API key from logs and error messages for security
The /api/v1/models endpoint doesn't require authentication, so any key
appeared valid. Changed to /api/v1/key which:
- Returns 401 for invalid keys
- Returns key info (label, tier) for valid keys
- Shows key label and tier (free/paid) in success message
The OpenRouter API key was not being saved because it wasn't in the
secure_keys list. Added it to:
- config_manager.py: _load_secure_keys() to load from keyring on startup
- settings.py: update_settings() to save to keyring and redact in logs
Added _apply_ai_settings() function to settings_handlers.py that:
- Loads the OpenRouter API key from settings into the input field
- Loads the enable AI switch state
- Loads the model preference selection
- Loads the explanation style selection

The function is now called in apply_settings_to_ui() so AI settings
are properly displayed when the settings dialog is opened.
The to_dict() method on AppSettings excludes secure keys (API keys) for
security reasons. This meant that when _on_ok called update_settings with
**new_settings.to_dict(), the API keys were never passed and thus never
saved to secure storage.

Fixed by explicitly adding visual_crossing_api_key and openrouter_api_key
to the settings dict before calling update_settings.

Also updated test_secure_storage_integration to expect 5 secure key loads
instead of 4 (added openrouter_api_key).
- Updated _call_openrouter to include actual error details in exception messages
- Added detection for 401/unauthorized errors as InvalidAPIKeyError
- Generic errors now show the actual API error message instead of generic text
- Updated ai_handlers.py to show actual error details for unexpected exceptions

This helps users understand what went wrong when AI explanations fail.
- Set MultilineTextInput value after widget creation instead of in constructor
- Added fallback text if explanation is empty
- Added debug logging to help diagnose display issues
- Log raw content from OpenRouter API
- Log formatted text after processing
- Handle None content from API response
- Use setup_logging from logging_config.py instead of local implementation
- Logs now written to ~/AccessiWeather_logs/accessiweather.log
- debug_mode flag now properly sets log level to DEBUG
- Removes duplicate setup_logging function from main.py
- Logs now saved to {config_dir}/logs/accessiweather.log
- Windows: %APPDATA%\.accessiweather\logs\
- Linux/macOS: ~/.accessiweather/logs/
- Portable mode: {app_dir}/config/logs/
- Updated tests to mock get_config_dir instead of Path.home
- Add comprehensive PRD for AI Weather Explanations feature
- Add BMAD methodology integration (agents, workflows, tools)
- Add full architecture documentation
- Add development and deployment guides
- Add cross-platform sync scripts for WSL/Windows workflow
- Add GitHub Copilot agent configurations
- Document brownfield workflow status tracking
- Add unit tests for forecast period inclusion in prompts
- Add property-based tests for cache behavior and key consistency
- Add unit tests for AFD explanation functionality
- Add tests for ForecastDiscussionDialog component
- Add integration tests for forecast and AFD explanations
- Mark tasks 6-10 as completed in tasks.md

Tests cover:
- Forecast periods properly included in weather explanations
- AFD explanation UI integration with plain language translation
- Cache prevents duplicate API calls (property test)
- AFD technical jargon translation verification
- Add toga.ActivityIndicator for visual spinner animation
- Set closable=False to prevent closing during loading
- Start/stop indicator properly on show/close
- Consistent with UpdateProgressDialog pattern
- Add Cancel button to LoadingDialog for user control
- Track cancellation state with is_cancelled flag
- Update AI handler to check for cancellation after generation
- Remove excessive debug logging from ai_explainer.py
- Simplify _format_response and _call_openrouter methods
- Add custom_system_prompt and custom_instructions fields to AppSettings
- Implement get_effective_system_prompt() for custom/default prompt selection
- Add get_default_system_prompt() static method for UI display
- Add get_prompt_preview() method for prompt preview functionality
- Modify _build_prompt() to include custom instructions after weather data
- Add property-based tests for configuration round-trip
- Add property-based tests for custom prompt usage and fallback behavior
- Add property-based tests for custom instructions inclusion and positioning
- Add property-based tests for prompt preview functionality

Validates Requirements: 1.2, 1.3, 1.4, 1.5, 2.1, 2.2, 2.3, 2.4, 4.1, 4.2, 4.3
- Add prompt customization section to AI settings tab
- Add custom system prompt multiline input with placeholder
- Add custom instructions multiline input
- Add reset buttons for system prompt and instructions
- Add preview prompt button with dialog
- Add accessibility attributes to all form elements
- Wire custom prompts from settings to AIExplainer in handlers
- Update discussion dialog to use custom prompts
- Add property tests for reset behavior
- Add property tests for accessibility attributes

Validates Requirements: 1.1, 1.5, 2.1, 3.1, 3.2, 3.3, 3.4, 4.1, 4.2, 5.1, 5.2, 5.3, 5.4
@Orinks Orinks merged commit 40f4b6f into dev Dec 12, 2025
4 checks passed
@Orinks Orinks deleted the feature/ai-weather-explanations branch December 12, 2025 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants