8 const user2 = url.searchParams.get("user2") || "stevekrouse";
9
10 async function fetchUserActivity(username: string) {
11 const threeMonthsAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString();
12 const response = await fetch(
13 `https://api.github.com/users/${username}/events?per_page=100&since=${threeMonthsAgo}`,
14 );
50 try {
51 const [user1Data, user2Data] = await Promise.all([
52 fetchUserActivity(user1),
53 fetchUserActivity(user2),
54 ]);
55
5## Features
6
7- Fetches the last 3 months of GitHub activity for two users
8- Summarizes activity including event counts, repositories, commits, issues, and pull requests
9- Uses AI to generate collaboration suggestions based on the activity summaries
1// This approach fetches GitHub activity for two users specified in the URL,
2// sends it to OpenAI for analysis, and returns collaboration suggestions.
3// It uses the GitHub API (which doesn't require authentication for public data)
4// and the OpenAI API (which does require an API key).
5// Tradeoff: We're using an inline API key for simplicity, which isn't ideal for security.
6// Note: This might hit rate limits for the GitHub API due to fetching a year of data.
7
8import { OpenAI } from "https://esm.town/v/std/openai";
15 const user2 = url.searchParams.get('user2') || 'octocat';
16
17 async function fetchUserActivity(username: string) {
18 const oneYearAgo = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString();
19 const response = await fetch(`https://api.github.com/users/${username}/events?per_page=100&since=${oneYearAgo}`);
20 const data = await response.json();
21 if (!Array.isArray(data)) {
27 try {
28 const [user1Data, user2Data] = await Promise.all([
29 fetchUserActivity(user1),
30 fetchUserActivity(user2)
31 ]);
32
39 event.payload.commits.forEach((commit: any) => {
40 if (commit.url) {
41 // This is a simplification. Ideally, we'd fetch each commit to get language info
42 languageSet.add("Unknown");
43 }
1# GitHub Activity Summarizer
2
3This val.town script fetches a user's recent GitHub activity and generates a summarized narrative overview using OpenAI's GPT model.
4
5## Features
1// This approach uses the GitHub API without authentication, which is subject to rate limiting.
2// We'll fetch and process the GitHub activity data, and render it as a nicely designed website
3// using Vue for templating and Tailwind for styling.
4// Tradeoff: May hit rate limits, but doesn't require setting up a personal access token.
8const GITHUB_USERNAME = "ejfox";
9
10async function fetchGitHubEvents(username: string) {
11 const response = await fetch(`https://api.github.com/users/${username}/events/public`, {
12 headers: {
13 "User-Agent": "Val-Town-Script",
90export default async function main(req: Request): Promise<Response> {
91 try {
92 const events = await fetchGitHubEvents(GITHUB_USERNAME);
93 const recentActivity = processEvents(events);
94
7
8export const resumeConfig = {
9 // URL to fetch the resume JSON data. This should point to your raw resume JSON.
10 // If you want to host your resume JSON somewhere I recommend a setup like this on val town (https://www.val.town/v/iamseeley/resumeDetails) or a github gist.
11 // You can test out the resume view using my resume: https://iamseeley-resumedetails.web.val.run
111
112 async function deleteEntry(index) {
113 const response = await fetch('/log', {
114 method: 'DELETE',
115 headers: { 'Content-Type': 'application/json' },
123 async function clearAll() {
124 if (confirm('Are you sure you want to delete all entries?')) {
125 const response = await fetch('/log', { method: 'DELETE' });
126 if (response.ok) {
127 window.location.reload();
35
36async function execute(statement: InStatement): Promise<ResultSet> {
37 const res = await fetch(`${API_URL}/v1/sqlite/execute`, {
38 method: "POST",
39 headers: {
49
50async function batch(statements: InStatement[], mode?: TransactionMode): Promise<ResultSet[]> {
51 const res = await fetch(`${API_URL}/v1/sqlite/batch`, {
52 method: "POST",
53 headers: {
1import { email } from "https://esm.town/v/std/email?v=9";
2import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
3import { nominatimSearch } from "https://esm.town/v/stevekrouse/nominatimSearch";
4import { weatherGovGrid } from "https://esm.town/v/stevekrouse/weatherGovGrid";
14 lon,
15 });
16 let { properties: { periods } } = await fetchJSON(
17 grid.forecastHourly,
18 );
16 try {
17 if (resumeJsonUrl) {
18 const response = await fetch(resumeJsonUrl);
19 if (!response.ok) {
20 throw new Error(`Failed to fetch resume details from URL: ${response.statusText}`);
21 }
22 resumeDetails = await response.json();
23 }
24 } catch (error) {
25 console.error(`Error fetching resume data: ${error.message}`);
26 }
27