
A fun tool that turns your GitHub code into Eurovision music during our 2-hour hands-on workshop. Code + Music = Fun!
Analyze commit patterns and developer coding style
Match coding moods with iconic Eurovision songs
Turn recommendations into playable playlists
Share your coding soundtrack with the world

2
We Are Developers 2025

3
We Are Developers 2025
Explore the versatile configuration options within GitHub Copilot to customize its behavior and optimize your development workflow.
Manage and create custom .prompt.md files for tailored Copilot interactions, stored in .github/prompts/.
Configure global coding style, documentation, and testing guidelines for Copilot, typically in .github/copilot-instructions.md.
Define and customize which tools Copilot can access in agent mode, such as codebase navigation, terminal, or web search.
Switch between interaction modes like "Ask" (Q&A) or "Agent" (autonomous task execution) to control Copilot's actions.
Connect to custom model servers, configure parameters, and adjust context settings for enterprise-specific Copilot deployments.
Automatically analyze your codebase to create instruction templates, helping establish consistent coding standards effortlessly.
Access general settings for the Copilot Chat interface, including visual preferences, auto-completion, and context inclusion.

4
We Are Developers 2025
Extract commit history and message content
Process commit messages for emotional context
Match commit patterns to Eurovision songs
Create playable playlists from recommendations

5
We Are Developers 2025
Connect to GitHub API and analyze commit patterns
Use AI to match commits with Eurovision songs
Make playlists playable with Spotify
Add sharing features and analytics
Error handling and performance optimization
Flow suggestions but this is your time!

6
We Are Developers 2025
Click the button: No fork needed. Uses the workshop's minutes, not yours.
Ensure the `gitvision` project loads. Flutter & Dart should already be installed.
Tip: Refresh if Codespace stalls during initialization.
7
We Are Developers 2025
cd gitvision
chmod +x workshop-start.sh
./workshop-start.sh
This script will:
You'll see a success message when the setup is complete.

8
We Are Developers 2025
Edit lib/config/api_tokens.dart with your credentials:
static const String githubModelsToken = "your_token_here";
static const String spotifyClientId = "your_client_id";

9
We Are Developers 2025
Run the app in web mode for the best workshop experience:
flutter run -d web-serverThe app will open in your default browser at localhost:8080
💡 You can also test the app using the iOS emulator if you have it installed:
flutter run -d ios
10
We Are Developers 2025
In this phase, we'll connect to GitHub and analyze commit patterns to detect the developer's coding "vibe".
Securely connect to GitHub and fetch commit history
Extract and analyze commit messages for sentiment
Map commit patterns to Eurovision song categories
11
We Are Developers 2025
lib/main.dart - Basic UI structure and GitHub integration skeletonlib/models/commit.dart - Commit data structurelib/config/api_tokens.dart - API configuration templatelib/services/github_service.dart - GitHub API wrapper with error handlinglib/sentiment_analyzer.dart - Eurovision mood detection logic
12
We Are Developers 2025
Enter valid and invalid GitHub usernames in the app. Success criteria: API returns 200 status code, correctly displays commit list, and handles 404 errors gracefully.
Open lib/sentiment_analyzer.dart to review keyword → Eurovision vibe mapping and understand the detectVibe() method.
Implement comprehensive error handling with specific error types: RateLimitException, UserNotFoundException, and NetworkException in the GitHub service.
Verify that error handling works by testing with invalid usernames and simulating rate limit errors. Success criteria: User sees friendly messages for all error scenarios.

13
We Are Developers 2025
// Excerpt from sentiment_analyzer.dart // Analyze commit messages and return the detected vibe static String detectVibe(List commitMessages) { if (commitMessages.isEmpty) { return 'Productive'; // Default vibe } // This map defines the keywords for each vibe const Map> vibeKeywords = { 'Productive': ['add', 'implement', 'feature', 'improve', 'optimize', 'refactor'], 'Intense': ['fix', 'bug', 'issue', 'error', 'crash', 'hotfix'], 'Creative': ['design', 'style', 'ui', 'ux', 'animation', 'visual'], // ... and so on for other vibes }; // Count occurrences of keywords for each vibe Map vibeCounts = {}; for (String vibe in vibeKeywords.keys) { vibeCounts[vibe] = 0; } for (String message in commitMessages) { String lowerMessage = message.toLowerCase(); for (String vibe in vibeKeywords.keys) { for (String keyword in vibeKeywords[vibe]!) { if (lowerMessage.contains(keyword.toLowerCase())) { vibeCounts[vibe] = (vibeCounts[vibe] ?? 0) + 1; } } } }
// Excerpt from sentiment_analyzer.dart // Analyze commit messages and return the detected vibe static String detectVibe(List<String> commitMessages) { if (commitMessages.isEmpty) { return 'Productive'; // Default vibe } // This map defines the keywords for each vibe const Map<String, List<String>> vibeKeywords = { 'Productive': ['add', 'implement', 'feature', 'improve', 'optimize', 'refactor'], 'Intense': ['fix', 'bug', 'issue', 'error', 'crash', 'hotfix'], 'Creative': ['design', 'style', 'ui', 'ux', 'animation', 'visual'], // ... and so on for other vibes }; // Count occurrences of keywords for each vibe Map<String, int> vibeCounts = {}; for (String vibe in vibeKeywords.keys) { vibeCounts[vibe] = 0; } for (String message in commitMessages) { String lowerMessage = message.toLowerCase(); for (String vibe in vibeKeywords.keys) { for (String keyword in vibeKeywords[vibe]!) { if (lowerMessage.contains(keyword.toLowerCase())) { vibeCounts[vibe] = (vibeCounts[vibe] ?? 0) + 1; } } } }

14
We Are Developers 2025
In this phase, we'll use AI to intelligently match GitHub commit patterns with Eurovision songs.
Connect to AI services to analyze commit patterns
Craft specialized prompts with Eurovision context
Extract structured song recommendations from AI responses
Ensure recommendations even when AI services fail

15
We Are Developers 2025
Let's explore how we'll implement AI in our Eurovision playlist generator:
We're using GPT-4.1 via GitHub Models with the endpoint: https://models.github.ai/inference
Authentication is handled through your GitHub token.
Our strategy includes providing context (relevant commit history and patterns), defining the task (requesting Eurovision song matches based on vibe), and specifying format (JSON response with song, artist, year).
We'll parse the AI's JSON responses to extract structured song recommendations that match the development vibe detected from your commits.

16
We Are Developers 2025

17
We Are Developers 2025
String _buildEurovisionPrompt(SentimentResult sentiment) {
return '''
Based on coding mood: "${sentiment.mood}" (${sentiment.confidence} confidence)
Suggest 5 Eurovision songs matching this developer vibe:
- Different years and countries
- Match energy/theme to coding mood
- Include reasoning for each choice
JSON format: [{"title":"", "artist":"", "country":"", "year":2024, "reasoning":""}]
Commit keywords: ${sentiment.keywords.join(', ')}
''';
}
18
We Are Developers 2025
Future<String> _callGitHubModelsAPI(String prompt) async {
final response = await http.post(
Uri.parse('https://models.github.ai/inference/chat/completions'),
headers: {
'Authorization': 'Bearer ${ApiConfig.githubToken}',
'Content-Type': 'application/json',
},
body: jsonEncode({
'messages': [
{'role': 'system', 'content': 'Eurovision expert & music curator'},
{'role': 'user', 'content': prompt}
],
'model': 'openai/gpt-4.1',
'temperature': 0.7, // Balance creativity + consistency
}),
);
// ... error handling
}
19
We Are Developers 2025
// In ai_playlist_service.dart
List<EurovisionSong> _parseAIResponse(String response) {
try {
// Extract JSON from AI response (handles non-JSON text)
final jsonMatch = RegExp(r'\[[\s\S]*\]').firstMatch(response);
if (jsonMatch == null) {
throw FormatException('No JSON array found in response');
}
final jsonString = jsonMatch.group(0);
final List songsList = jsonDecode(jsonString);
return songsList
.map((song) => EurovisionSong.fromJson(song))
.toList();
} catch (e) {
// Handle parsing errors gracefully
print('Error parsing AI response: $e');
return _getFallbackSongs();
}
}// In eurovision_song.dart
class EurovisionSong {
final String title;
final String artist;
final String country;
final int year;
final String reasoning;
// Constructor and validation
EurovisionSong({
required this.title,
required this.artist,
required this.country,
required this.year,
required this.reasoning,
}) : assert(year >= 1956 && year <= 2025);
// JSON parsing methods
factory EurovisionSong.fromJson(Map json) {...}
}
20
We Are Developers 2025
In this phase, we'll connect to Spotify to make our Eurovision recommendations playable.
Implement secure Spotify authentication flow
Find Eurovision songs on Spotify with fallback strategies
Create an interactive playlist with play controls
Handle missing tracks and API limitations

21
We Are Developers 2025
// Primary search with Eurovision context
String query = "${song.title} ${song.artist} eurovision";
var results = await spotify.searchTracks(query);
// First fallback: without Eurovision context
if (results.isEmpty) {
query = "${song.title} ${song.artist}";
results = await spotify.searchTracks(query);
}
// Second fallback: title only
if (results.isEmpty) {
query = "${song.title}";
results = await spotify.searchTracks(query);
}
// Handle not found
if (results.isEmpty) {
return EurovisionTrack.notFound(song);
}

22
We Are Developers 2025
In this phase, we'll add features to share Eurovision coding playlists on social media.
Pick one!
Platform-specific implementation for Twitter, Instagram, and LinkedIn
Monitor user engagement and sharing patterns
Visually appealing playlist cards with Eurovision branding
Text-based sharing and clipboard functionality

23
We Are Developers 2025
In this final phase, we'll add production-quality features and optimizations.
Implement user-friendly error messages for all API failures and edge cases
Add progress indicators and skeleton screens for better user experience
Implement caching and request batching to improve app responsiveness
Add final visual touches and animations for a professional look and feel

24
We Are Developers 2025
try {
commits = await githubService.fetchCommits(username);
} catch (e) {
if (e is RateLimitException) {
showRateLimitDialog();
} else if (e is UserNotFoundException) {
showUserNotFoundMessage();
} else {
showGenericErrorMessage();
}
}
try {
playlist = await aiService.generatePlaylist(commits);
} catch (e) {
// Fallback to rule-based recommendations
playlist = sentimentAnalyzer
.getRecommendations(commits);
// Track failure for analytics
analytics.trackEvent('ai_failure', {
'error_type': e.toString(),
'fallback_used': true
});
}

25
We Are Developers 2025
Built a production-ready application with multiple API integrations
GitHub, AI Models, and Spotify working together seamlessly
All Eurovision participating nations throughout history
Completed all development phases from integration to production polish

26
We Are Developers 2025
Share your Eurovision coding playlists with #githubcommunity
"Every great developer has their soundtrack. Today you discovered yours is Eurovision! 🇪🇺"
GitVision Workshop: Transforming GitHub Commits into Eurovision Playlists