import gradio as gr
import json
import os
from datetime import datetime
from typing import Dict, List, Optional, Union
from dataclasses import dataclass
from pathlib import Path
# Type definitions and data structures
@dataclass
class AIModel:
name: str
description: str
date_of_release: str
developer: str
use_case: str
impact: str
time_difference: Optional[int] = None
def to_dict(self) -> Dict:
return {
"name": self.name,
"description": self.description,
"dateOfRelease": self.date_of_release,
"developer": self.developer,
"use_case": self.use_case,
"impact": self.impact,
"time_difference": self.time_difference
}
@classmethod
def from_dict(cls, data: Dict) -> 'AIModel':
return cls(
name=data.get('name', ''),
description=data.get('description', ''),
date_of_release=data.get('dateOfRelease', ''),
developer=data.get('developer', ''),
use_case=data.get('use_case', ''),
impact=data.get('impact', ''),
time_difference=data.get('time_difference')
)
class ModelRepository:
def __init__(self, file_path: str = "models.json"):
self.file_path = Path(file_path)
self.models: List[AIModel] = []
self.load_models()
def load_models(self) -> None:
if self.file_path.exists():
try:
with open(self.file_path, "r") as f:
data = json.load(f)
self.models = [AIModel.from_dict(model_data) for model_data in data]
except json.JSONDecodeError:
print(f"Error reading {self.file_path}. Starting with empty model list.")
self.models = []
else:
self.models = []
def save_models(self) -> None:
with open(self.file_path, "w") as f:
json.dump([model.to_dict() for model in self.models], f, indent=4)
def add_model(self, model: AIModel) -> None:
self.models.append(model)
self.calculate_time_differences()
self.save_models()
def update_model(self, index: int, model: AIModel) -> bool:
if 0 <= index < len(self.models):
self.models[index] = model
self.calculate_time_differences()
self.save_models()
return True
return False
def get_filtered_models(
self,
developer: Optional[str] = None,
use_case: Optional[str] = None
) -> List[AIModel]:
filtered_models = self.models.copy()
if developer and developer != "All":
filtered_models = [m for m in filtered_models if m.developer == developer]
if use_case and use_case != "All":
filtered_models = [m for m in filtered_models if m.use_case == use_case]
return sorted(filtered_models, key=lambda x: x.date_of_release, reverse=True)
def calculate_time_differences(self) -> None:
# Sort by date in ascending order
sorted_models = sorted(self.models, key=lambda x: x.date_of_release)
# Reset all time differences
for model in sorted_models:
model.time_difference = None
# Calculate time differences starting from the most recent
for i in range(len(sorted_models)-1, 0, -1):
curr_date = datetime.strptime(sorted_models[i].date_of_release, "%Y-%m-%d")
prev_date = datetime.strptime(sorted_models[i-1].date_of_release, "%Y-%m-%d")
sorted_models[i].time_difference = (curr_date - prev_date).days
def get_unique_developers(self) -> List[str]:
return sorted(list(set(model.developer for model in self.models)))
def get_unique_use_cases(self) -> List[str]:
return sorted(list(set(model.use_case for model in self.models)))
class UIRenderer:
@staticmethod
def render_model_card(model: AIModel) -> str:
return f"""
{model.name} ({model.date_of_release})
Description: {model.description}
Developer: {model.developer}
Use Case: {model.use_case}
Impact: {model.impact}
"""
@staticmethod
def render_time_difference(days: int) -> str:
if days <= 0:
return ""
gap_height = days * 2 # Scale the gap based on days
return f"""
{days} days between releases
"""
@staticmethod
def render_timeline(models: List[AIModel]) -> str:
output = ""
for model in models: # models are already sorted in reverse order
if model.time_difference: # Check if there's a time difference
output += UIRenderer.render_time_difference(model.time_difference)
output += UIRenderer.render_model_card(model)
output += "
"
return output
def create_ui(repository: ModelRepository) -> gr.Blocks:
css = """
body {
font-family: 'Arial', sans-serif;
background-color: #121212;
color: white;
margin: 0;
padding: 0;
}
.timeline-container {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1rem;
}
.ai-card {
background: linear-gradient(145deg, #2b2b2b, #333);
border-radius: 1rem;
padding: 1.5rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.ai-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
}
.ai-card h3 {
color: #60a5fa;
margin: 0 0 1rem 0;
font-size: 1.25rem;
}
.ai-card p {
color: #e5e7eb;
margin: 0.5rem 0;
line-height: 1.5;
}
.ai-card strong {
color: #93c5fd;
}
.gradio-container {
width: 80%;
margin: auto;
padding: 20px;
}
.gradio-markdown {
color: white;
}
.gr-button {
background-color: #333;
color: white;
}
.gr-button:hover {
background-color: #555;
}
.gr-dropdown, .gr-textbox {
background-color: #333;
color: white;
border: 1px solid #555;
}
.time-difference {
text-align: center;
color: #9ca3af;
font-style: italic;
position: relative;
padding: 20px 0;
}
.time-line {
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: 2px;
background: linear-gradient(to bottom, transparent, #555, transparent);
}
.time-text {
background-color: #1a1a1a;
padding: 5px 15px;
border-radius: 15px;
display: inline-block;
position: relative;
z-index: 1;
}
"""
with gr.Blocks(css=css) as app:
gr.Markdown("# AI Timeline\n\nVisualize the development of AI models through an interactive timeline.")
with gr.Tab("View Timeline"):
with gr.Row():
developer_filter = gr.Dropdown(
label="Filter by Developer",
choices=["All"] + repository.get_unique_developers(),
value="All"
)
use_case_filter = gr.Dropdown(
label="Filter by Use Case",
choices=["All"] + repository.get_unique_use_cases(),
value="All"
)
filter_button = gr.Button("Apply Filters", variant="primary")
timeline_output = gr.HTML()
def update_timeline(developer: str, use_case: str) -> str:
filtered_models = repository.get_filtered_models(developer, use_case)
return UIRenderer.render_timeline(filtered_models)
filter_button.click(
update_timeline,
inputs=[developer_filter, use_case_filter],
outputs=[timeline_output]
)
with gr.Tab("Add Model"):
with gr.Row():
name_input = gr.Textbox(label="Model Name", placeholder="Enter model name")
date_input = gr.Textbox(label="Release Date (YYYY-MM-DD)", placeholder="Enter date of release")
description_input = gr.Textbox(label="Description", placeholder="Enter a short description", lines=3)
with gr.Row():
developer_input = gr.Textbox(label="Developer", placeholder="Enter the developer or organization")
use_case_input = gr.Textbox(label="Use Case", placeholder="Enter the primary use case")
impact_input = gr.Textbox(label="Impact", placeholder="Enter the model's impact", lines=2)
add_button = gr.Button("Add Model", variant="primary")
add_output = gr.Markdown()
def add_new_model(name, description, date, developer, use_case, impact):
try:
datetime.strptime(date, "%Y-%m-%d")
model = AIModel(
name=name,
description=description,
date_of_release=date,
developer=developer,
use_case=use_case,
impact=impact
)
repository.add_model(model)
return "Model added successfully!", UIRenderer.render_timeline(repository.get_filtered_models())
except ValueError:
return "Error: Invalid date format. Please use YYYY-MM-DD", ""
add_button.click(
add_new_model,
inputs=[name_input, description_input, date_input,
developer_input, use_case_input, impact_input],
outputs=[add_output, timeline_output]
)
with gr.Tab("Edit Model"):
edit_index = gr.Number(label="Model Number", precision=0)
with gr.Row():
edit_name = gr.Textbox(label="New Model Name", placeholder="Enter new model name")
edit_date = gr.Textbox(label="New Release Date", placeholder="Enter new date (YYYY-MM-DD)")
edit_description = gr.Textbox(label="New Description", placeholder="Enter new description", lines=3)
with gr.Row():
edit_developer = gr.Textbox(label="New Developer", placeholder="Enter new developer")
edit_use_case = gr.Textbox(label="New Use Case", placeholder="Enter new use case")
edit_impact = gr.Textbox(label="New Impact", placeholder="Enter new impact", lines=2)
edit_button = gr.Button("Edit Model", variant="primary")
edit_output = gr.Markdown()
def edit_existing_model(index, name, description, date, developer, use_case, impact):
try:
datetime.strptime(date, "%Y-%m-%d")
model = AIModel(
name=name,
description=description,
date_of_release=date,
developer=developer,
use_case=use_case,
impact=impact
)
if repository.update_model(int(index) - 1, model):
return "Model updated successfully!", UIRenderer.render_timeline(repository.get_filtered_models())
return "Error: Invalid model number", ""
except ValueError:
return "Error: Invalid date format. Please use YYYY-MM-DD", ""
edit_button.click(
edit_existing_model,
inputs=[edit_index, edit_name, edit_description, edit_date,
edit_developer, edit_use_case, edit_impact],
outputs=[edit_output, timeline_output]
)
return app
if __name__ == "__main__":
repository = ModelRepository()
app = create_ui(repository)
app.launch()