Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>MCP EdTech Demo</title> | |
| <style> | |
| :root { | |
| --primary-color: #4a6fa5; | |
| --secondary-color: #6c757d; | |
| --accent-color: #28a745; | |
| --light-bg: #f8f9fa; | |
| --dark-bg: #343a40; | |
| --text-color: #333; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| line-height: 1.6; | |
| color: var(--text-color); | |
| margin: 0; | |
| padding: 0; | |
| background-color: #f5f7fa; | |
| } | |
| .navbar { | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 1rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .navbar-brand { | |
| font-size: 1.5rem; | |
| font-weight: bold; | |
| color: white; | |
| text-decoration: none; | |
| } | |
| .navbar-nav { | |
| display: flex; | |
| list-style: none; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| .nav-item { | |
| margin-left: 1.5rem; | |
| } | |
| .nav-link { | |
| color: white; | |
| text-decoration: none; | |
| transition: color 0.3s; | |
| } | |
| .nav-link:hover { | |
| color: #e0e0e0; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 2rem; | |
| } | |
| .card { | |
| background-color: white; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| padding: 1.5rem; | |
| margin-bottom: 2rem; | |
| } | |
| .card-header { | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 1rem; | |
| border-radius: 8px 8px 0 0; | |
| margin: -1.5rem -1.5rem 1.5rem -1.5rem; | |
| } | |
| h1, h2, h3, h4 { | |
| color: var(--primary-color); | |
| } | |
| .btn { | |
| display: inline-block; | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 0.5rem 1rem; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| transition: background-color 0.3s; | |
| } | |
| .btn:hover { | |
| background-color: #3a5a8a; | |
| } | |
| .btn-success { | |
| background-color: var(--accent-color); | |
| } | |
| .btn-success:hover { | |
| background-color: #218838; | |
| } | |
| .form-group { | |
| margin-bottom: 1rem; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 500; | |
| } | |
| input, textarea { | |
| width: 100%; | |
| padding: 0.5rem; | |
| border: 1px solid #ddd; | |
| border-radius: 4px; | |
| font-size: 1rem; | |
| } | |
| .response-area { | |
| background-color: var(--light-bg); | |
| border: 1px solid #ddd; | |
| border-radius: 4px; | |
| padding: 1rem; | |
| margin-top: 1rem; | |
| min-height: 100px; | |
| white-space: pre-wrap; | |
| } | |
| .endpoints-list { | |
| list-style-type: none; | |
| padding: 0; | |
| } | |
| .endpoints-list li { | |
| padding: 0.5rem 0; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .context-id { | |
| font-family: monospace; | |
| background-color: #f1f1f1; | |
| padding: 0.2rem 0.4rem; | |
| border-radius: 4px; | |
| } | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| margin: 1rem 0; | |
| } | |
| .loading::after { | |
| content: "..."; | |
| animation: dots 1.5s steps(5, end) infinite; | |
| } | |
| @keyframes dots { | |
| 0%, 20% { content: "."; } | |
| 40% { content: ".."; } | |
| 60%, 100% { content: "..."; } | |
| } | |
| .error-message { | |
| color: #dc3545; | |
| margin-top: 0.5rem; | |
| display: none; | |
| } | |
| .success-message { | |
| color: var(--accent-color); | |
| margin-top: 0.5rem; | |
| display: none; | |
| } | |
| code { | |
| font-family: 'Courier New', Courier, monospace; | |
| background-color: #f5f5f5; | |
| padding: 0.2rem 0.4rem; | |
| border-radius: 3px; | |
| font-size: 0.9em; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 1rem; | |
| } | |
| .navbar { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| } | |
| .navbar-nav { | |
| margin-top: 1rem; | |
| flex-direction: column; | |
| } | |
| .nav-item { | |
| margin-left: 0; | |
| margin-top: 0.5rem; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <nav class="navbar"> | |
| <a href="#" class="navbar-brand">MCP EdTech</a> | |
| <ul class="navbar-nav"> | |
| <li class="nav-item"><a href="#" class="nav-link">Home</a></li> | |
| <li class="nav-item"><a href="#api-demo" class="nav-link">API Demo</a></li> | |
| <li class="nav-item"><a href="/docs" class="nav-link">Documentation</a></li> | |
| <li class="nav-item"><a href="#" class="nav-link">Developed by M.Habib Agrebi</a></li> | |
| </ul> | |
| </nav> | |
| <div class="container"> | |
| <div class="card"> | |
| <h1>Model Context Protocol (MCP) for EdTech</h1> | |
| <h2>Welcome to the MCP EdTech Demo</h2> | |
| <p>This demo showcases the Model Context Protocol (MCP) implementation for educational technology applications. MCP provides a standardized way for EdTech applications to interact with various AI models while maintaining context and state across interactions.</p> | |
| <h3>Key features of this implementation:</h3> | |
| <ul> | |
| <li>Context management for stateful conversations</li> | |
| <li>Student profile management</li> | |
| <li>Learning progress tracking</li> | |
| <li>Content adaptation based on student profiles</li> | |
| <li>Assessment and feedback systems</li> | |
| </ul> | |
| </div> | |
| <div id="api-demo" class="card"> | |
| <div class="card-header"> | |
| <h2>API Demo</h2> | |
| </div> | |
| <h3>Try the MCP API</h3> | |
| <p>1. Create a Context</p> | |
| <p>First, let's create a new context for our interaction:</p> | |
| <button id="createContextBtn" class="btn">Create Context</button> | |
| <div id="contextLoading" class="loading">Creating context</div> | |
| <div id="contextError" class="error-message"></div> | |
| <div id="contextSuccess" class="success-message"></div> | |
| <div id="contextResponse" class="response-area" style="display: none;"></div> | |
| <p>2. Process an Interaction</p> | |
| <p>Now, let's process an interaction using the context we created:</p> | |
| <div class="form-group"> | |
| <label for="interactionInput">Enter your question or prompt:</label> | |
| <input type="text" id="interactionInput" placeholder="e.g., Explain the concept of photosynthesis"> | |
| </div> | |
| <button id="processInteractionBtn" class="btn">Process Interaction</button> | |
| <div id="interactionLoading" class="loading">Processing interaction</div> | |
| <div id="interactionError" class="error-message"></div> | |
| <div id="interactionResponse" class="response-area" style="display: none;"></div> | |
| </div> | |
| <div class="card"> | |
| <h3>Available Endpoints</h3> | |
| <ul class="endpoints-list"> | |
| <li><strong>Interaction</strong> | |
| <ul> | |
| <li>POST /interact - Process an interaction</li> | |
| </ul> | |
| </li> | |
| <li><strong>Student Profiles</strong> | |
| <ul> | |
| <li>POST /students - Create student profile</li> | |
| <li>GET /students/{student_id} - Get student information</li> | |
| <li>PUT /students/{student_id} - Update student information</li> | |
| </ul> | |
| </li> | |
| <li><strong>Content Adaptation</strong> | |
| <ul> | |
| <li>POST /content/adapt - Adapt content for a student</li> | |
| </ul> | |
| </li> | |
| <li><strong>Models</strong> | |
| <ul> | |
| <li>GET /models - List available models</li> | |
| <li>GET /models/{model_name}/capabilities - Get model capabilities</li> | |
| </ul> | |
| </li> | |
| </ul> | |
| <p>For complete API documentation, visit the <a href="/docs">Swagger UI</a> or <a href="/redoc">ReDoc</a> pages.</p> | |
| </div> | |
| </div> | |
| <footer style="background-color: var(--primary-color); color: white; text-align: center; padding: 1rem; margin-top: 2rem;"> | |
| <p>Developed by M.Habib Agrebi</p> | |
| </footer> | |
| <script> | |
| let currentContextId = null; | |
| document.getElementById('createContextBtn').addEventListener('click', createContext); | |
| document.getElementById('processInteractionBtn').addEventListener('click', processInteraction); | |
| async function createContext() { | |
| const contextLoading = document.getElementById('contextLoading'); | |
| const contextError = document.getElementById('contextError'); | |
| const contextSuccess = document.getElementById('contextSuccess'); | |
| const contextResponse = document.getElementById('contextResponse'); | |
| contextLoading.style.display = 'block'; | |
| contextError.style.display = 'none'; | |
| contextSuccess.style.display = 'none'; | |
| contextResponse.style.display = 'none'; | |
| try { | |
| const response = await fetch('/context/create', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| metadata: { | |
| source: 'demo-ui', | |
| created_by: 'demo-user' | |
| } | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (!response.ok) { | |
| throw new Error(data.detail || 'Failed to create context'); | |
| } | |
| currentContextId = data.context_id; | |
| contextResponse.textContent = JSON.stringify(data, null, 2); | |
| contextResponse.style.display = 'block'; | |
| contextSuccess.textContent = `Context created successfully! Context ID: ${currentContextId}`; | |
| contextSuccess.style.display = 'block'; | |
| } catch (error) { | |
| contextError.textContent = `Error: ${error.message}`; | |
| contextError.style.display = 'block'; | |
| } finally { | |
| contextLoading.style.display = 'none'; | |
| } | |
| } | |
| async function processInteraction() { | |
| if (!currentContextId) { | |
| alert('Please create a context first!'); | |
| return; | |
| } | |
| const interactionInput = document.getElementById('interactionInput'); | |
| const interactionLoading = document.getElementById('interactionLoading'); | |
| const interactionError = document.getElementById('interactionError'); | |
| const interactionResponse = document.getElementById('interactionResponse'); | |
| if (!interactionInput.value.trim()) { | |
| alert('Please enter a question or prompt!'); | |
| return; | |
| } | |
| interactionLoading.style.display = 'block'; | |
| interactionError.style.display = 'none'; | |
| interactionResponse.style.display = 'none'; | |
| try { | |
| const response = await fetch('/interact', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| context_id: currentContextId, | |
| interaction_type: 'text', | |
| content: { | |
| text: interactionInput.value.trim() | |
| }, | |
| format: 'text', | |
| model_name: 'mock' | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (!response.ok) { | |
| throw new Error(data.detail || 'Failed to process interaction'); | |
| } | |
| interactionResponse.textContent = data.content.text || JSON.stringify(data, null, 2); | |
| interactionResponse.style.display = 'block'; | |
| } catch (error) { | |
| interactionError.textContent = `Error: ${error.message}`; | |
| interactionError.style.display = 'block'; | |
| } finally { | |
| interactionLoading.style.display = 'none'; | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |