|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>OpenAI O4 Analysis App</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/> |
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> |
|
<style> |
|
:root { |
|
--primary: #6366f1; |
|
--primary-dark: #4f46e5; |
|
--primary-light: #818cf8; |
|
} |
|
|
|
body { |
|
font-family: 'Inter', sans-serif; |
|
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); |
|
min-height: 100vh; |
|
} |
|
|
|
.gradient-bg { |
|
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%); |
|
} |
|
|
|
.tab-button { |
|
transition: all 0.3s ease; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.tab-button::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 3px; |
|
background: white; |
|
transform: scaleX(0); |
|
transform-origin: right; |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.tab-button.active::after { |
|
transform: scaleX(1); |
|
transform-origin: left; |
|
} |
|
|
|
.result-box { |
|
transition: all 0.3s ease; |
|
min-height: 200px; |
|
background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%); |
|
} |
|
|
|
.loading-dots { |
|
display: inline-block; |
|
} |
|
|
|
.loading-dots span { |
|
display: inline-block; |
|
width: 8px; |
|
height: 8px; |
|
border-radius: 50%; |
|
background-color: var(--primary); |
|
margin: 0 2px; |
|
animation: bounce 1.4s infinite ease-in-out both; |
|
} |
|
|
|
.loading-dots span:nth-child(1) { |
|
animation-delay: -0.32s; |
|
} |
|
|
|
.loading-dots span:nth-child(2) { |
|
animation-delay: -0.16s; |
|
} |
|
|
|
@keyframes bounce { |
|
0%, 80%, 100% { |
|
transform: scale(0); |
|
} |
|
40% { |
|
transform: scale(1); |
|
} |
|
} |
|
|
|
.file-input-label { |
|
transition: all 0.3s ease; |
|
position: relative; |
|
} |
|
|
|
.file-input-label:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 6px -1px rgba(99, 102, 241, 0.3), 0 2px 4px -1px rgba(99, 102, 241, 0.06); |
|
} |
|
|
|
.glow { |
|
animation: glow 2s infinite alternate; |
|
} |
|
|
|
@keyframes glow { |
|
from { |
|
box-shadow: 0 0 5px rgba(99, 102, 241, 0.5); |
|
} |
|
to { |
|
box-shadow: 0 0 20px rgba(99, 102, 241, 0.8); |
|
} |
|
} |
|
|
|
.card { |
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.card:hover { |
|
transform: translateY(-5px); |
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
|
} |
|
|
|
.btn-primary { |
|
background: var(--primary); |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.btn-primary:hover { |
|
background: var(--primary-dark); |
|
transform: translateY(-2px); |
|
} |
|
|
|
.btn-secondary { |
|
background: #f1f5f9; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.btn-secondary:hover { |
|
background: #e2e8f0; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.input-field { |
|
transition: all 0.3s ease; |
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05); |
|
} |
|
|
|
.input-field:focus { |
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.3); |
|
} |
|
|
|
.preview-container { |
|
position: relative; |
|
border-radius: 0.5rem; |
|
overflow: hidden; |
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
|
} |
|
|
|
.remove-btn { |
|
position: absolute; |
|
top: 0.5rem; |
|
right: 0.5rem; |
|
background: rgba(0, 0, 0, 0.6); |
|
color: white; |
|
border-radius: 50%; |
|
width: 2rem; |
|
height: 2rem; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.remove-btn:hover { |
|
background: rgba(239, 68, 68, 0.8); |
|
transform: scale(1.1); |
|
} |
|
|
|
.pulse { |
|
animation: pulse 2s infinite; |
|
} |
|
|
|
@keyframes pulse { |
|
0% { |
|
transform: scale(1); |
|
} |
|
50% { |
|
transform: scale(1.05); |
|
} |
|
100% { |
|
transform: scale(1); |
|
} |
|
} |
|
|
|
.floating { |
|
animation: floating 6s ease-in-out infinite; |
|
} |
|
|
|
@keyframes floating { |
|
0% { |
|
transform: translateY(0px); |
|
} |
|
50% { |
|
transform: translateY(-10px); |
|
} |
|
100% { |
|
transform: translateY(0px); |
|
} |
|
} |
|
|
|
.wave { |
|
position: absolute; |
|
bottom: 0; |
|
left: 0; |
|
width: 100%; |
|
overflow: hidden; |
|
line-height: 0; |
|
} |
|
|
|
.wave svg { |
|
position: relative; |
|
display: block; |
|
width: calc(100% + 1.3px); |
|
height: 150px; |
|
} |
|
|
|
.wave .shape-fill { |
|
fill: #FFFFFF; |
|
} |
|
|
|
.feature-icon { |
|
width: 60px; |
|
height: 60px; |
|
border-radius: 50%; |
|
background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(99, 102, 241, 0.2) 100%); |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin-bottom: 1rem; |
|
} |
|
</style> |
|
</head> |
|
<body class="antialiased"> |
|
|
|
<div class="fixed top-0 left-0 w-full h-full -z-10 opacity-10"> |
|
<div class="absolute top-0 left-0 w-full h-full bg-gradient-to-br from-indigo-100 to-purple-100"></div> |
|
</div> |
|
|
|
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> |
|
|
|
<div class="text-center mb-16 animate__animated animate__fadeIn"> |
|
<div class="inline-flex items-center justify-center mb-4 px-6 py-2 rounded-full bg-indigo-50 text-indigo-600"> |
|
<i class="fas fa-bolt mr-2"></i> |
|
<span class="font-medium">AI-Powered Analysis</span> |
|
</div> |
|
<h1 class="text-5xl font-bold text-gray-900 mb-4">OpenAI O4 Mini <span class="text-indigo-600">Analysis</span></h1> |
|
<p class="text-xl text-gray-600 max-w-2xl mx-auto">Unlock insights from your documents and images with cutting-edge AI technology</p> |
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 mb-16"> |
|
<div class="bg-white rounded-xl card p-6 text-center"> |
|
<div class="feature-icon mx-auto"> |
|
<i class="fas fa-file-pdf text-indigo-600 text-2xl"></i> |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">PDF Analysis</h3> |
|
<p class="text-gray-600">Extract key information and insights from your PDF documents with AI-powered analysis.</p> |
|
</div> |
|
|
|
<div class="bg-white rounded-xl card p-6 text-center"> |
|
<div class="feature-icon mx-auto"> |
|
<i class="fas fa-image text-indigo-600 text-2xl"></i> |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">Image Analysis</h3> |
|
<p class="text-gray-600">Understand visual content with advanced image recognition and description capabilities.</p> |
|
</div> |
|
|
|
<div class="bg-white rounded-xl card p-6 text-center"> |
|
<div class="feature-icon mx-auto"> |
|
<i class="fas fa-brain text-indigo-600 text-2xl"></i> |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">Smart Insights</h3> |
|
<p class="text-gray-600">Get comprehensive answers to your questions with adjustable reasoning levels.</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-white rounded-xl card p-8 mb-12 animate__animated animate__fadeInUp relative overflow-hidden"> |
|
<div class="absolute -top-10 -right-10 w-32 h-32 rounded-full bg-indigo-100 opacity-50"></div> |
|
<div class="absolute -bottom-10 -left-10 w-32 h-32 rounded-full bg-purple-100 opacity-50"></div> |
|
|
|
<div class="relative z-10"> |
|
<label for="api-key" class="block text-sm font-medium text-gray-700 mb-2 flex items-center"> |
|
<i class="fas fa-key mr-2 text-indigo-600"></i> |
|
OpenAI API Key |
|
</label> |
|
<div class="relative"> |
|
<input |
|
type="password" |
|
id="api-key" |
|
placeholder="Enter your OpenAI API key here..." |
|
class="w-full px-4 py-3 rounded-lg border border-gray-300 input-field focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" |
|
> |
|
<button |
|
onclick="toggleApiKeyVisibility()" |
|
class="absolute right-3 top-3 text-gray-500 hover:text-indigo-600 focus:outline-none" |
|
> |
|
<i class="far fa-eye"></i> |
|
</button> |
|
</div> |
|
<p class="mt-2 text-sm text-gray-500"> |
|
<i class="fas fa-info-circle mr-1 text-indigo-500"></i> |
|
Your API key is only used for requests and is not stored. |
|
</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="flex space-x-2 mb-8 animate__animated animate__fadeIn"> |
|
<button |
|
id="pdf-tab" |
|
onclick="switchTab('pdf')" |
|
class="tab-button active px-8 py-4 rounded-t-lg font-medium bg-white text-indigo-600 border-b-2 border-indigo-600" |
|
> |
|
<i class="fas fa-file-pdf mr-2"></i> |
|
PDF Analysis |
|
</button> |
|
<button |
|
id="image-tab" |
|
onclick="switchTab('image')" |
|
class="tab-button px-8 py-4 rounded-t-lg font-medium bg-white text-gray-600 hover:text-indigo-600 border-b-2 border-transparent hover:border-gray-300" |
|
> |
|
<i class="fas fa-image mr-2"></i> |
|
Image Analysis |
|
</button> |
|
</div> |
|
|
|
|
|
<div id="pdf-content" class="animate__animated animate__fadeIn"> |
|
<div class="bg-white rounded-b-xl rounded-tr-xl card overflow-hidden"> |
|
<div class="p-8"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center"> |
|
<i class="fas fa-file-pdf mr-3 text-indigo-600"></i> |
|
PDF Document Analysis |
|
</h2> |
|
|
|
<div class="mb-8"> |
|
<label class="block text-sm font-medium text-gray-700 mb-3">Upload PDF</label> |
|
<div id="pdf-upload-container"> |
|
<label for="pdf-upload" class="file-input-label cursor-pointer flex flex-col items-center justify-center px-6 py-12 border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 transition duration-200"> |
|
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i> |
|
<span class="text-sm font-medium text-gray-600">Drag & drop your PDF here or click to browse</span> |
|
<span class="text-xs text-gray-500 mt-1">Supports .pdf files up to 10MB</span> |
|
<input id="pdf-upload" type="file" accept=".pdf" class="hidden"> |
|
</label> |
|
</div> |
|
<div id="pdf-preview-container" class="hidden mt-4"> |
|
<div class="preview-container p-4 bg-gray-50 rounded-lg"> |
|
<div class="flex items-center"> |
|
<i class="fas fa-file-pdf text-3xl text-red-500 mr-3"></i> |
|
<div> |
|
<p id="pdf-filename" class="font-medium text-gray-800"></p> |
|
<p id="pdf-filesize" class="text-sm text-gray-500"></p> |
|
</div> |
|
<button id="remove-pdf" class="ml-auto remove-btn"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="mb-8"> |
|
<label for="pdf-prompt" class="block text-sm font-medium text-gray-700 mb-3">Analysis Prompt</label> |
|
<textarea |
|
id="pdf-prompt" |
|
rows="4" |
|
class="w-full px-4 py-3 rounded-lg border border-gray-300 input-field focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" |
|
placeholder="What would you like to know about this PDF? (e.g., 'Summarize this document', 'What are the key points?', 'Extract the main ideas')" |
|
>What is this PDF about?</textarea> |
|
</div> |
|
|
|
<div class="mb-8"> |
|
<label class="block text-sm font-medium text-gray-700 mb-3">Reasoning Effort Level</label> |
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="pdf-effort" value="low" class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Quick Scan</span> |
|
<span class="block text-xs text-gray-500">Basic analysis, faster results</span> |
|
</div> |
|
</label> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="pdf-effort" value="medium" checked class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Standard</span> |
|
<span class="block text-xs text-gray-500">Balanced speed and depth</span> |
|
</div> |
|
</label> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="pdf-effort" value="high" class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Deep Dive</span> |
|
<span class="block text-xs text-gray-500">Comprehensive, detailed analysis</span> |
|
</div> |
|
</label> |
|
</div> |
|
</div> |
|
|
|
<button |
|
id="analyze-pdf-btn" |
|
onclick="analyzePDF()" |
|
class="w-full py-4 px-6 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition duration-200 transform hover:scale-[1.02] focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 flex items-center justify-center" |
|
> |
|
<i class="fas fa-magic mr-2"></i> |
|
Analyze PDF |
|
</button> |
|
</div> |
|
|
|
<div id="pdf-result" class="result-box border-t border-gray-200 p-8 hidden"> |
|
<div class="flex items-center justify-between mb-6"> |
|
<h3 class="text-xl font-semibold text-gray-800 flex items-center"> |
|
<i class="fas fa-chart-line mr-2 text-indigo-600"></i> |
|
Analysis Results |
|
</h3> |
|
<button id="copy-pdf-result" class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center"> |
|
<i class="far fa-copy mr-1"></i> Copy |
|
</button> |
|
</div> |
|
<div id="pdf-result-content" class="min-h-40 p-6 bg-white rounded-lg border border-gray-200 shadow-sm"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="image-content" class="hidden animate__animated animate__fadeIn"> |
|
<div class="bg-white rounded-b-xl rounded-tr-xl card overflow-hidden"> |
|
<div class="p-8"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center"> |
|
<i class="fas fa-image mr-3 text-indigo-600"></i> |
|
Image Analysis |
|
</h2> |
|
|
|
<div class="mb-8"> |
|
<label class="block text-sm font-medium text-gray-700 mb-3">Image Source</label> |
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> |
|
<div> |
|
<div class="flex items-center space-x-4 mb-4"> |
|
<div class="flex-1 border-b-2 border-indigo-600 pb-2"> |
|
<h4 class="font-medium text-indigo-600 flex items-center"> |
|
<i class="fas fa-upload mr-2"></i> |
|
Upload Image |
|
</h4> |
|
</div> |
|
<div class="flex-1 text-center text-gray-400 pb-2"> |
|
<h4 class="font-medium">or</h4> |
|
</div> |
|
<div class="flex-1 border-b-2 border-gray-200 pb-2"> |
|
<h4 class="font-medium text-gray-600 hover:text-indigo-600 cursor-pointer flex items-center justify-end" onclick="switchImageSource('url')"> |
|
<i class="fas fa-link mr-2"></i> |
|
Use URL |
|
</h4> |
|
</div> |
|
</div> |
|
|
|
<div id="image-upload-container"> |
|
<label for="image-upload" class="file-input-label cursor-pointer flex flex-col items-center justify-center px-6 py-12 border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 transition duration-200"> |
|
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i> |
|
<span class="text-sm font-medium text-gray-600">Drag & drop your image here or click to browse</span> |
|
<span class="text-xs text-gray-500 mt-1">Supports JPG, PNG, GIF up to 5MB</span> |
|
<input id="image-upload" type="file" accept="image/*" class="hidden"> |
|
</label> |
|
</div> |
|
|
|
<div id="image-preview-container" class="hidden mt-4"> |
|
<div class="preview-container"> |
|
<img id="image-preview" src="" alt="Preview" class="w-full h-auto rounded-lg"> |
|
<button id="remove-image" class="remove-btn"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div id="image-url-container" class="hidden"> |
|
<div class="flex items-center space-x-4 mb-4"> |
|
<div class="flex-1 border-b-2 border-gray-200 pb-2"> |
|
<h4 class="font-medium text-gray-600 hover:text-indigo-600 cursor-pointer flex items-center" onclick="switchImageSource('upload')"> |
|
<i class="fas fa-upload mr-2"></i> |
|
Upload Image |
|
</h4> |
|
</div> |
|
<div class="flex-1 text-center text-gray-400 pb-2"> |
|
<h4 class="font-medium">or</h4> |
|
</div> |
|
<div class="flex-1 border-b-2 border-indigo-600 pb-2"> |
|
<h4 class="font-medium text-indigo-600 flex items-center justify-end"> |
|
<i class="fas fa-link mr-2"></i> |
|
Use URL |
|
</h4> |
|
</div> |
|
</div> |
|
|
|
<div class="mb-4"> |
|
<label for="image-url" class="block text-sm font-medium text-gray-700 mb-2">Image URL</label> |
|
<input |
|
type="text" |
|
id="image-url" |
|
placeholder="https://example.com/image.jpg" |
|
class="w-full px-4 py-3 rounded-lg border border-gray-300 input-field focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" |
|
> |
|
</div> |
|
|
|
<div id="url-preview-container" class="hidden mt-4"> |
|
<div class="preview-container"> |
|
<img id="url-preview" src="" alt="Preview" class="w-full h-auto rounded-lg"> |
|
<button id="remove-url" class="remove-btn"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="mb-8"> |
|
<label for="image-prompt" class="block text-sm font-medium text-gray-700 mb-3">Analysis Prompt</label> |
|
<textarea |
|
id="image-prompt" |
|
rows="4" |
|
class="w-full px-4 py-3 rounded-lg border border-gray-300 input-field focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" |
|
placeholder="What would you like to know about this image? (e.g., 'Describe this image', 'What objects are visible?', 'What is the main subject?')" |
|
>What is this image about?</textarea> |
|
</div> |
|
|
|
<div class="mb-8"> |
|
<label class="block text-sm font-medium text-gray-700 mb-3">Reasoning Effort Level</label> |
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="image-effort" value="low" class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Quick Scan</span> |
|
<span class="block text-xs text-gray-500">Basic analysis, faster results</span> |
|
</div> |
|
</label> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="image-effort" value="medium" checked class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Standard</span> |
|
<span class="block text-xs text-gray-500">Balanced speed and depth</span> |
|
</div> |
|
</label> |
|
<label class="inline-flex items-center bg-gray-50 hover:bg-gray-100 rounded-lg p-4 cursor-pointer transition duration-200"> |
|
<input type="radio" name="image-effort" value="high" class="h-5 w-5 text-indigo-600 focus:ring-indigo-500"> |
|
<div class="ml-3"> |
|
<span class="block text-sm font-medium text-gray-700">Deep Dive</span> |
|
<span class="block text-xs text-gray-500">Comprehensive, detailed analysis</span> |
|
</div> |
|
</label> |
|
</div> |
|
</div> |
|
|
|
<button |
|
id="analyze-image-btn" |
|
onclick="analyzeImage()" |
|
class="w-full py-4 px-6 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition duration-200 transform hover:scale-[1.02] focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 flex items-center justify-center" |
|
> |
|
<i class="fas fa-magic mr-2"></i> |
|
Analyze Image |
|
</button> |
|
</div> |
|
|
|
<div id="image-result" class="result-box border-t border-gray-200 p-8 hidden"> |
|
<div class="flex items-center justify-between mb-6"> |
|
<h3 class="text-xl font-semibold text-gray-800 flex items-center"> |
|
<i class="fas fa-chart-line mr-2 text-indigo-600"></i> |
|
Analysis Results |
|
</h3> |
|
<button id="copy-image-result" class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center"> |
|
<i class="far fa-copy mr-1"></i> Copy |
|
</button> |
|
</div> |
|
<div id="image-result-content" class="min-h-40 p-6 bg-white rounded-lg border border-gray-200 shadow-sm"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="mt-20 bg-white rounded-xl card p-8 relative overflow-hidden"> |
|
<div class="absolute -top-20 -right-20 w-64 h-64 rounded-full bg-indigo-100 opacity-30"></div> |
|
<div class="absolute -bottom-20 -left-20 w-64 h-64 rounded-full bg-purple-100 opacity-30"></div> |
|
|
|
<div class="relative z-10"> |
|
<h2 class="text-3xl font-bold text-center text-gray-900 mb-12"> |
|
<span class="text-indigo-600">How It Works</span> |
|
</h2> |
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> |
|
<div class="flex flex-col items-center text-center"> |
|
<div class="w-16 h-16 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mb-4 text-2xl"> |
|
1 |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">Upload Your File</h3> |
|
<p class="text-gray-600">Select a PDF document or image you want to analyze by uploading from your device or providing a URL.</p> |
|
</div> |
|
|
|
<div class="flex flex-col items-center text-center"> |
|
<div class="w-16 h-16 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mb-4 text-2xl"> |
|
2 |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">Set Your Preferences</h3> |
|
<p class="text-gray-600">Enter your analysis prompt and choose the reasoning effort level that suits your needs.</p> |
|
</div> |
|
|
|
<div class="flex flex-col items-center text-center"> |
|
<div class="w-16 h-16 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center mb-4 text-2xl"> |
|
3 |
|
</div> |
|
<h3 class="text-xl font-semibold text-gray-800 mb-2">Get AI Insights</h3> |
|
<p class="text-gray-600">Receive comprehensive analysis and answers to your questions powered by OpenAI's advanced models.</p> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<footer class="bg-gray-900 text-white py-12 mt-20 relative"> |
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> |
|
<div> |
|
<h3 class="text-xl font-semibold mb-4">OpenAI O4 Mini Analysis</h3> |
|
<p class="text-gray-400">Unlock the power of AI to analyze your documents and images with ease.</p> |
|
</div> |
|
<div> |
|
<h3 class="text-xl font-semibold mb-4">Quick Links</h3> |
|
<ul class="space-y-2"> |
|
<li><a href="#" class="text-gray-400 hover:text-white transition duration-200">Home</a></li> |
|
<li><a href="#" class="text-gray-400 hover:text-white transition duration-200">PDF Analysis</a></li> |
|
<li><a href="#" class="text-gray-400 hover:text-white transition duration-200">Image Analysis</a></li> |
|
</ul> |
|
</div> |
|
<div> |
|
<h3 class="text-xl font-semibold mb-4">Connect</h3> |
|
<div class="flex space-x-4"> |
|
<a href="https://www.facebook.com/shukdevdattatroy" class="text-gray-400 hover:text-white transition duration-200 text-xl"><i class="fab fa-facebook-f"></i></a> |
|
<a href="https://github.com/shukdevtroy" class="text-gray-400 hover:text-white transition duration-200 text-xl"><i class="fab fa-github"></i></a> |
|
<a href="https://www.linkedin.com/in/shukdev-datta-729767144/" class="text-gray-400 hover:text-white transition duration-200 text-xl"><i class="fab fa-linkedin"></i></a> |
|
<a href="https://huggingface.co./shukdevdatta123" class="text-gray-400 hover:text-white transition duration-200 text-xl"><i class="fa-solid fa-link"></i></a> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="border-t border-gray-800 mt-8 pt-8 text-center text-gray-400"> |
|
<p>© 2023 OpenAI O4 Mini Analysis. All rights reserved.</p> |
|
</div> |
|
</div> |
|
</footer> |
|
|
|
<script> |
|
|
|
function toggleApiKeyVisibility() { |
|
const apiKeyInput = document.getElementById('api-key'); |
|
const toggleBtn = apiKeyInput.nextElementSibling; |
|
|
|
if (apiKeyInput.type === 'password') { |
|
apiKeyInput.type = 'text'; |
|
toggleBtn.innerHTML = '<i class="far fa-eye-slash"></i>'; |
|
} else { |
|
apiKeyInput.type = 'password'; |
|
toggleBtn.innerHTML = '<i class="far fa-eye"></i>'; |
|
} |
|
} |
|
|
|
|
|
function switchTab(tab) { |
|
const pdfTab = document.getElementById('pdf-tab'); |
|
const imageTab = document.getElementById('image-tab'); |
|
const pdfContent = document.getElementById('pdf-content'); |
|
const imageContent = document.getElementById('image-content'); |
|
|
|
if (tab === 'pdf') { |
|
pdfTab.classList.remove('bg-white', 'text-gray-600', 'border-transparent', 'hover:border-gray-300'); |
|
pdfTab.classList.add('bg-white', 'text-indigo-600', 'border-b-2', 'border-indigo-600'); |
|
imageTab.classList.remove('bg-white', 'text-indigo-600', 'border-b-2', 'border-indigo-600'); |
|
imageTab.classList.add('bg-white', 'text-gray-600', 'border-transparent', 'hover:border-gray-300'); |
|
|
|
pdfContent.classList.remove('hidden'); |
|
imageContent.classList.add('hidden'); |
|
|
|
|
|
pdfContent.classList.remove('animate__fadeIn'); |
|
void pdfContent.offsetWidth; |
|
pdfContent.classList.add('animate__fadeIn'); |
|
} else { |
|
imageTab.classList.remove('bg-white', 'text-gray-600', 'border-transparent', 'hover:border-gray-300'); |
|
imageTab.classList.add('bg-white', 'text-indigo-600', 'border-b-2', 'border-indigo-600'); |
|
pdfTab.classList.remove('bg-white', 'text-indigo-600', 'border-b-2', 'border-indigo-600'); |
|
pdfTab.classList.add('bg-white', 'text-gray-600', 'border-transparent', 'hover:border-gray-300'); |
|
|
|
imageContent.classList.remove('hidden'); |
|
pdfContent.classList.add('hidden'); |
|
|
|
|
|
imageContent.classList.remove('animate__fadeIn'); |
|
void imageContent.offsetWidth; |
|
imageContent.classList.add('animate__fadeIn'); |
|
} |
|
} |
|
|
|
|
|
function switchImageSource(source) { |
|
const uploadContainer = document.getElementById('image-upload-container'); |
|
const urlContainer = document.getElementById('image-url-container'); |
|
const uploadPreview = document.getElementById('image-preview-container'); |
|
const urlPreview = document.getElementById('url-preview-container'); |
|
|
|
if (source === 'upload') { |
|
uploadContainer.classList.remove('hidden'); |
|
urlContainer.classList.add('hidden'); |
|
urlPreview.classList.add('hidden'); |
|
document.getElementById('image-url').value = ''; |
|
} else { |
|
uploadContainer.classList.add('hidden'); |
|
urlContainer.classList.remove('hidden'); |
|
uploadPreview.classList.add('hidden'); |
|
document.getElementById('image-upload').value = ''; |
|
} |
|
} |
|
|
|
|
|
document.getElementById('pdf-upload').addEventListener('change', function(e) { |
|
const uploadContainer = document.getElementById('pdf-upload-container'); |
|
const previewContainer = document.getElementById('pdf-preview-container'); |
|
const filenameDisplay = document.getElementById('pdf-filename'); |
|
const filesizeDisplay = document.getElementById('pdf-filesize'); |
|
|
|
if (this.files.length > 0) { |
|
const file = this.files[0]; |
|
filenameDisplay.textContent = file.name; |
|
filesizeDisplay.textContent = formatFileSize(file.size); |
|
|
|
uploadContainer.classList.add('hidden'); |
|
previewContainer.classList.remove('hidden'); |
|
} else { |
|
uploadContainer.classList.remove('hidden'); |
|
previewContainer.classList.add('hidden'); |
|
} |
|
}); |
|
|
|
|
|
document.getElementById('image-upload').addEventListener('change', function(e) { |
|
const uploadContainer = document.getElementById('image-upload-container'); |
|
const previewContainer = document.getElementById('image-preview-container'); |
|
const previewImage = document.getElementById('image-preview'); |
|
|
|
if (this.files.length > 0) { |
|
const file = this.files[0]; |
|
const reader = new FileReader(); |
|
|
|
reader.onload = function(event) { |
|
previewImage.src = event.target.result; |
|
uploadContainer.classList.add('hidden'); |
|
previewContainer.classList.remove('hidden'); |
|
} |
|
|
|
reader.readAsDataURL(file); |
|
} else { |
|
uploadContainer.classList.remove('hidden'); |
|
previewContainer.classList.add('hidden'); |
|
} |
|
}); |
|
|
|
|
|
document.getElementById('image-url').addEventListener('change', function(e) { |
|
const url = this.value.trim(); |
|
const previewContainer = document.getElementById('url-preview-container'); |
|
const previewImage = document.getElementById('url-preview'); |
|
|
|
if (url) { |
|
previewImage.src = url; |
|
previewContainer.classList.remove('hidden'); |
|
|
|
|
|
previewImage.onload = function() { |
|
previewContainer.classList.remove('hidden'); |
|
} |
|
|
|
previewImage.onerror = function() { |
|
previewContainer.classList.add('hidden'); |
|
alert('Could not load image from the provided URL. Please check the URL and try again.'); |
|
} |
|
} else { |
|
previewContainer.classList.add('hidden'); |
|
} |
|
}); |
|
|
|
|
|
document.getElementById('remove-pdf').addEventListener('click', function() { |
|
document.getElementById('pdf-upload').value = ''; |
|
document.getElementById('pdf-upload-container').classList.remove('hidden'); |
|
document.getElementById('pdf-preview-container').classList.add('hidden'); |
|
}); |
|
|
|
|
|
document.getElementById('remove-image').addEventListener('click', function() { |
|
document.getElementById('image-upload').value = ''; |
|
document.getElementById('image-upload-container').classList.remove('hidden'); |
|
document.getElementById('image-preview-container').classList.add('hidden'); |
|
}); |
|
|
|
|
|
document.getElementById('remove-url').addEventListener('click', function() { |
|
document.getElementById('image-url').value = ''; |
|
document.getElementById('url-preview-container').classList.add('hidden'); |
|
}); |
|
|
|
|
|
function formatFileSize(bytes) { |
|
if (bytes === 0) return '0 Bytes'; |
|
|
|
const k = 1024; |
|
const sizes = ['Bytes', 'KB', 'MB', 'GB']; |
|
const i = Math.floor(Math.log(bytes) / Math.log(k)); |
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; |
|
} |
|
|
|
|
|
function showLoading(element) { |
|
element.innerHTML = ` |
|
<div class="flex flex-col items-center justify-center py-8"> |
|
<div class="loading-dots mb-4"> |
|
<span></span> |
|
<span></span> |
|
<span></span> |
|
</div> |
|
<p class="text-gray-500">Analyzing content, please wait...</p> |
|
</div> |
|
`; |
|
} |
|
|
|
|
|
document.getElementById('copy-pdf-result')?.addEventListener('click', function() { |
|
const resultContent = document.getElementById('pdf-result-content').textContent; |
|
navigator.clipboard.writeText(resultContent).then(() => { |
|
const originalText = this.innerHTML; |
|
this.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; |
|
setTimeout(() => { |
|
this.innerHTML = originalText; |
|
}, 2000); |
|
}); |
|
}); |
|
|
|
document.getElementById('copy-image-result')?.addEventListener('click', function() { |
|
const resultContent = document.getElementById('image-result-content').textContent; |
|
navigator.clipboard.writeText(resultContent).then(() => { |
|
const originalText = this.innerHTML; |
|
this.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; |
|
setTimeout(() => { |
|
this.innerHTML = originalText; |
|
}, 2000); |
|
}); |
|
}); |
|
|
|
|
|
async function analyzePDF() { |
|
const apiKey = document.getElementById('api-key').value; |
|
const pdfFile = document.getElementById('pdf-upload').files[0]; |
|
const prompt = document.getElementById('pdf-prompt').value; |
|
const effortLevel = document.querySelector('input[name="pdf-effort"]:checked').value; |
|
const resultContent = document.getElementById('pdf-result-content'); |
|
const resultBox = document.getElementById('pdf-result'); |
|
|
|
if (!apiKey) { |
|
showAlert('Please provide an OpenAI API key.', 'error'); |
|
return; |
|
} |
|
|
|
if (!pdfFile) { |
|
showAlert('Please upload a PDF file.', 'error'); |
|
return; |
|
} |
|
|
|
|
|
resultBox.classList.remove('hidden'); |
|
showLoading(resultContent); |
|
|
|
try { |
|
|
|
const pdfBase64 = await new Promise((resolve, reject) => { |
|
const reader = new FileReader(); |
|
reader.onload = () => { |
|
const arrayBuffer = reader.result; |
|
const bytes = new Uint8Array(arrayBuffer); |
|
let binary = ''; |
|
for (let i = 0; i < bytes.byteLength; i++) { |
|
binary += String.fromCharCode(bytes[i]); |
|
} |
|
const base64 = btoa(binary); |
|
resolve(base64); |
|
}; |
|
reader.onerror = reject; |
|
reader.readAsArrayBuffer(pdfFile); |
|
}); |
|
|
|
|
|
const payload = { |
|
model: "o4-mini", |
|
input: [ |
|
{ |
|
role: "user", |
|
content: [ |
|
{ |
|
type: "input_text", |
|
text: prompt |
|
}, |
|
{ |
|
type: "input_file", |
|
filename: pdfFile.name, |
|
file_data: `data:application/pdf;base64,${pdfBase64}` |
|
} |
|
] |
|
} |
|
], |
|
text: { |
|
format: { |
|
type: "text" |
|
} |
|
}, |
|
reasoning: { |
|
effort: effortLevel |
|
}, |
|
tools: [], |
|
store: true |
|
}; |
|
|
|
|
|
const response = await axios.post('https://api.openai.com/v1/responses', payload, { |
|
headers: { |
|
'Authorization': `Bearer ${apiKey}`, |
|
'Content-Type': 'application/json' |
|
} |
|
}); |
|
|
|
|
|
const result = extractTextFromResponse(response.data); |
|
resultContent.innerHTML = `<div class="text-gray-700 whitespace-pre-wrap">${result}</div>`; |
|
|
|
} catch (error) { |
|
console.error('Error:', error); |
|
let errorMessage = 'An error occurred while analyzing the PDF.'; |
|
if (error.response) { |
|
errorMessage = `Error: ${error.response.data.error?.message || error.response.statusText}`; |
|
} else if (error.message) { |
|
errorMessage = `Error: ${error.message}`; |
|
} |
|
resultContent.innerHTML = `<div class="text-red-600">${errorMessage}</div>`; |
|
} |
|
} |
|
|
|
|
|
async function analyzeImage() { |
|
const apiKey = document.getElementById('api-key').value; |
|
const imageFile = document.getElementById('image-upload').files[0]; |
|
const imageUrl = document.getElementById('image-url').value; |
|
const prompt = document.getElementById('image-prompt').value; |
|
const effortLevel = document.querySelector('input[name="image-effort"]:checked').value; |
|
const resultContent = document.getElementById('image-result-content'); |
|
const resultBox = document.getElementById('image-result'); |
|
|
|
if (!apiKey) { |
|
showAlert('Please provide an OpenAI API key.', 'error'); |
|
return; |
|
} |
|
|
|
if (!imageFile && !imageUrl) { |
|
showAlert('Please upload an image or provide an image URL.', 'error'); |
|
return; |
|
} |
|
|
|
if (!prompt) { |
|
showAlert('Please provide a prompt for the image analysis.', 'error'); |
|
return; |
|
} |
|
|
|
|
|
resultBox.classList.remove('hidden'); |
|
showLoading(resultContent); |
|
|
|
try { |
|
const content = [ |
|
{ |
|
type: "input_text", |
|
text: prompt |
|
} |
|
]; |
|
|
|
if (imageFile) { |
|
|
|
const imageBase64 = await new Promise((resolve, reject) => { |
|
const reader = new FileReader(); |
|
reader.onload = () => { |
|
const base64 = reader.result.split(',')[1]; |
|
resolve(base64); |
|
}; |
|
reader.onerror = reject; |
|
reader.readAsDataURL(imageFile); |
|
}); |
|
|
|
content.unshift({ |
|
type: "input_image", |
|
image_url: `data:image/png;base64,${imageBase64}` |
|
}); |
|
} else if (imageUrl) { |
|
content.unshift({ |
|
type: "input_image", |
|
image_url: imageUrl |
|
}); |
|
} |
|
|
|
|
|
const payload = { |
|
model: "o4-mini", |
|
input: [ |
|
{ |
|
role: "user", |
|
content: content |
|
} |
|
], |
|
text: { |
|
format: { |
|
type: "text" |
|
} |
|
}, |
|
reasoning: { |
|
effort: effortLevel |
|
}, |
|
tools: [], |
|
store: true |
|
}; |
|
|
|
|
|
const response = await axios.post('https://api.openai.com/v1/responses', payload, { |
|
headers: { |
|
'Authorization': `Bearer ${apiKey}`, |
|
'Content-Type': 'application/json' |
|
} |
|
}); |
|
|
|
|
|
const result = extractTextFromResponse(response.data); |
|
resultContent.innerHTML = `<div class="text-gray-700 whitespace-pre-wrap">${result}</div>`; |
|
|
|
} catch (error) { |
|
console.error('Error:', error); |
|
let errorMessage = 'An error occurred while analyzing the image.'; |
|
if (error.response) { |
|
errorMessage = `Error: ${error.response.data.error?.message || error.response.statusText}`; |
|
} else if (error.message) { |
|
errorMessage = `Error: ${error.message}`; |
|
} |
|
resultContent.innerHTML = `<div class="text-red-600">${errorMessage}</div>`; |
|
} |
|
} |
|
|
|
|
|
function extractTextFromResponse(response) { |
|
try { |
|
|
|
if (response.output) { |
|
const output = response.output; |
|
|
|
|
|
for (const item of output) { |
|
if (item.role === 'assistant') { |
|
for (const contentItem of item.content) { |
|
if (contentItem.type === 'output_text') { |
|
return contentItem.text; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
return `Couldn't extract text from response: ${JSON.stringify(response)}`; |
|
} |
|
|
|
return `Unexpected response structure: ${JSON.stringify(response)}`; |
|
} catch (error) { |
|
return `Error processing response: ${error.message}`; |
|
} |
|
} |
|
|
|
|
|
function showAlert(message, type = 'info') { |
|
const alertDiv = document.createElement('div'); |
|
alertDiv.className = `fixed top-4 right-4 z-50 px-6 py-4 rounded-lg shadow-lg flex items-center ${ |
|
type === 'error' ? 'bg-red-100 text-red-800' : |
|
type === 'success' ? 'bg-green-100 text-green-800' : |
|
'bg-blue-100 text-blue-800' |
|
}`; |
|
|
|
const icon = type === 'error' ? 'exclamation-circle' : |
|
type === 'success' ? 'check-circle' : 'info-circle'; |
|
|
|
alertDiv.innerHTML = ` |
|
<i class="fas fa-${icon} mr-3"></i> |
|
<span>${message}</span> |
|
<button class="ml-4 text-xl" onclick="this.parentElement.remove()"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
`; |
|
|
|
document.body.appendChild(alertDiv); |
|
|
|
setTimeout(() => { |
|
alertDiv.remove(); |
|
}, 5000); |
|
} |
|
|
|
|
|
document.querySelectorAll('button').forEach(button => { |
|
if (!button.id.includes('remove') && button.id !== 'api-key-toggle') { |
|
button.addEventListener('mouseenter', () => { |
|
button.classList.add('glow'); |
|
}); |
|
button.addEventListener('mouseleave', () => { |
|
button.classList.remove('glow'); |
|
}); |
|
} |
|
}); |
|
|
|
|
|
document.querySelectorAll('.card').forEach(card => { |
|
card.addEventListener('mouseenter', () => { |
|
card.classList.add('glow'); |
|
}); |
|
card.addEventListener('mouseleave', () => { |
|
card.classList.remove('pulse'); |
|
}); |
|
}); |
|
</script> |
|
|
|
</body> |
|
</html> |