|
| 1 | +import streamlit as st |
| 2 | +import requests |
| 3 | +from datetime import datetime |
| 4 | +import pandas as pd |
| 5 | + |
| 6 | +# GitHub repository URL |
| 7 | +REPO_URL = "https://api.github.com/repos/recodehive/Scrape-ML" |
| 8 | + |
| 9 | + |
| 10 | +# Function to fetch repository statistics |
| 11 | +def fetch_repo_statistics(): |
| 12 | + closed_pr_count = fetch_closed_pr_count() |
| 13 | + return { |
| 14 | + "total_prs": closed_pr_count, |
| 15 | + "total_projects": fetch_total_projects(), |
| 16 | + "total_contributors": fetch_contributors_count(), |
| 17 | + } |
| 18 | + |
| 19 | + |
| 20 | +# Existing fetch functions remain the same |
| 21 | +def fetch_closed_pr_count(): |
| 22 | + closed_prs_url = f"{REPO_URL}/pulls?state=closed" |
| 23 | + closed_pr_count = 0 |
| 24 | + page = 1 |
| 25 | + while True: |
| 26 | + response = requests.get(f"{closed_prs_url}&page={page}") |
| 27 | + if response.status_code != 200 or not response.json(): |
| 28 | + break |
| 29 | + closed_pr_count += len(response.json()) |
| 30 | + page += 1 |
| 31 | + return closed_pr_count |
| 32 | + |
| 33 | + |
| 34 | +def fetch_total_projects(): |
| 35 | + return 0 |
| 36 | + |
| 37 | + |
| 38 | +def fetch_closed_prs(): |
| 39 | + closed_prs_url = f"{REPO_URL}/pulls?state=closed" |
| 40 | + closed_prs = [] |
| 41 | + page = 1 |
| 42 | + while True: |
| 43 | + response = requests.get(f"{closed_prs_url}&page={page}") |
| 44 | + if response.status_code != 200 or not response.json(): |
| 45 | + break |
| 46 | + pulls = response.json() |
| 47 | + for pr in pulls: |
| 48 | + if pr["merged_at"]: |
| 49 | + closed_prs.append( |
| 50 | + { |
| 51 | + "title": pr["title"], |
| 52 | + "url": pr["html_url"], |
| 53 | + "date": pr["merged_at"], |
| 54 | + "user": pr["user"]["login"], |
| 55 | + "avatar_url": pr["user"]["avatar_url"], |
| 56 | + } |
| 57 | + ) |
| 58 | + page += 1 |
| 59 | + return closed_prs |
| 60 | + |
| 61 | + |
| 62 | +def fetch_upcoming_issues(): |
| 63 | + issues_url = f"{REPO_URL}/issues?state=open" |
| 64 | + upcoming_issues = [] |
| 65 | + response = requests.get(issues_url) |
| 66 | + if response.status_code == 200: |
| 67 | + issues = response.json() |
| 68 | + for issue in issues: |
| 69 | + if issue.get("assignee"): |
| 70 | + upcoming_issues.append( |
| 71 | + { |
| 72 | + "title": issue["title"], |
| 73 | + "url": issue["html_url"], |
| 74 | + "date": issue["created_at"], |
| 75 | + "assignee": issue["assignee"]["login"], |
| 76 | + "avatar_url": issue["assignee"]["avatar_url"], |
| 77 | + } |
| 78 | + ) |
| 79 | + return upcoming_issues |
| 80 | + |
| 81 | + |
| 82 | +def fetch_contributors_count(): |
| 83 | + contributors_url = f"{REPO_URL}/contributors" |
| 84 | + response = requests.get(contributors_url) |
| 85 | + if response.status_code == 200: |
| 86 | + return len(response.json()) |
| 87 | + return 0 |
| 88 | + |
| 89 | + |
| 90 | +# Custom CSS for modern design |
| 91 | +st.set_page_config( |
| 92 | + page_title="Changelog - Scrape ML", |
| 93 | + page_icon="📝", |
| 94 | + layout="wide", |
| 95 | + initial_sidebar_state="expanded", |
| 96 | +) |
| 97 | + |
| 98 | +# Custom CSS |
| 99 | +st.markdown( |
| 100 | + """ |
| 101 | +<style> |
| 102 | + /* Modern card design */ |
| 103 | + .css-1r6slb0 { |
| 104 | + background-color: #ffffff; |
| 105 | + border-radius: 10px; |
| 106 | + padding: 20px; |
| 107 | + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| 108 | + } |
| 109 | + |
| 110 | + /* Timeline design */ |
| 111 | + .timeline-item { |
| 112 | + position: relative; |
| 113 | + padding: 20px; |
| 114 | + margin: 20px 0; |
| 115 | + background: white; |
| 116 | + border-radius: 10px; |
| 117 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| 118 | + color: black; |
| 119 | + } |
| 120 | + |
| 121 | + .timeline-item::before { |
| 122 | + content: ''; |
| 123 | + position: absolute; |
| 124 | + left: -8px; |
| 125 | + top: 50%; |
| 126 | + width: 16px; |
| 127 | + height: 16px; |
| 128 | + background: #6c5ce7; |
| 129 | + border-radius: 50%; |
| 130 | + transform: translateY(-50%); |
| 131 | + } |
| 132 | + |
| 133 | + /* Stats cards */ |
| 134 | + .stat-card { |
| 135 | + background: white; |
| 136 | + padding: 20px; |
| 137 | + border-radius: 10px; |
| 138 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| 139 | + text-align: center; |
| 140 | + } |
| 141 | + |
| 142 | + .stat-number { |
| 143 | + font-size: 2.5em; |
| 144 | + font-weight: bold; |
| 145 | + color: #6c5ce7; |
| 146 | + } |
| 147 | + |
| 148 | + .stat-label { |
| 149 | + color: #666; |
| 150 | + font-size: 1.1em; |
| 151 | + } |
| 152 | + |
| 153 | + /* Avatar style */ |
| 154 | + .avatar-small { |
| 155 | + border-radius: 50%; |
| 156 | + width: 30px; |
| 157 | + height: 30px; |
| 158 | + margin-right: 10px; |
| 159 | + vertical-align: middle; |
| 160 | + } |
| 161 | + |
| 162 | + /* Progress bar */ |
| 163 | + .stProgress > div > div > div > div { |
| 164 | + background-color: #6c5ce7; |
| 165 | + } |
| 166 | +</style> |
| 167 | +""", |
| 168 | + unsafe_allow_html=True, |
| 169 | +) |
| 170 | + |
| 171 | +# Title with gradient |
| 172 | +st.markdown( |
| 173 | + """ |
| 174 | + <h1 style='text-align: center; background: linear-gradient(45deg, #6c5ce7, #a8c0ff); |
| 175 | + -webkit-background-clip: text; -webkit-text-fill-color: transparent; |
| 176 | + margin-bottom: 30px;'> |
| 177 | + Scrape ML Changelog 📝 |
| 178 | + </h1> |
| 179 | +""", |
| 180 | + unsafe_allow_html=True, |
| 181 | +) |
| 182 | + |
| 183 | +# Fetch data |
| 184 | +repo_stats = fetch_repo_statistics() |
| 185 | +closed_prs = fetch_closed_prs() |
| 186 | +upcoming_issues = fetch_upcoming_issues() |
| 187 | + |
| 188 | +# Stats dashboard |
| 189 | +st.markdown("### Project Statistics") |
| 190 | +cols = st.columns(4) |
| 191 | + |
| 192 | +with cols[0]: |
| 193 | + st.markdown( |
| 194 | + """ |
| 195 | + <div class='stat-card'> |
| 196 | + <div class='stat-number'>{}</div> |
| 197 | + <div class='stat-label'>PRs Merged</div> |
| 198 | + </div> |
| 199 | + """.format( |
| 200 | + repo_stats["total_prs"] |
| 201 | + ), |
| 202 | + unsafe_allow_html=True, |
| 203 | + ) |
| 204 | + |
| 205 | +with cols[1]: |
| 206 | + st.markdown( |
| 207 | + """ |
| 208 | + <div class='stat-card'> |
| 209 | + <div class='stat-number'>{}</div> |
| 210 | + <div class='stat-label'>Contributors</div> |
| 211 | + </div> |
| 212 | + """.format( |
| 213 | + repo_stats["total_contributors"] |
| 214 | + ), |
| 215 | + unsafe_allow_html=True, |
| 216 | + ) |
| 217 | + |
| 218 | +# Timeline section |
| 219 | +st.markdown("### Recent Activity Timeline") |
| 220 | + |
| 221 | +for pr in closed_prs[:5]: # Show only last 5 PRs |
| 222 | + date = datetime.strptime(pr["date"], "%Y-%m-%dT%H:%M:%SZ").strftime("%B %d, %Y") |
| 223 | + st.markdown( |
| 224 | + f""" |
| 225 | + <div class='timeline-item'> |
| 226 | + <img src='{pr['avatar_url']}' class='avatar-small'> |
| 227 | + <strong>{pr['user']}</strong> merged PR: |
| 228 | + <a href='{pr['url']}' target='_blank'>{pr['title']}</a> |
| 229 | + <div style='color: #666; font-size: 0.9em; margin-top: 5px;'>{date}</div> |
| 230 | + </div> |
| 231 | + """, |
| 232 | + unsafe_allow_html=True, |
| 233 | + ) |
| 234 | + |
| 235 | +# Upcoming Features |
| 236 | +st.markdown("### 🚀 Upcoming Features") |
| 237 | +cols = st.columns(3) |
| 238 | + |
| 239 | +upcoming_features = [ |
| 240 | + { |
| 241 | + "title": "Personalized Watchlist", |
| 242 | + "progress": 75, |
| 243 | + "desc": "Implementation of user preferences-based watchlist", |
| 244 | + }, |
| 245 | + { |
| 246 | + "title": "External DB Integration", |
| 247 | + "progress": 45, |
| 248 | + "desc": "Integration with external movie databases", |
| 249 | + }, |
| 250 | + { |
| 251 | + "title": "Advanced Filtering", |
| 252 | + "progress": 30, |
| 253 | + "desc": "Enhanced search and filter capabilities", |
| 254 | + }, |
| 255 | +] |
| 256 | + |
| 257 | +for idx, feature in enumerate(upcoming_features): |
| 258 | + with cols[idx]: |
| 259 | + st.markdown( |
| 260 | + f""" |
| 261 | + <div style='background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);'> |
| 262 | + <h4>{feature['title']}</h4> |
| 263 | + <p style='color: black; font-size: 0.9em;'>{feature['desc']}</p> |
| 264 | + </div> |
| 265 | + """, |
| 266 | + unsafe_allow_html=True, |
| 267 | + ) |
| 268 | + st.progress(feature["progress"] / 100) |
| 269 | + |
| 270 | +# Footer |
| 271 | +st.markdown("---") |
| 272 | +st.markdown( |
| 273 | + """ |
| 274 | + <div style='text-align: center; padding: 20px;'> |
| 275 | + <h3 style='color: #6c5ce7;'>About Scrape ML</h3> |
| 276 | + <p>Scrape ML is a robust web scraping tool designed to simplify the extraction of data from various online sources. |
| 277 | + With its user-friendly interface and powerful features, Scrape ML allows users to collect, organize, |
| 278 | + and analyze data seamlessly. Ideal for developers, data scientists, and anyone interested in leveraging |
| 279 | + web data for their projects.</p> |
| 280 | + <p style='color: #666; margin-top: 20px;'>Made with 💜 by the Scrape ML Team</p> |
| 281 | + </div> |
| 282 | +""", |
| 283 | + unsafe_allow_html=True, |
| 284 | +) |
0 commit comments