ModelHubManager / components /version_control.py
S-Dreamer's picture
Upload 31 files
74dd3f1 verified
import streamlit as st
import pandas as pd
from datetime import datetime
import difflib
import json
def fetch_model_versions(repo_id):
"""
Fetch model versions from the Hugging Face API.
In a real implementation, this would call the HF API to get version history.
For now, we'll use demo data.
"""
# In a production app, you would fetch this from the Hugging Face API
# For demo purposes, create some sample version data
versions = [
{
"version": "v1.0",
"commit_id": "abc123",
"timestamp": "2023-01-15T10:30:00Z",
"author": st.session_state.username,
"message": "Initial model release",
"files_changed": 5,
"performance": {"accuracy": 0.85, "f1": 0.82}
},
{
"version": "v1.1",
"commit_id": "def456",
"timestamp": "2023-02-20T14:45:00Z",
"author": st.session_state.username,
"message": "Improved tokenization",
"files_changed": 2,
"performance": {"accuracy": 0.87, "f1": 0.84}
},
{
"version": "v2.0",
"commit_id": "ghi789",
"timestamp": "2023-03-10T09:15:00Z",
"author": st.session_state.username,
"message": "Major model architecture upgrade",
"files_changed": 12,
"performance": {"accuracy": 0.92, "f1": 0.90}
}
]
return versions
def render_version_history(model_info):
"""Render the version history of a model"""
if not model_info:
st.error("Model information not found")
return
repo_id = model_info.modelId
st.subheader("πŸ”„ Version History")
with st.spinner("Loading version history..."):
versions = fetch_model_versions(repo_id)
if not versions:
st.info("No version history found for this model.")
return
# Convert to DataFrame for easier display
df = pd.DataFrame(versions)
# Format timestamp
df["timestamp"] = pd.to_datetime(df["timestamp"]).dt.strftime("%Y-%m-%d %H:%M")
# Create a cleaner display version
display_df = df[["version", "timestamp", "author", "message", "files_changed"]]
display_df.columns = ["Version", "Date", "Author", "Commit Message", "Files Changed"]
# Show the version history
st.dataframe(display_df, use_container_width=True)
# Version comparison
st.subheader("Compare Versions")
col1, col2 = st.columns(2)
with col1:
base_version = st.selectbox(
"Base Version",
options=df["version"].tolist(),
index=0
)
with col2:
compare_version = st.selectbox(
"Compare Version",
options=[v for v in df["version"].tolist() if v != base_version],
index=0
)
if st.button("Compare", use_container_width=True):
with st.spinner("Generating comparison..."):
# In a real implementation, fetch the actual data from each version
# For demo, use the sample performance metrics
base_data = df[df["version"] == base_version].iloc[0]
compare_data = df[df["version"] == compare_version].iloc[0]
# Display comparison
col1, col2 = st.columns(2)
with col1:
st.markdown(f"### {base_version}")
st.markdown(f"**Commit:** {base_data['commit_id']}")
st.markdown(f"**Date:** {base_data['timestamp']}")
st.markdown(f"**Author:** {base_data['author']}")
st.markdown(f"**Message:** {base_data['message']}")
# Performance metrics
st.markdown("#### Performance Metrics")
for metric, value in base_data["performance"].items():
st.markdown(f"**{metric.capitalize()}:** {value:.4f}")
with col2:
st.markdown(f"### {compare_version}")
st.markdown(f"**Commit:** {compare_data['commit_id']}")
st.markdown(f"**Date:** {compare_data['timestamp']}")
st.markdown(f"**Author:** {compare_data['author']}")
st.markdown(f"**Message:** {compare_data['message']}")
# Performance metrics
st.markdown("#### Performance Metrics")
for metric, value in compare_data["performance"].items():
# Calculate change
base_value = base_data["performance"].get(metric, 0)
change = value - base_value
change_pct = (change / base_value * 100) if base_value != 0 else float('inf')
# Display with change indicator
if change > 0:
st.markdown(f"**{metric.capitalize()}:** {value:.4f} πŸ“ˆ **(+{change:.4f}, {change_pct:.2f}%)**")
elif change < 0:
st.markdown(f"**{metric.capitalize()}:** {value:.4f} πŸ“‰ **({change:.4f}, {change_pct:.2f}%)**")
else:
st.markdown(f"**{metric.capitalize()}:** {value:.4f} (no change)")
# Show visual diff of model config
st.subheader("Configuration Changes")
# Sample configs (in a real app, you'd fetch these from the API)
base_config = {
"hidden_size": 768,
"num_attention_heads": 12,
"num_hidden_layers": 6,
"vocab_size": 30000
}
compare_config = {
"hidden_size": 1024,
"num_attention_heads": 16,
"num_hidden_layers": 8,
"vocab_size": 30000
}
# Generate a formatted diff
base_str = json.dumps(base_config, indent=2).splitlines()
compare_str = json.dumps(compare_config, indent=2).splitlines()
diff = difflib.unified_diff(
base_str,
compare_str,
fromfile=f'config_{base_version}',
tofile=f'config_{compare_version}',
lineterm=''
)
diff_html = []
for line in diff:
if line.startswith('+'):
diff_html.append(f'<span style="color: green">{line}</span>')
elif line.startswith('-'):
diff_html.append(f'<span style="color: red">{line}</span>')
elif line.startswith('@@'):
diff_html.append(f'<span style="color: purple">{line}</span>')
else:
diff_html.append(line)
st.markdown('<div style="background-color: #f5f5f5; padding: 10px; border-radius: 5px; font-family: monospace; white-space: pre-wrap;">' + '<br>'.join(diff_html) + '</div>', unsafe_allow_html=True)
# Rollback functionality
st.subheader("Rollback to Previous Version")
rollback_version = st.selectbox(
"Select version to rollback to",
options=df["version"].tolist(),
index=len(df)-2 # Default to second-to-last version
)
if st.button("Rollback", use_container_width=True, type="primary"):
with st.spinner("Rolling back to version " + rollback_version):
# In a real implementation, this would call the HF API to perform the rollback
st.success(f"Successfully rolled back to {rollback_version}")
# Here you would update the model information and refresh the view