<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple MCP Data Manager with AI</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.content {
padding: 30px;
}
.section {
margin-bottom: 40px;
padding: 25px;
border: 1px solid #e1e5e9;
border-radius: 10px;
background: #f8f9fa;
}
.section h2 {
color: #333;
margin-bottom: 20px;
font-size: 1.5rem;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 600;
color: #555;
}
input, textarea, select {
width: 100%;
padding: 12px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s;
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: #667eea;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: transform 0.2s;
}
.btn:hover {
transform: translateY(-2px);
}
.btn-secondary {
background: #6c757d;
}
.btn-danger {
background: #dc3545;
}
.btn-success {
background: #28a745;
}
.btn-warning {
background: #ffc107;
color: #212529;
}
.btn-group {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.items-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.item-card {
background: white;
border: 1px solid #e1e5e9;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.item-card h3 {
color: #333;
margin-bottom: 10px;
}
.item-card p {
color: #666;
margin-bottom: 8px;
}
.item-meta {
font-size: 12px;
color: #999;
margin-top: 15px;
padding-top: 10px;
border-top: 1px solid #eee;
}
.search-section {
background: #e3f2fd;
border-color: #2196f3;
}
.create-section {
background: #e8f5e8;
border-color: #4caf50;
}
.ai-section {
background: #fff3e0;
border-color: #ff9800;
}
.response {
margin-top: 20px;
padding: 15px;
border-radius: 8px;
font-family: monospace;
font-size: 14px;
max-height: 300px;
overflow-y: auto;
}
.response.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.response.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.response.info {
background: #d1ecf1;
border: 1px solid #bee5eb;
color: #0c5460;
}
.loading {
text-align: center;
padding: 20px;
color: #666;
}
.api-links {
background: #fff3cd;
border-color: #ffc107;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.api-links h3 {
color: #856404;
margin-bottom: 10px;
}
.api-links a {
color: #667eea;
text-decoration: none;
margin-right: 20px;
}
.api-links a:hover {
text-decoration: underline;
}
.model-info {
background: #e8f5e8;
border: 1px solid #4caf50;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.model-info h3 {
color: #2e7d32;
margin-bottom: 10px;
}
.model-status {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
}
.model-status.loaded {
background: #d4edda;
color: #155724;
}
.model-status.not-loaded {
background: #f8d7da;
color: #721c24;
}
.tabs {
display: flex;
border-bottom: 2px solid #e1e5e9;
margin-bottom: 20px;
}
.tab {
padding: 10px 20px;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s;
}
.tab.active {
border-bottom-color: #667eea;
color: #667eea;
font-weight: bold;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 Simple MCP Data Manager with AI</h1>
<p>Manage your data with RESTful API operations and local AI model integration</p>
</div>
<div class="content">
<!-- API Documentation Links -->
<div class="api-links">
<h3>📚 API Documentation</h3>
<a href="/docs" target="_blank">Interactive API Docs (Swagger)</a>
<a href="/redoc" target="_blank">ReDoc Documentation</a>
<a href="/api/health" target="_blank">Health Check</a>
</div>
<!-- AI Model Info -->
<div class="model-info">
<h3>🤖 AI Model Status</h3>
<div id="modelStatus">Loading model information...</div>
</div>
<!-- Tabs -->
<div class="tabs">
<div class="tab active" onclick="showTab('data')">📊 Data Management</div>
<div class="tab" onclick="showTab('ai')">🤖 AI Features</div>
</div>
<!-- Data Management Tab -->
<div id="data-tab" class="tab-content active">
<!-- Search Section -->
<div class="section search-section">
<h2>🔍 Search Items</h2>
<div class="form-group">
<label for="searchQuery">Search Query:</label>
<input type="text" id="searchQuery" placeholder="Enter search term...">
</div>
<button class="btn" onclick="searchItems()">Search</button>
<div id="searchResponse"></div>
</div>
<!-- Create Section -->
<div class="section create-section">
<h2>➕ Create New Item</h2>
<div class="form-group">
<label for="itemName">Name:</label>
<input type="text" id="itemName" placeholder="Enter item name">
</div>
<div class="form-group">
<label for="itemDescription">Description:</label>
<textarea id="itemDescription" rows="3" placeholder="Enter item description"></textarea>
</div>
<div class="form-group">
<label for="itemCategory">Category:</label>
<input type="text" id="itemCategory" placeholder="Enter category">
</div>
<button class="btn" onclick="createItem()">Create Item</button>
<div id="createResponse"></div>
</div>
<!-- Items List -->
<div class="section">
<h2>📋 All Items</h2>
<button class="btn" onclick="loadItems()">Refresh Items</button>
<div id="itemsContainer" class="items-grid"></div>
</div>
</div>
<!-- AI Features Tab -->
<div id="ai-tab" class="tab-content">
<!-- AI Model Control -->
<div class="section ai-section">
<h2>🤖 AI Model Control</h2>
<div class="form-group">
<label for="modelType">Model Type:</label>
<select id="modelType">
<option value="sentence_transformer">Sentence Transformer</option>
<option value="text_generation">Text Generation</option>
<option value="text_classification">Text Classification</option>
<option value="sentiment_analysis">Sentiment Analysis</option>
<option value="tfidf">TF-IDF</option>
</select>
</div>
<div class="form-group">
<label for="modelName">Model Name:</label>
<input type="text" id="modelName" placeholder="e.g., all-MiniLM-L6-v2" value="all-MiniLM-L6-v2">
</div>
<button class="btn btn-warning" onclick="changeModel()">Change Model</button>
<div id="modelChangeResponse"></div>
</div>
<!-- Text Analysis -->
<div class="section ai-section">
<h2>📝 Text Analysis</h2>
<div class="form-group">
<label for="analysisText">Text to Analyze:</label>
<textarea id="analysisText" rows="4" placeholder="Enter text to analyze..."></textarea>
</div>
<button class="btn btn-success" onclick="analyzeText()">Analyze Text</button>
<div id="textAnalysisResponse"></div>
</div>
<!-- AI Search -->
<div class="section ai-section">
<h2>🔍 AI-Powered Search</h2>
<div class="form-group">
<label for="aiSearchQuery">Search Query:</label>
<input type="text" id="aiSearchQuery" placeholder="Enter search query...">
</div>
<div class="form-group">
<label for="aiSearchTopK">Number of Results:</label>
<input type="number" id="aiSearchTopK" value="5" min="1" max="20">
</div>
<div class="btn-group">
<button class="btn btn-success" onclick="findSimilarItems()">Find Similar Items</button>
<button class="btn btn-warning" onclick="smartSearch()">Smart Search</button>
</div>
<div id="aiSearchResponse"></div>
</div>
<!-- Batch Analysis -->
<div class="section ai-section">
<h2>📊 Batch Analysis</h2>
<div class="btn-group">
<button class="btn btn-success" onclick="analyzeAllItems()">Analyze All Items</button>
</div>
<div id="batchAnalysisResponse"></div>
</div>
</div>
</div>
</div>
<script>
const API_BASE = '/api';
// Tab functionality
function showTab(tabName) {
// Hide all tab contents
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tabs
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
// Show selected tab content
document.getElementById(tabName + '-tab').classList.add('active');
// Add active class to clicked tab
event.target.classList.add('active');
}
// Load model information
async function loadModelInfo() {
try {
const response = await fetch(`${API_BASE}/ai/model-info`);
const info = await response.json();
const statusDiv = document.getElementById('modelStatus');
const statusClass = info.is_loaded ? 'loaded' : 'not-loaded';
const statusText = info.is_loaded ? 'Loaded' : 'Not Loaded';
statusDiv.innerHTML = `
<p><strong>Model Type:</strong> ${info.model_type}</p>
<p><strong>Model Name:</strong> ${info.model_name}</p>
<p><strong>Status:</strong> <span class="model-status ${statusClass}">${statusText}</span></p>
<p><strong>AI Available:</strong> ${info.ai_available ? 'Yes' : 'No'}</p>
`;
} catch (error) {
document.getElementById('modelStatus').innerHTML = `<p>Error loading model info: ${error.message}</p>`;
}
}
// Change AI model
async function changeModel() {
const modelType = document.getElementById('modelType').value;
const modelName = document.getElementById('modelName').value.trim();
if (!modelName) {
showResponse('modelChangeResponse', { error: 'Model name is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/ai/change-model?model_type=${encodeURIComponent(modelType)}&model_name=${encodeURIComponent(modelName)}`, {
method: 'POST'
});
const result = await response.json();
showResponse('modelChangeResponse', result, !result.success);
if (result.success) {
// Reload model info
setTimeout(loadModelInfo, 1000);
}
} catch (error) {
showResponse('modelChangeResponse', { error: error.message }, true);
}
}
// Analyze text
async function analyzeText() {
const text = document.getElementById('analysisText').value.trim();
if (!text) {
showResponse('textAnalysisResponse', { error: 'Text is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/ai/analyze-text?text=${encodeURIComponent(text)}`, {
method: 'POST'
});
const result = await response.json();
showResponse('textAnalysisResponse', result, !result.success);
} catch (error) {
showResponse('textAnalysisResponse', { error: error.message }, true);
}
}
// Find similar items
async function findSimilarItems() {
const query = document.getElementById('aiSearchQuery').value.trim();
const topK = document.getElementById('aiSearchTopK').value;
if (!query) {
showResponse('aiSearchResponse', { error: 'Search query is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/ai/similar-items?q=${encodeURIComponent(query)}&top_k=${topK}`);
const result = await response.json();
showResponse('aiSearchResponse', result, !result.success);
} catch (error) {
showResponse('aiSearchResponse', { error: error.message }, true);
}
}
// Smart search
async function smartSearch() {
const query = document.getElementById('aiSearchQuery').value.trim();
const topK = document.getElementById('aiSearchTopK').value;
if (!query) {
showResponse('aiSearchResponse', { error: 'Search query is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/ai/smart-search?q=${encodeURIComponent(query)}&top_k=${topK}`);
const result = await response.json();
showResponse('aiSearchResponse', result, !result.success);
} catch (error) {
showResponse('aiSearchResponse', { error: error.message }, true);
}
}
// Analyze all items
async function analyzeAllItems() {
try {
const response = await fetch(`${API_BASE}/ai/analyze-items`);
const result = await response.json();
showResponse('batchAnalysisResponse', result, !result.success);
} catch (error) {
showResponse('batchAnalysisResponse', { error: error.message }, true);
}
}
// Utility function to show response
function showResponse(containerId, data, isError = false) {
const container = document.getElementById(containerId);
const responseClass = isError ? 'error' : (data.success === false ? 'error' : 'success');
container.innerHTML = `<div class="response ${responseClass}">${JSON.stringify(data, null, 2)}</div>`;
}
// Load all items
async function loadItems() {
const container = document.getElementById('itemsContainer');
container.innerHTML = '<div class="loading">Loading items...</div>';
try {
const response = await fetch(`${API_BASE}/items`);
const result = await response.json();
if (result.success) {
if (result.data.length === 0) {
container.innerHTML = '<p>No items found. Create some items to get started!</p>';
return;
}
container.innerHTML = result.data.map(item => `
<div class="item-card">
<h3>${item.name}</h3>
<p><strong>Description:</strong> ${item.description || 'No description'}</p>
<p><strong>Category:</strong> ${item.category || 'No category'}</p>
<div class="item-meta">
<p><strong>ID:</strong> ${item.id}</p>
<p><strong>Created:</strong> ${new Date(item.createdAt).toLocaleString()}</p>
<p><strong>Updated:</strong> ${new Date(item.updatedAt).toLocaleString()}</p>
</div>
<div class="btn-group" style="margin-top: 15px;">
<button class="btn btn-secondary" onclick="editItem('${item.id}')">Edit</button>
<button class="btn btn-danger" onclick="deleteItem('${item.id}')">Delete</button>
<button class="btn btn-success" onclick="analyzeItem('${item.id}')">Analyze</button>
</div>
</div>
`).join('');
} else {
container.innerHTML = `<div class="response error">Error: ${result.error}</div>`;
}
} catch (error) {
container.innerHTML = `<div class="response error">Error: ${error.message}</div>`;
}
}
// Create new item
async function createItem() {
const name = document.getElementById('itemName').value.trim();
const description = document.getElementById('itemDescription').value.trim();
const category = document.getElementById('itemCategory').value.trim();
if (!name) {
showResponse('createResponse', { error: 'Name is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/items`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name,
description,
category
})
});
const result = await response.json();
showResponse('createResponse', result, !result.success);
if (result.success) {
// Clear form
document.getElementById('itemName').value = '';
document.getElementById('itemDescription').value = '';
document.getElementById('itemCategory').value = '';
// Reload items
setTimeout(loadItems, 1000);
}
} catch (error) {
showResponse('createResponse', { error: error.message }, true);
}
}
// Search items
async function searchItems() {
const query = document.getElementById('searchQuery').value.trim();
if (!query) {
showResponse('searchResponse', { error: 'Search query is required' }, true);
return;
}
try {
const response = await fetch(`${API_BASE}/search?q=${encodeURIComponent(query)}`);
const result = await response.json();
showResponse('searchResponse', result, !result.success);
} catch (error) {
showResponse('searchResponse', { error: error.message }, true);
}
}
// Delete item
async function deleteItem(id) {
if (!confirm('Are you sure you want to delete this item?')) {
return;
}
try {
const response = await fetch(`${API_BASE}/items/${id}`, {
method: 'DELETE'
});
const result = await response.json();
if (result.success) {
loadItems(); // Reload the list
} else {
alert(`Error: ${result.error}`);
}
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Edit item
async function editItem(id) {
const newName = prompt('Enter new name:');
const newDescription = prompt('Enter new description:');
const newCategory = prompt('Enter new category:');
if (!newName) return;
try {
const updateData = { name: newName };
if (newDescription) updateData.description = newDescription;
if (newCategory) updateData.category = newCategory;
const response = await fetch(`${API_BASE}/items/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updateData)
});
const result = await response.json();
if (result.success) {
loadItems(); // Reload the list
} else {
alert(`Error: ${result.error}`);
}
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Analyze single item
async function analyzeItem(id) {
try {
const response = await fetch(`${API_BASE}/ai/analyze-item/${id}`);
const result = await response.json();
if (result.success) {
alert(`Item Analysis:\n${JSON.stringify(result.data, null, 2)}`);
} else {
alert(`Error: ${result.error}`);
}
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Load items and model info on page load
document.addEventListener('DOMContentLoaded', () => {
loadItems();
loadModelInfo();
});
</script>
</body>
</html>