Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI-Powered Code Analysis Platform</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.gradient-bg { | |
background: linear-gradient(135deg, #1e3a8a 0%, #7c3aed 100%); | |
} | |
.code-block { | |
font-family: 'Courier New', monospace; | |
background-color: #1e293b; | |
color: #f8fafc; | |
} | |
.sidebar-item:hover .sidebar-tooltip { | |
display: block; | |
} | |
.animate-float { | |
animation: float 6s ease-in-out infinite; | |
} | |
@keyframes float { | |
0% { transform: translateY(0px); } | |
50% { transform: translateY(-20px); } | |
100% { transform: translateY(0px); } | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<!-- Solution Definition & Architecture Overview --> | |
<div class="container mx-auto px-4 py-12 max-w-7xl"> | |
<div class="gradient-bg text-white rounded-2xl p-8 mb-12 shadow-2xl"> | |
<h1 class="text-4xl font-bold mb-4">CodeReviewApp Architecture</h1> | |
<h2 class="text-2xl font-semibold mb-6">AI-Powered Code Analysis Platform</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> | |
<div> | |
<h3 class="text-xl font-semibold mb-3">Use Case Strategy</h3> | |
<ul class="space-y-3"> | |
<li class="flex items-start"> | |
<i class="fas fa-check-circle mt-1 mr-3 text-emerald-300"></i> | |
<span>Automated code quality analysis using AI models</span> | |
</li> | |
<li class="flex items-start"> | |
<i class="fas fa-check-circle mt-1 mr-3 text-emerald-300"></i> | |
<span>Security vulnerability detection in source code</span> | |
</li> | |
<li class="flex items-start"> | |
<i class="fas fa-check-circle mt-1 mr-3 text-emerald-300"></i> | |
<span>Technical debt visualization and recommendations</span> | |
</li> | |
</ul> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-3">Enterprise Benefits</h3> | |
<ul class="space-y-3"> | |
<li class="flex items-start"> | |
<i class="fas fa-chart-line mt-1 mr-3 text-amber-300"></i> | |
<span>30-50% reduction in code review time</span> | |
</li> | |
<li class="flex items-start"> | |
<i class="fas fa-shield-alt mt-1 mr-3 text-amber-300"></i> | |
<span>Early detection of security vulnerabilities</span> | |
</li> | |
<li class="flex items-start"> | |
<i class="fas fa-money-bill-wave mt-1 mr-3 text-amber-300"></i> | |
<span>Reduced technical debt maintenance costs</span> | |
</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
<!-- UX/UI Blueprint --> | |
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">UX/UI Blueprint</h2> | |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-8"> | |
<div class="lg:col-span-2"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Dashboard Layout</h3> | |
<div class="border-2 border-dashed border-gray-300 rounded-xl p-6 h-96 bg-gradient-to-br from-gray-50 to-gray-100"> | |
<div class="flex h-full"> | |
<!-- Sidebar --> | |
<div class="w-16 bg-gray-800 rounded-l-lg flex flex-col items-center py-4"> | |
<div class="mb-8 relative sidebar-item"> | |
<div class="w-10 h-10 bg-indigo-600 rounded-lg flex items-center justify-center text-white"> | |
<i class="fas fa-code"></i> | |
</div> | |
<div class="sidebar-tooltip absolute left-full ml-2 bg-gray-900 text-white px-2 py-1 rounded text-xs whitespace-nowrap hidden"> | |
Code Analysis | |
</div> | |
</div> | |
<div class="mb-8 relative sidebar-item"> | |
<div class="w-10 h-10 bg-gray-700 rounded-lg flex items-center justify-center text-gray-300"> | |
<i class="fas fa-shield-alt"></i> | |
</div> | |
<div class="sidebar-tooltip absolute left-full ml-2 bg-gray-900 text-white px-2 py-1 rounded text-xs whitespace-nowrap hidden"> | |
Security Scan | |
</div> | |
</div> | |
<div class="mb-8 relative sidebar-item"> | |
<div class="w-10 h-10 bg-gray-700 rounded-lg flex items-center justify-center text-gray-300"> | |
<i class="fas fa-chart-pie"></i> | |
</div> | |
<div class="sidebar-tooltip absolute left-full ml-2 bg-gray-900 text-white px-2 py-1 rounded text-xs whitespace-nowrap hidden"> | |
Metrics | |
</div> | |
</div> | |
</div> | |
<!-- Main Content --> | |
<div class="flex-1 bg-white rounded-r-lg p-4 flex flex-col"> | |
<div class="flex justify-between items-center mb-4"> | |
<h4 class="font-semibold text-gray-700">Code Analysis Report</h4> | |
<div class="flex space-x-2"> | |
<button class="px-3 py-1 bg-indigo-100 text-indigo-700 rounded text-sm">Export</button> | |
<button class="px-3 py-1 bg-gray-100 text-gray-700 rounded text-sm">Share</button> | |
</div> | |
</div> | |
<div class="flex-1 grid grid-cols-3 gap-4"> | |
<div class="bg-blue-50 rounded-lg p-3 col-span-2"> | |
<div class="h-6 bg-blue-200 rounded animate-pulse mb-2"></div> | |
<div class="h-4 bg-blue-200 rounded animate-pulse w-3/4"></div> | |
</div> | |
<div class="bg-purple-50 rounded-lg p-3"> | |
<div class="h-6 bg-purple-200 rounded animate-pulse mb-2"></div> | |
<div class="h-4 bg-purple-200 rounded animate-pulse w-1/2"></div> | |
</div> | |
<div class="bg-green-50 rounded-lg p-3"> | |
<div class="h-6 bg-green-200 rounded animate-pulse mb-2"></div> | |
<div class="h-4 bg-green-200 rounded animate-pulse w-2/3"></div> | |
</div> | |
<div class="bg-yellow-50 rounded-lg p-3 col-span-3"> | |
<div class="h-6 bg-yellow-200 rounded animate-pulse mb-2"></div> | |
<div class="h-4 bg-yellow-200 rounded animate-pulse w-full"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Design System</h3> | |
<div class="space-y-4"> | |
<div> | |
<p class="text-sm font-medium text-gray-500 mb-1">Primary Colors</p> | |
<div class="flex space-x-2"> | |
<div class="w-12 h-12 rounded-lg bg-indigo-600"></div> | |
<div class="w-12 h-12 rounded-lg bg-indigo-500"></div> | |
<div class="w-12 h-12 rounded-lg bg-indigo-400"></div> | |
</div> | |
</div> | |
<div> | |
<p class="text-sm font-medium text-gray-500 mb-1">Secondary Colors</p> | |
<div class="flex space-x-2"> | |
<div class="w-12 h-12 rounded-lg bg-emerald-500"></div> | |
<div class="w-12 h-12 rounded-lg bg-amber-500"></div> | |
<div class="w-12 h-12 rounded-lg bg-rose-500"></div> | |
</div> | |
</div> | |
<div> | |
<p class="text-sm font-medium text-gray-500 mb-1">Typography</p> | |
<div class="space-y-2"> | |
<p class="text-lg font-bold text-gray-800">Heading 1</p> | |
<p class="text-base font-medium text-gray-700">Body Text</p> | |
<p class="text-sm text-gray-500">Caption</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-gray-50 rounded-xl p-6"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Accessibility Features</h3> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-eye"></i> | |
</div> | |
<h4 class="font-medium mb-1">Color Contrast</h4> | |
<p class="text-sm text-gray-600">4.5:1 minimum contrast ratio for all text</p> | |
</div> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-keyboard"></i> | |
</div> | |
<h4 class="font-medium mb-1">Keyboard Nav</h4> | |
<p class="text-sm text-gray-600">Full keyboard navigation support</p> | |
</div> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-assistive-listening-systems"></i> | |
</div> | |
<h4 class="font-medium mb-1">Screen Reader</h4> | |
<p class="text-sm text-gray-600">ARIA labels and semantic HTML</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Frontend Engineering --> | |
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">Frontend Engineering</h2> | |
<div class="mb-8"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">React/TypeScript Architecture</h3> | |
<div class="bg-gray-800 rounded-lg p-4 mb-4"> | |
<div class="flex items-center text-gray-400 text-sm mb-2"> | |
<i class="fas fa-folder-open mr-2"></i> | |
<span>src/</span> | |
</div> | |
<div class="ml-6"> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>components/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>CodeEditor.tsx</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>AnalysisResults.tsx</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>SecurityFindings.tsx</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>hooks/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>useCodeAnalysis.ts</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>store/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>analysisSlice.ts</span> | |
</div> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div> | |
<h4 class="font-medium mb-2 text-gray-700">State Management</h4> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
// analysisSlice.ts | |
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; | |
interface AnalysisState { | |
code: string; | |
isLoading: boolean; | |
results: CodeAnalysisResult | null; | |
error: string | null; | |
} | |
const initialState: AnalysisState = { | |
code: '', | |
isLoading: false, | |
results: null, | |
error: null | |
}; | |
const analysisSlice = createSlice({ | |
name: 'analysis', | |
initialState, | |
reducers: { | |
setCode: (state, action: PayloadAction<string>) => { | |
state.code = action.payload; | |
}, | |
analyzeCodeStart: (state) => { | |
state.isLoading = true; | |
state.error = null; | |
}, | |
analyzeCodeSuccess: (state, action: PayloadAction<CodeAnalysisResult>) => { | |
state.isLoading = false; | |
state.results = action.payload; | |
}, | |
analyzeCodeFailure: (state, action: PayloadAction<string>) => { | |
state.isLoading = false; | |
state.error = action.payload; | |
} | |
} | |
}); | |
export const { | |
setCode, | |
analyzeCodeStart, | |
analyzeCodeSuccess, | |
analyzeCodeFailure | |
} = analysisSlice.actions; | |
export default analysisSlice.reducer;</pre> | |
</div> | |
</div> | |
<div> | |
<h4 class="font-medium mb-2 text-gray-700">Custom Hook</h4> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
// useCodeAnalysis.ts | |
import { useEffect } from 'react'; | |
import { useDispatch, useSelector } from 'react-redux'; | |
import { analyzeCodeStart, analyzeCodeSuccess, analyzeCodeFailure } from '../store/analysisSlice'; | |
import { RootState } from '../store/store'; | |
import api from '../services/api'; | |
export const useCodeAnalysis = () => { | |
const dispatch = useDispatch(); | |
const { code, isLoading, results, error } = useSelector( | |
(state: RootState) => state.analysis | |
); | |
const analyzeCode = async () => { | |
try { | |
dispatch(analyzeCodeStart()); | |
const response = await api.post('/analyze', { code }); | |
dispatch(analyzeCodeSuccess(response.data)); | |
} catch (err) { | |
dispatch(analyzeCodeFailure(err.message)); | |
} | |
}; | |
return { | |
code, | |
isLoading, | |
results, | |
error, | |
analyzeCode | |
}; | |
};</pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mb-8"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Component Implementation</h3> | |
<div class="bg-gray-50 p-4 rounded-lg mb-6"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
// CodeEditor.tsx | |
import React, { useState, useEffect } from 'react'; | |
import { useDispatch } from 'react-redux'; | |
import { setCode } from '../store/analysisSlice'; | |
import MonacoEditor from '@monaco-editor/react'; | |
import { LoadingSpinner } from './ui/LoadingSpinner'; | |
interface CodeEditorProps { | |
initialValue?: string; | |
language?: string; | |
} | |
export const CodeEditor: React.FC<CodeEditorProps> = ({ | |
initialValue = '', | |
language = 'javascript' | |
}) => { | |
const [value, setValue] = useState(initialValue); | |
const dispatch = useDispatch(); | |
useEffect(() => { | |
const timer = setTimeout(() => { | |
dispatch(setCode(value)); | |
}, 500); | |
return () => clearTimeout(timer); | |
}, [value, dispatch]); | |
return ( | |
<div className="border border-gray-200 rounded-lg overflow-hidden"> | |
<div className="bg-gray-800 px-4 py-2 flex justify-between items-center"> | |
<span className="text-sm text-gray-300">{language.toUpperCase()}</span> | |
<button className="text-xs bg-indigo-600 text-white px-2 py-1 rounded"> | |
Analyze | |
</button> | |
</div> | |
<MonacoEditor | |
height="500px" | |
language={language} | |
theme="vs-dark" | |
value={value} | |
onChange={(newValue) => setValue(newValue || '')} | |
loading={<LoadingSpinner />} | |
options={{ | |
minimap: { enabled: false }, | |
fontSize: 14, | |
wordWrap: 'on', | |
automaticLayout: true | |
}} | |
/> | |
</div> | |
); | |
};</pre> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
// AnalysisResults.tsx | |
import React from 'react'; | |
import { CodeIssue } from '../types'; | |
import { IssueSeverityBadge } from './ui/IssueSeverityBadge'; | |
interface AnalysisResultsProps { | |
issues: CodeIssue[]; | |
loading?: boolean; | |
} | |
export const AnalysisResults: React.FC<AnalysisResultsProps> = ({ | |
issues, | |
loading = false | |
}) => { | |
if (loading) { | |
return <div className="text-center py-8">Analyzing code...</div>; | |
} | |
if (!issues || issues.length === 0) { | |
return <div className="text-center py-8 text-gray-500">No issues found</div>; | |
} | |
return ( | |
<div className="space-y-4"> | |
{issues.map((issue, index) => ( | |
<div key={index} className="border border-gray-200 rounded-lg p-4"> | |
<div className="flex justify-between items-start mb-2"> | |
<h4 className="font-medium">{issue.message}</h4> | |
<IssueSeverityBadge severity={issue.severity} /> | |
</div> | |
<p className="text-sm text-gray-600 mb-2"> | |
Line {issue.line}: {issue.codeSnippet} | |
</p> | |
<p className="text-xs text-gray-500">{issue.ruleId}</p> | |
</div> | |
))} | |
</div> | |
); | |
};</pre> | |
</div> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
// SecurityFindings.tsx | |
import React from 'react'; | |
import { SecurityFinding } from '../types'; | |
import { CveBadge } from './ui/CveBadge'; | |
interface SecurityFindingsProps { | |
findings: SecurityFinding[]; | |
} | |
export const SecurityFindings: React.FC<SecurityFindingsProps> = ({ | |
findings | |
}) => { | |
return ( | |
<div className="space-y-4"> | |
{findings.map((finding, index) => ( | |
<div key={index} className="border border-red-200 rounded-lg p-4 bg-red-50"> | |
<div className="flex justify-between items-start mb-2"> | |
<h4 className="font-medium text-red-800">{finding.title}</h4> | |
<CveBadge cveId={finding.cveId} /> | |
</div> | |
<p className="text-sm text-red-700 mb-2">{finding.description}</p> | |
<div className="flex space-x-2"> | |
<span className="text-xs px-2 py-1 bg-red-100 text-red-800 rounded"> | |
Severity: {finding.severity} | |
</span> | |
<span className="text-xs px-2 py-1 bg-red-100 text-red-800 rounded"> | |
Line: {finding.line} | |
</span> | |
</div> | |
</div> | |
))} | |
</div> | |
); | |
};</pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Backend & API Architecture --> | |
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">Backend & API Architecture</h2> | |
<div class="mb-8"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">FastAPI Service Structure</h3> | |
<div class="bg-gray-800 rounded-lg p-4 mb-4"> | |
<div class="flex items-center text-gray-400 text-sm mb-2"> | |
<i class="fas fa-folder-open mr-2"></i> | |
<span>app/</span> | |
</div> | |
<div class="ml-6"> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>api/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>v1/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-12"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>endpoints/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>dependencies.py</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>core/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>config.py</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1"> | |
<i class="fas fa-folder mr-2"></i> | |
<span>services/</span> | |
</div> | |
<div class="flex items-center text-gray-400 text-sm mb-1 ml-6"> | |
<i class="fas fa-file-code mr-2"></i> | |
<span>code_analysis.py</span> | |
</div> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div> | |
<h4 class="font-medium mb-2 text-gray-700">Main Application</h4> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# main.py | |
from fastapi import FastAPI, Depends | |
from fastapi.middleware.cors import CORSMiddleware | |
from app.api.v1.endpoints import code_analysis, auth | |
from app.core.config import settings | |
app = FastAPI( | |
title="Deepsite API", | |
description="AI-powered code analysis platform", | |
version="1.0.0", | |
docs_url="/api/docs", | |
redoc_url="/api/redoc" | |
) | |
# CORS middleware | |
app.add_middleware( | |
CORSMiddleware, | |
allow_origins=settings.BACKEND_CORS_ORIGINS, | |
allow_credentials=True, | |
allow_methods=["*"], | |
allow_headers=["*"], | |
) | |
# Include API routers | |
app.include_router( | |
auth.router, | |
prefix="/api/v1/auth", | |
tags=["authentication"] | |
) | |
app.include_router( | |
code_analysis.router, | |
prefix="/api/v1/analysis", | |
tags=["code analysis"], | |
dependencies=[Depends(auth.get_current_active_user)] | |
)</pre> | |
</div> | |
</div> | |
<div> | |
<h4 class="font-medium mb-2 text-gray-700">Authentication</h4> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# auth.py | |
from datetime import datetime, timedelta | |
from typing import Optional | |
from fastapi import Depends, HTTPException, status | |
from fastapi.security import OAuth2PasswordBearer | |
from jose import JWTError, jwt | |
from passlib.context import CryptContext | |
from pydantic import BaseModel | |
from app.core.config import settings | |
# Password hashing | |
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | |
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") | |
class Token(BaseModel): | |
access_token: str | |
token_type: str | |
class TokenData(BaseModel): | |
username: Optional[str] = None | |
def verify_password(plain_password: str, hashed_password: str): | |
return pwd_context.verify(plain_password, hashed_password) | |
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): | |
to_encode = data.copy() | |
if expires_delta: | |
expire = datetime.utcnow() + expires_delta | |
else: | |
expire = datetime.utcnow() + timedelta(minutes=15) | |
to_encode.update({"exp": expire}) | |
encoded_jwt = jwt.encode( | |
to_encode, | |
settings.SECRET_KEY, | |
algorithm=settings.ALGORITHM | |
) | |
return encoded_jwt | |
async def get_current_user(token: str = Depends(oauth2_scheme)): | |
credentials_exception = HTTPException( | |
status_code=status.HTTP_401_UNAUTHORIZED, | |
detail="Could not validate credentials", | |
headers={"WWW-Authenticate": "Bearer"}, | |
) | |
try: | |
payload = jwt.decode( | |
token, | |
settings.SECRET_KEY, | |
algorithms=[settings.ALGORITHM] | |
) | |
username: str = payload.get("sub") | |
if username is None: | |
raise credentials_exception | |
token_data = TokenData(username=username) | |
except JWTError: | |
raise credentials_exception | |
user = get_user(fake_db, username=token_data.username) | |
if user is None: | |
raise credentials_exception | |
return user</pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mb-8"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">API Endpoints</h3> | |
<div class="bg-gray-50 p-4 rounded-lg mb-6"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# endpoints/code_analysis.py | |
from fastapi import APIRouter, Depends, HTTPException | |
from fastapi import status | |
from typing import List | |
from app.services.code_analysis import analyze_code | |
from app.models.schemas import CodeAnalysisRequest, CodeAnalysisResult | |
from app.api.v1.dependencies import get_current_active_user | |
router = APIRouter() | |
@router.post( | |
"/", | |
response_model=CodeAnalysisResult, | |
summary="Analyze code for quality and security issues", | |
description="""Analyzes the provided code for: | |
- Code quality issues | |
- Security vulnerabilities | |
- Performance anti-patterns | |
- Style violations""", | |
response_description="Analysis results with found issues" | |
) | |
async def analyze_code_endpoint( | |
request: CodeAnalysisRequest, | |
current_user: str = Depends(get_current_active_user) | |
) -> CodeAnalysisResult: | |
try: | |
result = await analyze_code(request.code, request.language) | |
return result | |
except Exception as e: | |
raise HTTPException( | |
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, | |
detail=f"Error analyzing code: {str(e)}" | |
) | |
@router.get( | |
"/history/", | |
response_model=List[CodeAnalysisResult], | |
summary="Get analysis history", | |
description="Returns the user's previous code analysis results", | |
response_description="List of previous analysis results" | |
) | |
async def get_analysis_history( | |
current_user: str = Depends(get_current_active_user) | |
) -> List[CodeAnalysisResult]: | |
# Implementation would query database for user's history | |
return []</pre> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# services/code_analysis.py | |
from typing import Optional | |
from app.models.schemas import CodeAnalysisResult, CodeIssue, SecurityFinding | |
from app.integrations.huggingface import query_hf_model | |
from app.integrations.sonarqube import analyze_with_sonarqube | |
async def analyze_code( | |
code: str, | |
language: str = "python" | |
) -> CodeAnalysisResult: | |
"""Analyze code using multiple analysis methods""" | |
# Initialize result objects | |
quality_issues: List[CodeIssue] = [] | |
security_findings: List[SecurityFinding] = [] | |
# 1. Static analysis with SonarQube | |
sonar_results = await analyze_with_sonarqube(code, language) | |
quality_issues.extend(sonar_results.issues) | |
# 2. AI-powered analysis with HuggingFace | |
hf_prompt = f""" | |
Analyze this {language} code for quality and security issues: | |
{code} | |
Return findings in JSON format with: | |
- issue_type (quality|security|performance|style) | |
- severity (low|medium|high|critical) | |
- message | |
- line_number | |
- recommendation | |
""" | |
hf_response = await query_hf_model( | |
model="codellama/CodeLlama-34b-Instruct-hf", | |
prompt=hf_prompt | |
) | |
# Process HF response and add to findings | |
if hf_response and hf_response.get("findings"): | |
for finding in hf_response["findings"]: | |
if finding["issue_type"] == "security": | |
security_findings.append( | |
SecurityFinding.from_hf_response(finding) | |
) | |
else: | |
quality_issues.append( | |
CodeIssue.from_hf_response(finding) | |
) | |
return CodeAnalysisResult( | |
quality_issues=quality_issues, | |
security_findings=security_findings, | |
summary=generate_summary(quality_issues, security_findings) | |
)</pre> | |
</div> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# models/schemas.py | |
from pydantic import BaseModel, Field | |
from typing import List, Optional | |
from enum import Enum | |
class Severity(str, Enum): | |
LOW = "low" | |
MEDIUM = "medium" | |
HIGH = "high" | |
CRITICAL = "critical" | |
class CodeIssue(BaseModel): | |
rule_id: str = Field(..., example="S100") | |
message: str = Field(..., example="Avoid using 'eval' function") | |
severity: Severity = Field(..., example="high") | |
line: int = Field(..., example=42) | |
code_snippet: str = Field(..., example="eval(user_input)") | |
category: str = Field(..., example="security") | |
@classmethod | |
def from_hf_response(cls, data: dict): | |
return cls( | |
rule_id=data.get("rule_id", "AI-"+data["issue_type"]), | |
message=data["message"], | |
severity=data["severity"], | |
line=data["line_number"], | |
code_snippet=data.get("code_snippet", ""), | |
category=data["issue_type"] | |
) | |
class SecurityFinding(BaseModel): | |
cve_id: Optional[str] = Field(None, example="CVE-2021-1234") | |
title: str = Field(..., example="SQL Injection Vulnerability") | |
description: str = Field(..., example="User input directly concatenated into SQL query") | |
severity: Severity = Field(..., example="critical") | |
line: int = Field(..., example=15) | |
recommendation: str = Field(..., example="Use parameterized queries") | |
@classmethod | |
def from_hf_response(cls, data: dict): | |
return cls( | |
title=data["message"], | |
description=data.get("recommendation", ""), | |
severity=data["severity"], | |
line=data["line_number"], | |
recommendation=data.get("recommendation", "") | |
) | |
class CodeAnalysisRequest(BaseModel): | |
code: str = Field(..., example="def foo():\n pass") | |
language: str = Field("python", example="python") | |
class CodeAnalysisResult(BaseModel): | |
quality_issues: List[CodeIssue] = [] | |
security_findings: List[SecurityFinding] = [] | |
summary: str = Field(..., example="Found 3 critical issues")</pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- AI/ML Integration --> | |
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">AI/ML Integration</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8"> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">HuggingFace Integration</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# integrations/huggingface.py | |
import os | |
from typing import Optional, Dict, Any | |
import httpx | |
from app.core.config import settings | |
from app.core.logging import logger | |
HF_API_URL = "https://api-inference.huggingface.co/models" | |
HF_API_KEY = settings.HF_API_KEY | |
async def query_hf_model( | |
model: str, | |
prompt: str, | |
parameters: Optional[Dict[str, Any]] = None | |
) -> Optional[Dict[str, Any]]: | |
"""Query HuggingFace inference API""" | |
headers = { | |
"Authorization": f"Bearer {HF_API_KEY}", | |
"Content-Type": "application/json" | |
} | |
payload = { | |
"inputs": prompt, | |
"parameters": parameters or { | |
"max_new_tokens": 1024, | |
"temperature": 0.7, | |
"return_full_text": False | |
} | |
} | |
try: | |
async with httpx.AsyncClient(timeout=30.0) as client: | |
response = await client.post( | |
f"{HF_API_URL}/{model}", | |
headers=headers, | |
json=payload | |
) | |
if response.status_code == 200: | |
return response.json() | |
elif response.status_code == 503: | |
# Model is loading, wait and retry | |
logger.info(f"Model {model} is loading, retrying...") | |
await asyncio.sleep(10) | |
return await query_hf_model(model, prompt, parameters) | |
else: | |
logger.error( | |
f"HF API error: {response.status_code} - {response.text}" | |
) | |
return None | |
except Exception as e: | |
logger.error(f"Error querying HF API: {str(e)}") | |
return None</pre> | |
</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Model Selection Strategy</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# services/model_selector.py | |
from enum import Enum | |
from typing import Optional, Dict, Any | |
from app.integrations.huggingface import query_hf_model | |
class ModelType(str, Enum): | |
CODE_ANALYSIS = "code_analysis" | |
SECURITY = "security" | |
DOCUMENTATION = "documentation" | |
MODEL_MAP = { | |
ModelType.CODE_ANALYSIS: "codellama/CodeLlama-34b-Instruct-hf", | |
ModelType.SECURITY: "deepset/roberta-base-squad2", | |
ModelType.DOCUMENTATION: "bigcode/starcoder" | |
} | |
def get_model_for_task(task_type: ModelType) -> str: | |
"""Get appropriate model for given task type""" | |
return MODEL_MAP.get(task_type, MODEL_MAP[ModelType.CODE_ANALYSIS]) | |
async def analyze_with_model( | |
code: str, | |
task_type: ModelType, | |
language: str = "python" | |
) -> Optional[Dict[str, Any]]: | |
"""Analyze code with task-specific model""" | |
model = get_model_for_task(task_type) | |
prompt = generate_prompt_for_task(task_type, code, language) | |
parameters = { | |
"max_new_tokens": 1024, | |
"temperature": 0.5 if task_type == ModelType.SECURITY else 0.7 | |
} | |
return await query_hf_model(model, prompt, parameters) | |
def generate_prompt_for_task( | |
task_type: ModelType, | |
code: str, | |
language: str | |
) -> str: | |
"""Generate task-specific prompt""" | |
if task_type == ModelType.SECURITY: | |
return f"""Analyze this {language} code for security vulnerabilities: | |
{code} | |
Return JSON with: | |
- vulnerability_type | |
- severity (low/medium/high/critical) | |
- description | |
- line_number | |
- recommendation | |
""" | |
elif task_type == ModelType.DOCUMENTATION: | |
return f"""Generate documentation for this {language} code: | |
{code} | |
Include: | |
- Function description | |
- Parameters | |
- Return value | |
- Usage example | |
""" | |
else: # Default code analysis | |
return f"""Analyze this {language} code for quality issues: | |
{code} | |
Return JSON with: | |
- issue_type (style/performance/bug) | |
- severity (low/medium/high) | |
- message | |
- line_number | |
- recommendation | |
"""</pre> | |
</div> | |
</div> | |
</div> | |
<div class="bg-gray-50 rounded-xl p-6"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">AI Pipeline Architecture</h3> | |
<div class="flex justify-center"> | |
<div class="relative w-full max-w-3xl"> | |
<!-- AI Pipeline Visualization --> | |
<div class="flex flex-col items-center space-y-8"> | |
<!-- Step 1 --> | |
<div class="flex items-center w-full"> | |
<div class="w-12 h-12 rounded-full bg-indigo-600 flex items-center justify-center text-white z-10"> | |
<i class="fas fa-code"></i> | |
</div> | |
<div class="ml-4 bg-white p-4 rounded-lg shadow-sm flex-1"> | |
<h4 class="font-medium">Code Input</h4> | |
<p class="text-sm text-gray-600">User submits code for analysis</p> | |
</div> | |
</div> | |
<!-- Arrow --> | |
<div class="h-8 w-0.5 bg-indigo-300 ml-6 -my-4"></div> | |
<!-- Step 2 --> | |
<div class="flex items-center w-full"> | |
<div class="w-12 h-12 rounded-full bg-indigo-600 flex items-center justify-center text-white z-10"> | |
<i class="fas fa-shield-alt"></i> | |
</div> | |
<div class="ml-4 bg-white p-4 rounded-lg shadow-sm flex-1"> | |
<h4 class="font-medium">Static Analysis</h4> | |
<p class="text-sm text-gray-600">SonarQube scans for common issues</p> | |
</div> | |
</div> | |
<!-- Arrow --> | |
<div class="h-8 w-0.5 bg-indigo-300 ml-6 -my-4"></div> | |
<!-- Step 3 --> | |
<div class="flex items-center w-full"> | |
<div class="w-12 h-12 rounded-full bg-indigo-600 flex items-center justify-center text-white z-10"> | |
<i class="fas fa-brain"></i> | |
</div> | |
<div class="ml-4 bg-white p-4 rounded-lg shadow-sm flex-1"> | |
<h4 class="font-medium">AI Analysis</h4> | |
<p class="text-sm text-gray-600">CodeLlama analyzes for complex patterns</p> | |
</div> | |
</div> | |
<!-- Arrow --> | |
<div class="h-8 w-0.5 bg-indigo-300 ml-6 -my-4"></div> | |
<!-- Step 4 --> | |
<div class="flex items-center w-full"> | |
<div class="w-12 h-12 rounded-full bg-indigo-600 flex items-center justify-center text-white z-10"> | |
<i class="fas fa-chart-bar"></i> | |
</div> | |
<div class="ml-4 bg-white p-4 rounded-lg shadow-sm flex-1"> | |
<h4 class="font-medium">Results Aggregation</h4> | |
<p class="text-sm text-gray-600">Combine findings from all sources</p> | |
</div> | |
</div> | |
<!-- Arrow --> | |
<div class="h-8 w-0.5 bg-indigo-300 ml-6 -my-4"></div> | |
<!-- Step 5 --> | |
<div class="flex items-center w-full"> | |
<div class="w-12 h-12 rounded-full bg-indigo-600 flex items-center justify-center text-white z-10"> | |
<i class="fas fa-file-alt"></i> | |
</div> | |
<div class="ml-4 bg-white p-4 rounded-lg shadow-sm flex-1"> | |
<h4 class="font-medium">Report Generation</h4> | |
<p class="text-sm text-gray-600">Create comprehensive report</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Deployment & Scalability --> | |
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">Deployment & Scalability</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8"> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Docker Configuration</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# Dockerfile | |
FROM python:3.9-slim as base | |
# Install system dependencies | |
RUN apt-get update && apt-get install -y \ | |
build-essential \ | |
curl \ | |
&& rm -rf /var/lib/apt/lists/* | |
# Create and activate virtual environment | |
ENV VIRTUAL_ENV=/opt/venv | |
RUN python3 -m venv $VIRTUAL_ENV | |
ENV PATH="$VIRTUAL_ENV/bin:$PATH" | |
# Install Python dependencies | |
WORKDIR /app | |
COPY requirements.txt . | |
RUN pip install --no-cache-dir -r requirements.txt | |
# Copy application code | |
COPY . . | |
# Frontend build stage | |
FROM node:16 as frontend-builder | |
WORKDIR /app/frontend | |
COPY frontend/package.json frontend/package-lock.json ./ | |
RUN npm install | |
COPY frontend . | |
RUN npm run build | |
# Final production image | |
FROM base as production | |
COPY --from=frontend-builder /app/frontend/dist /app/frontend/dist | |
# Set environment variables | |
ENV PYTHONUNBUFFERED=1 | |
ENV PORT=8000 | |
ENV MODE=production | |
# Run application | |
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "$PORT"]</pre> | |
</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">CI/CD Pipeline</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# .github/workflows/deploy.yml | |
name: Deploy to HuggingFace Spaces | |
on: | |
push: | |
branches: [ main ] | |
pull_request: | |
branches: [ main ] | |
jobs: | |
build-and-deploy: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: '3.9' | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install -r requirements.txt | |
- name: Set up Node.js | |
uses: actions/setup-node@v3 | |
with: | |
node-version: '16' | |
- name: Build frontend | |
working-directory: ./frontend | |
run: | | |
npm install | |
npm run build | |
- name: Configure Docker | |
run: | | |
echo "${{ secrets.HF_TOKEN }}" | docker login \ | |
-u ${{ secrets.HF_USERNAME }} \ | |
--password-stdin \ | |
ghcr.io | |
- name: Build and push Docker image | |
run: | | |
docker build -t ghcr.io/${{ secrets.HF_USERNAME }}/deepsite:latest . | |
docker push ghcr.io/${{ secrets.HF_USERNAME }}/deepsite:latest | |
- name: Deploy to Spaces | |
uses: huggingface/huggingface_hub@main | |
with: | |
huggingface_token: ${{ secrets.HF_TOKEN }} | |
repo_id: ${{ secrets.HF_USERNAME }}/deepsite | |
space_sdk: docker | |
space_hardware: cpu-basic | |
space_storage: small</pre> | |
</div> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Rate Limiting</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# app/api/dependencies.py | |
from fastapi import Depends, Request | |
from fastapi.security import HTTPBearer | |
from fastapi import HTTPException, status | |
from redis import Redis | |
from app.core.config import settings | |
security = HTTPBearer() | |
redis = Redis.from_url(settings.REDIS_URL) | |
async def rate_limit( | |
request: Request, | |
credentials: str = Depends(security) | |
) -> None: | |
"""Rate limiting middleware""" | |
# Get user ID from token | |
try: | |
payload = jwt.decode( | |
credentials.credentials, | |
settings.SECRET_KEY, | |
algorithms=[settings.ALGORITHM] | |
) | |
user_id = payload.get("sub") | |
except JWTError: | |
user_id = request.client.host # Fallback to IP | |
# Check rate limit | |
key = f"rate_limit:{user_id}" | |
current = redis.incr(key) | |
if current == 1: | |
redis.expire(key, 60) # 1 minute window | |
if current > settings.RATE_LIMIT: | |
raise HTTPException( | |
status_code=status.HTTP_429_TOO_MANY_REQUESTS, | |
detail="Too many requests" | |
)</pre> | |
</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">HuggingFace Space Config</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<pre class="text-xs code-block overflow-x-auto p-3 rounded"> | |
# README.md | |
--- | |
title: Deepsite | |
emoji: 🚀 | |
colorFrom: indigo | |
colorTo: purple | |
sdk: docker | |
app_file: app/main.py | |
pinned: true | |
license: apache-2.0 | |
# Hardware resources | |
resources: | |
cpu: 2 | |
memory: 8Gi | |
# Environment variables | |
env: | |
- HF_API_KEY: your_huggingface_api_key | |
- MODE: production | |
- PORT: 8000 | |
# Health check | |
healthcheck: | |
test: ["CMD", "curl", "-f", "http://localhost:$PORT/api/health"] | |
interval: 30s | |
timeout: 10s | |
retries: 3</pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Integration Strategy & Maintenance --> | |
<div class="bg-white rounded-2xl shadow-xl p-8"> | |
<h2 class="text-3xl font-bold mb-6 text-gray-800">Integration Strategy & Maintenance</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8"> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Deployment Steps</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<ol class="list-decimal pl-5 space-y-2 text-sm text-gray-700"> | |
<li>Set up HuggingFace Space with Docker SDK</li> | |
<li>Configure environment variables in Space settings</li> | |
<li>Connect GitHub repository for CI/CD</li> | |
<li>Set up Redis for rate limiting (if needed)</li> | |
<li>Configure custom domain (optional)</li> | |
<li>Enable monitoring and alerts</li> | |
</ol> | |
</div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700 mt-6">Monitoring</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<ul class="list-disc pl-5 space-y-2 text-sm text-gray-700"> | |
<li>Prometheus metrics endpoint at <code>/metrics</code></li> | |
<li>Health check endpoint at <code>/api/health</code></li> | |
<li>Log aggregation with ELK stack</li> | |
<li>Performance monitoring with Grafana</li> | |
</ul> | |
</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-semibold mb-4 text-gray-700">Maintenance Plan</h3> | |
<div class="bg-gray-50 p-4 rounded-lg"> | |
<div class="space-y-4"> | |
<div> | |
<h4 class="font-medium text-gray-700">Weekly</h4> | |
<ul class="list-disc pl-5 text-sm text-gray-700 mt-2"> | |
<li>Review error logs and metrics</li> | |
<li>Check for model updates on HuggingFace</li> | |
<li>Verify backup systems</li> | |
</ul> | |
</div> | |
<div> | |
<h4 class="font-medium text-gray-700">Monthly</h4> | |
<ul class="list-disc pl-5 text-sm text-gray-700 mt-2"> | |
<li>Update dependencies</li> | |
<li>Review rate limit thresholds</li> | |
<li>Test failover procedures</li> | |
</ul> | |
</div> | |
<div> | |
<h4 class="font-medium text-gray-700">Quarterly</h4> | |
<ul class="list-disc pl-5 text-sm text-gray-700 mt-2"> | |
<li>Security audit</li> | |
<li>Performance benchmark</li> | |
<li>User feedback review</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-indigo-50 rounded-xl p-6"> | |
<h3 class="text-xl font-semibold mb-4 text-indigo-800">Final Integration Strategy</h3> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-layer-group"></i> | |
</div> | |
<h4 class="font-medium mb-1">Layered Architecture</h4> | |
<p class="text-sm text-gray-600">Clear separation between frontend, backend, and AI components</p> | |
</div> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-plug"></i> | |
</div> | |
<h4 class="font-medium mb-1">API-First Design</h4> | |
<p class="text-sm text-gray-600">RESTful interfaces between all components</p> | |
</div> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-3"> | |
<i class="fas fa-box-open"></i> | |
</div> | |
<h4 class="font-medium mb-1">Containerized Deployment</h4> | |
<p class="text-sm text-gray-600">Docker containers for easy deployment on HuggingFace Spaces</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Simple animation for the architecture diagram | |
document.addEventListener('DOMContentLoaded', () => { | |
const architectureSteps = document.querySelectorAll('.flex.items-center.w-full'); | |
architectureSteps.forEach((step, index) => { | |
step.style.opacity = '0'; | |
step.style.transform = 'translateY(20px)'; | |
step.style.transition = `all 0.5s ease ${index * 0.2}s`; | |
setTimeout(() => { | |
step.style.opacity = '1'; | |
step.style.transform = 'translateY(0)'; | |
}, 100); | |
}); | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Boobs00/deepsite-architecture" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |