anycoder-0f176898 / index.html
raphaelmansuy's picture
Upload folder using huggingface_hub
b0a0d50 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenRouter Models - Compare & Choose AI Models</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--success-gradient: linear-gradient(135deg, #13f1fc 0%, #0470dc 100%);
--openrouter-gradient: linear-gradient(135deg, #FF6B6B 0%, #4ECDC4 100%);
--card-bg: #ffffff;
--text-primary: #2d3748;
--text-secondary: #4a5568;
--border-color: #e2e8f0;
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: var(--text-primary);
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
pointer-events: none;
}
header {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
padding: 1.5rem 0;
box-shadow: var(--shadow-lg);
position: sticky;
top: 0;
z-index: 100;
animation: slideDown 0.5s ease-out;
}
@keyframes slideDown {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.logo-section {
display: flex;
align-items: center;
gap: 1rem;
}
.logo {
width: 45px;
height: 45px;
background: var(--openrouter-gradient);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5rem;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
h1 {
font-size: 1.8rem;
background: var(--openrouter-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header-actions {
display: flex;
align-items: center;
gap: 1.5rem;
}
.stats {
display: flex;
gap: 2rem;
align-items: center;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 1.5rem;
font-weight: bold;
background: var(--openrouter-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.stat-label {
font-size: 0.875rem;
color: var(--text-secondary);
}
.search-container {
position: relative;
max-width: 400px;
flex: 1;
}
.search-input {
width: 100%;
padding: 0.75rem 1rem 0.75rem 3rem;
border: 2px solid var(--border-color);
border-radius: 50px;
font-size: 1rem;
transition: var(--transition);
background: white;
}
.search-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.search-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
}
.filter-section {
max-width: 1400px;
margin: 2rem auto;
padding: 0 2rem;
display: flex;
gap: 1rem;
flex-wrap: wrap;
align-items: center;
}
.filter-chips {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
flex: 1;
}
.chip {
padding: 0.5rem 1.25rem;
background: white;
border: 2px solid var(--border-color);
border-radius: 25px;
cursor: pointer;
transition: var(--transition);
font-size: 0.9rem;
font-weight: 500;
position: relative;
overflow: hidden;
}
.chip::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: var(--openrouter-gradient);
transition: left 0.3s ease;
z-index: -1;
}
.chip:hover::before,
.chip.active::before {
left: 0;
}
.chip:hover,
.chip.active {
color: white;
border-color: transparent;
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.sort-dropdown {
padding: 0.5rem 1rem;
background: white;
border: 2px solid var(--border-color);
border-radius: 10px;
cursor: pointer;
font-size: 0.9rem;
transition: var(--transition);
}
.sort-dropdown:hover {
border-color: #667eea;
}
.cards-container {
max-width: 1400px;
margin: 2rem auto;
padding: 0 2rem 3rem;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 2rem;
animation: fadeIn 0.8s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.model-card {
background: white;
border-radius: 20px;
padding: 1.5rem;
box-shadow: var(--shadow-md);
transition: var(--transition);
position: relative;
overflow: hidden;
cursor: pointer;
animation: slideUp 0.5s ease-out backwards;
}
.model-card:nth-child(1) {
animation-delay: 0.1s;
}
.model-card:nth-child(2) {
animation-delay: 0.2s;
}
.model-card:nth-child(3) {
animation-delay: 0.3s;
}
.model-card:nth-child(4) {
animation-delay: 0.4s;
}
.model-card:nth-child(5) {
animation-delay: 0.5s;
}
.model-card:nth-child(6) {
animation-delay: 0.6s;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.model-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--openrouter-gradient);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.model-card:hover::before {
transform: scaleX(1);
}
.model-card:hover {
transform: translateY(-5px);
box-shadow: var(--shadow-xl);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1rem;
}
.model-info {
flex: 1;
}
.model-name {
font-size: 1.25rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.25rem;
}
.model-provider {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.75rem;
background: rgba(102, 126, 234, 0.1);
border-radius: 20px;
font-size: 0.875rem;
color: #667eea;
font-weight: 500;
}
.favorite-btn {
background: none;
border: none;
color: #cbd5e0;
font-size: 1.25rem;
cursor: pointer;
transition: var(--transition);
}
.favorite-btn:hover,
.favorite-btn.active {
color: #f56565;
transform: scale(1.2);
}
.model-description {
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.5;
margin-bottom: 1.5rem;
}
.pricing-section {
background: linear-gradient(135deg, #f6f8fb 0%, #f1f5f9 100%);
border-radius: 12px;
padding: 1rem;
margin-bottom: 1.5rem;
}
.price-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.price-row:last-child {
margin-bottom: 0;
}
.price-label {
font-size: 0.875rem;
color: var(--text-secondary);
}
.price-value {
font-weight: 600;
color: var(--text-primary);
}
.price-value.highlight {
font-size: 1.25rem;
background: var(--openrouter-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.specs-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1.5rem;
}
.spec-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.spec-icon {
width: 32px;
height: 32px;
background: rgba(102, 126, 234, 0.1);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: #667eea;
}
.spec-details {
flex: 1;
}
.spec-label {
font-size: 0.75rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.spec-value {
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
}
.card-footer {
display: flex;
gap: 0.75rem;
}
.btn {
flex: 1;
padding: 0.75rem;
border: none;
border-radius: 10px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
text-align: center;
text-decoration: none;
display: inline-block;
}
.btn-primary {
background: var(--openrouter-gradient);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background: white;
color: var(--text-primary);
border: 2px solid var(--border-color);
}
.btn-secondary:hover {
background: #f7fafc;
border-color: #667eea;
}
.floating-action {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 60px;
height: 60px;
background: var(--openrouter-gradient);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5rem;
cursor: pointer;
box-shadow: var(--shadow-xl);
transition: var(--transition);
z-index: 50;
}
.floating-action:hover {
transform: scale(1.1) rotate(90deg);
}
.badge {
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.25rem 0.75rem;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.anycoder-link {
color: #667eea;
text-decoration: none;
font-size: 0.875rem;
transition: var(--transition);
}
.anycoder-link:hover {
color: #764ba2;
text-decoration: underline;
}
@media (max-width: 768px) {
.header-content {
flex-direction: column;
text-align: center;
}
.stats {
order: 3;
width: 100%;
justify-content: space-around;
}
.search-container {
order: 2;
width: 100%;
}
.cards-container {
grid-template-columns: 1fr;
padding: 0 1rem 2rem;
}
.filter-section {
padding: 0 1rem;
}
}
.loading-skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.tooltip {
position: relative;
}
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
background: #2d3748;
color: white;
padding: 0.5rem 1rem;
border-radius: 8px;
font-size: 0.875rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.tooltip:hover::after {
opacity: 1;
}
</style>
</head>
<body>
<header>
<div class="header-content">
<div class="logo-section">
<div class="logo">
<i class="fas fa-route"></i>
</div>
<div>
<h1>OpenRouter Models</h1>
<p style="color: var(--text-secondary); font-size: 0.875rem;">
Compare and choose the best AI models |
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
Built with anycoder
</a>
</p>
</div>
</div>
<div class="header-actions">
<div class="stats">
<div class="stat-item">
<div class="stat-value" id="modelCount">24</div>
<div class="stat-label">Models</div>
</div>
<div class="stat-item">
<div class="stat-value" id="providerCount">12</div>
<div class="stat-label">Providers</div>
</div>
</div>
<div class="search-container">
<i class="fas fa-search search-icon"></i>
<input type="text" class="search-input" id="searchInput" placeholder="Search AI models...">
</div>
</div>
</div>
</header>
<div class="filter-section">
<div class="filter-chips">
<button class="chip active" data-filter="all">All Models</button>
<button class="chip" data-filter="text">Text Generation</button>
<button class="chip" data-filter="image">Image Generation</button>
<button class="chip" data-filter="code">Code Generation</button>
<button class="chip" data-filter="multimodal">Multimodal</button>
<button class="chip" data-filter="open-source">Open Source</button>
</div>
<select class="sort-dropdown" id="sortDropdown">
<option value="price-low">Price: Low to High</option>
<option value="price-high">Price: High to Low</option>
<option value="tokens">Max Tokens</option>
<option value="name">Name: A-Z</option>
</select>
</div>
<div class="cards-container" id="cardsContainer">
<!-- Cards will be generated here -->
</div>
<div class="floating-action tooltip" data-tooltip="Compare Models">
<i class="fas fa-balance-scale"></i>
</div>
<script>
const aiModels = [
{
id: 1,
name: "gpt-4-turbo-preview",
provider: "OpenAI",
description: "Latest GPT-4 Turbo model with improved instruction following and 128k context window.",
category: "text",
pricePerInput: "$0.01",
pricePerOutput: "$0.03",
maxTokens: "128k",
contextWindow: "128,000",
modelType: "Text Generation",
badge: "Popular",
isFavorite: false
},
{
id: 2,
name: "claude-3-opus",
provider: "Anthropic",
description: "Most powerful Claude model for complex tasks with 200k context window.",
category: "text",
pricePerInput: "$0.015",
pricePerOutput: "$0.075",
maxTokens: "200k",
contextWindow: "200,000",
modelType: "Text Generation",
badge: "Top Tier",
isFavorite: false
},
{
id: 3,
name: "gemini-pro",
provider: "Google",
description: "Google's multimodal model with 32k context, supporting text and images.",
category: "multimodal",
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Multimodal",
badge: "Value",
isFavorite: false
},
{
id: 4,
name: "dall-e-3",
provider: "OpenAI",
description: "State-of-the-art image generation model with photorealistic capabilities.",
category: "image",
pricePerInput: "$0.04",
pricePerOutput: "$0.08",
maxTokens: "N/A",
contextWindow: "N/A",
modelType: "Image Generation",
badge: "Premium",
isFavorite: false
},
{
id: 5,
name: "gpt-3.5-turbo",
provider: "OpenAI",
description: "Fast and efficient model optimized for chat completions and API usage.",
category: "text",
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "16k",
contextWindow: "16,000",
modelType: "Text Generation",
badge: null,
isFavorite: false
},
{
id: 6,
name: "claude-3-sonnet",
provider: "Anthropic",
description: "Balanced performance and speed, ideal for enterprise workloads.",
category: "text",
pricePerInput: "$0.003",
pricePerOutput: "$0.015",
maxTokens: "200k",
contextWindow: "200,000",
modelType: "Text Generation",
badge: null,
isFavorite: false
},
{
id: 7,
name: "codellama-70b-instruct",
provider: "Meta",
description: "Specialized model for code generation, debugging, and programming assistance.",
category: "code",
pricePerInput: "$0.0008",
pricePerOutput: "$0.0024",
maxTokens: "4k",
contextWindow: "4,000",
modelType: "Code Generation",
badge: "Developer",
isFavorite: false
},
{
id: 8,
name: "midjourney-v6",
provider: "Midjourney",
description: "Advanced AI art generator with stunning visual quality and style diversity.",
category: "image",
pricePerInput: "$0.03",
pricePerOutput: "$0.06",
maxTokens: "N/A",
contextWindow: "N/A",
modelType: "Image Generation",
badge: "Artist",
isFavorite: false
},
{
id: 9,
name: "llama-3-70b-instruct",
provider: "Meta",
description: "Open-source large language model with strong reasoning capabilities.",
category: ["text", "open-source"],
pricePerInput: "$0.0007",
pricePerOutput: "$0.0021",
maxTokens: "8k",
contextWindow: "8,000",
modelType: "Text Generation",
badge: "Open Source",
isFavorite: false
},
{
id: 10,
name: "stable-diffusion-xl",
provider: "Stability AI",
description: "High-quality image generation with fine-grained control and customization.",
category: ["image", "open-source"],
pricePerInput: "$0.02",
pricePerOutput: "$0.04",
maxTokens: "N/A",
contextWindow: "N/A",
modelType: "Image Generation",
badge: null,
isFavorite: false
},
{
id: 11,
name: "mistral-large",
provider: "Mistral AI",
description: "Flagship model with top-tier reasoning capabilities and multilingual support.",
category: "text",
pricePerInput: "$0.008",
pricePerOutput: "$0.024",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: "New",
isFavorite: false
},
{
id: 12,
name: "claude-3-haiku",
provider: "Anthropic",
description: "Fast and compact model for near-instant responsiveness.",
category: "text",
pricePerInput: "$0.00025",
pricePerOutput: "$0.00125",
maxTokens: "200k",
contextWindow: "200,000",
modelType: "Text Generation",
badge: "Fast",
isFavorite: false
},
{
id: 13,
name: "mistral-medium",
provider: "Mistral AI",
description: "Balanced performance model suitable for most use cases.",
category: "text",
pricePerInput: "$0.0027",
pricePerOutput: "$0.0081",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: null,
isFavorite: false
},
{
id: 14,
name: "mistral-small",
provider: "Mistral AI",
description: "Lightweight model for simple tasks and cost-effective operations.",
category: "text",
pricePerInput: "$0.0002",
pricePerOutput: "$0.0006",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: "Economy",
isFavorite: false
},
{
id: 15,
name: "gemma-7b-it",
provider: "Google",
description: "Lightweight, state-of-the-art open model from Google.",
category: ["text", "open-source"],
pricePerInput: "$0.0001",
pricePerOutput: "$0.0003",
maxTokens: "8k",
contextWindow: "8,000",
modelType: "Text Generation",
badge: "Open Source",
isFavorite: false
},
{
id: 16,
name: "command-r-plus",
provider: "Cohere",
description: "Enterprise-grade model with RAG capabilities and tool use.",
category: "text",
pricePerInput: "$0.003",
pricePerOutput: "$0.015",
maxTokens: "128k",
contextWindow: "128,000",
modelType: "Text Generation",
badge: "Enterprise",
isFavorite: false
},
{
id: 17,
name: "qwen-2-72b-instruct",
provider: "Alibaba",
description: "Powerful multilingual model with strong reasoning in 27 languages.",
category: ["text", "open-source"],
pricePerInput: "$0.0009",
pricePerOutput: "$0.0027",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: "Multilingual",
isFavorite: false
},
{
id: 18,
name: "deepseek-coder",
provider: "DeepSeek",
description: "Specialized coding model with 16k context for complex programming tasks.",
category: ["code", "open-source"],
pricePerInput: "$0.00014",
pricePerOutput: "$0.00028",
maxTokens: "16k",
contextWindow: "16,000",
modelType: "Code Generation",
badge: "Open Source",
isFavorite: false
},
{
id: 19,
name: "nous-hermes-2-mixtral-8x7b-dpo",
provider: "Nous Research",
description: "Fine-tuned Mixtral model with DPO for better instruction following.",
category: ["text", "open-source"],
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: "Open Source",
isFavorite: false
},
{
id: 20,
name: "mixtral-8x7b-instruct",
provider: "Mistral AI",
description: "Mixture of Experts model with excellent performance and efficiency.",
category: ["text", "open-source"],
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "32k",
contextWindow: "32,000",
modelType: "Text Generation",
badge: "MoE",
isFavorite: false
},
{
id: 21,
name: "gpt-4-vision-preview",
provider: "OpenAI",
description: "GPT-4 with vision capabilities for image understanding and analysis.",
category: "multimodal",
pricePerInput: "$0.01",
pricePerOutput: "$0.03",
maxTokens: "128k",
contextWindow: "128,000",
modelType: "Multimodal",
badge: "Vision",
isFavorite: false
},
{
id: 22,
name: "palm-2-chat-bison",
provider: "Google",
description: "Google's chat model optimized for conversational AI applications.",
category: "text",
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "8k",
contextWindow: "8,000",
modelType: "Text Generation",
badge: null,
isFavorite: false
},
{
id: 23,
name: "wizardlm-2-8x22b",
provider: "Microsoft",
description: "Advanced instruction-following model with complex reasoning.",
category: ["text", "open-source"],
pricePerInput: "$0.001",
pricePerOutput: "$0.003",
maxTokens: "65k",
contextWindow: "65,000",
modelType: "Text Generation",
badge: "Open Source",
isFavorite: false
},
{
id: 24,
name: "solar-10.7b-instruct",
provider: "Upstage",
description: "Compact yet powerful model with 10.7B parameters and strong performance.",
category: ["text", "open-source"],
pricePerInput: "$0.0005",
pricePerOutput: "$0.0015",
maxTokens: "4k",
contextWindow: "4,000",
modelType: "Text Generation",
badge: "Compact",
isFavorite: false
}
];
let currentFilter = 'all';
let currentSort = 'price-low';
let favorites = new Set();
function renderCards(models) {
const container = document.getElementById('cardsContainer');
container.innerHTML = '';
models.forEach((model, index) => {
const card = document.createElement('div');
card.className = 'model-card';
card.style.animationDelay = `${index * 0.1}s`;
const badges = model.badge ? `<div class="badge">${model.badge}</div>` : '';
card.innerHTML = `
${badges}
<div class="card-header">
<div class="model-info">
<h3 class="model-name">${model.name}</h3>
<div class="model-provider">
<i class="fas fa-building"></i>
${model.provider}
</div>
</div>
<button class="favorite-btn ${favorites.has(model.id) ? 'active' : ''}" data-id="${model.id}">
<i class="${favorites.has(model.id) ? 'fas' : 'far'} fa-heart"></i>
</button>
</div>
<p class="model-description">${model.description}</p>
<div class="pricing-section">
<div class="price-row">
<span class="price-label">Input Tokens</span>
<span class="price-value">${model.pricePerInput}/1K</span>
</div>
<div class="price-row">
<span class="price-label">Output Tokens</span>
<span class="price-value highlight">${model.pricePerOutput}/1K</span>
</div>
</div>
<div class="specs-grid">
<div class="spec-item">
<div class="spec-icon">
<i class="fas fa-database"></i>
</div>
<div class="spec-details">
<div class="spec-label">Max Tokens</div>
<div class="spec-value">${model.maxTokens}</div>
</div>
</div>
<div class="spec-item">
<div class="spec-icon">
<i class="fas fa-window-maximize"></i>
</div>
<div class="spec-details">
<div class="spec-label">Context</div>
<div class="spec-value">${model.contextWindow}</div>
</div>
</div>
</div>
<div class="card-footer">
<button class="btn btn-primary" onclick="selectModel(${model.id})">
Select Model
</button>
<button class="btn btn-secondary" onclick="viewDetails(${model.id})">
Details
</button>
</div>
`;
container.appendChild(card);
});
// Add favorite button listeners
document.querySelectorAll('.favorite-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation();
const modelId = parseInt(this.dataset.id);
toggleFavorite(modelId, this);
});
});
}
function toggleFavorite(modelId, button) {
if (favorites.has(modelId)) {
favorites.delete(modelId);
button.classList.remove('active');
button.innerHTML = '<i class="far fa-heart"></i>';
} else {
favorites.add(modelId);
button.classList.add('active');
button.innerHTML = '<i class="fas fa-heart"></i>';
}
}
function filterModels(category) {
if (category === 'all') {
return aiModels;
}
return aiModels.filter(model => {
if (Array.isArray(model.category)) {
return model.category.includes(category);
}
return model.category === category;
});
}
function sortModels(models, sortBy) {
const sorted = [...models];
switch(sortBy) {
case 'price-low':
return sorted.sort((a, b) => parseFloat(a.pricePerOutput.slice(1)) - parseFloat(b.pricePerOutput.slice(1)));
case 'price-high':
return sorted.sort((a, b) => parseFloat(b.pricePerOutput.slice(1)) - parseFloat(a.pricePerOutput.slice(1)));
case 'tokens':
return sorted.sort((a, b) => {
const aTokens = a.maxTokens === 'N/A' ? 0 : parseInt(a.maxTokens.replace('k', '000'));
const bTokens = b.maxTokens === 'N/A' ? 0 : parseInt(b.maxTokens.replace('k', '000'));
return bTokens - aTokens;
});
case 'name':
return sorted.sort((a, b) => a.name.localeCompare(b.name));
default:
return sorted;
}
}
function selectModel(modelId) {
const model = aiModels.find(m => m.id === modelId);
console.log('Selected model:', model);
// Create a toast notification
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
background: var(--openrouter-gradient);
color: white;
padding: 1rem 2rem;
border-radius: 50px;
box-shadow: var(--shadow-xl);
z-index: 1000;
animation: slideUp 0.3s ease-out;
`;
toast.textContent = `Selected ${model.name}`;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideDown 0.3s ease-out';
setTimeout(() => toast.remove(), 300);
}, 2000);
}
function viewDetails(modelId) {
const model = aiModels.find(m => m.id === modelId);
console.log('View details for:', model);
// Create a modal with details
const modal = document.createElement('div');
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
animation: fadeIn 0.3s ease-out;
`;
modal.innerHTML = `
<div style="background: white; padding: 2rem; border-radius: 20px; max-width: 500px; margin: 2rem;">
<h2 style="margin-bottom: 1rem; color: var(--text-primary);">${model.name}</h2>
<p style="color: var(--text-secondary); margin-bottom: 1rem;">${model.description}</p>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
<div>
<strong>Provider:</strong> ${model.provider}<br>
<strong>Type:</strong> ${model.modelType}<br>
<strong>Input Price:</strong> ${model.pricePerInput}/1K
</div>
<div>
<strong>Output Price:</strong> ${model.pricePerOutput}/1K<br>
<strong>Max Tokens:</strong> ${model.maxTokens}<br>
<strong>Context:</strong> ${model.contextWindow}
</div>
</div>
<button onclick="this.closest('div').parentElement.remove()" style="
background: var(--openrouter-gradient);
color: white;
border: none;
padding: 0.75rem 2rem;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
">Close</button>
</div>
`;
document.body.appendChild(modal);
modal.addEventListener('click', function(e) {
if (e.target === modal) modal.remove();
});
}
// Filter chips
document.querySelectorAll('.chip').forEach(chip => {
chip.addEventListener('click', function() {
document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
this.classList.add('active');
currentFilter = this.dataset.filter;
const filtered = filterModels(currentFilter);
const sorted = sortModels(filtered, currentSort);
renderCards(sorted);
});
});
// Sort dropdown
document.getElementById('sortDropdown').addEventListener('change', function() {
currentSort = this.value;
const filtered = filterModels(currentFilter);
const sorted = sortModels(filtered, currentSort);
renderCards(sorted);
});
// Search functionality
document.getElementById('searchInput').addEventListener('input', function(e) {
const searchTerm = e.target.value.toLowerCase();
const filtered = aiModels.filter(model =>
model.name.toLowerCase().includes(searchTerm) ||
model.provider.toLowerCase().includes(searchTerm) ||
model.description.toLowerCase().includes(searchTerm)
);
renderCards(filtered);
});
// Floating action button
document.querySelector('.floating-action').addEventListener('click', function() {
if (favorites.size === 0) {
alert('Please select some favorite models to compare!');
return;
}
const favoriteModels = aiModels.filter(m => favorites.has(m.id));
console.log('Comparing models:', favoriteModels);
this.style.transform = 'scale(1.1) rotate(180deg)';
setTimeout(() => {
this.style.transform = '';
}, 300);
});
// Initialize
document.addEventListener('DOMContentLoaded', function() {
const sorted = sortModels(aiModels, currentSort);
renderCards(sorted);
// Update stats
document.getElementById('modelCount').textContent = aiModels.length;
document.getElementById('providerCount').textContent = [...new Set(aiModels.map(m => m.provider))].length;
});
</script>
</body>
</html>