mirror of
https://github.com/deepseek-ai/Janus.git
synced 2025-02-22 21:58:59 -05:00
adds a simple WebUI for the evaluation of models
This commit is contained in:
parent
bfa6c0e1c1
commit
1f83d279a1
@ -1,5 +1,6 @@
|
||||
from fastapi import FastAPI, File, Form, UploadFile, HTTPException
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
import torch
|
||||
from transformers import AutoConfig, AutoModelForCausalLM
|
||||
from janus.models import MultiModalityCausalLM, VLChatProcessor
|
||||
@ -8,7 +9,12 @@ import numpy as np
|
||||
import io
|
||||
import os
|
||||
|
||||
# Resolve absolute path based on the script's location
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # This gets "demo/"
|
||||
WEBUI_DIR = os.path.join(BASE_DIR, "webui") # Moves up to the project root
|
||||
|
||||
app = FastAPI()
|
||||
app.mount("/webui", StaticFiles(directory=WEBUI_DIR, html=True), name="webui")
|
||||
|
||||
# Load model and processor
|
||||
model_path = os.getenv("MODEL_NAME", "deepseek-ai/Janus-1.3B")
|
||||
|
164
demo/webui/APIChat.js
Normal file
164
demo/webui/APIChat.js
Normal file
@ -0,0 +1,164 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const apiUrlInput = document.getElementById('apiUrlInput');
|
||||
const dropdownButton = document.getElementById('dropdownButton');
|
||||
const dropdownMenu = document.getElementById('dropdownMenu');
|
||||
const responsesContainer = document.getElementById('responsesContainer');
|
||||
const promptInput = document.getElementById('promptInput');
|
||||
const sendButton = document.getElementById('sendButton');
|
||||
const errorMessage = document.getElementById('errorMessage');
|
||||
|
||||
const defaultApiUrl = window.location.origin + '/generate_images';
|
||||
|
||||
let apiUrl = localStorage.getItem('lastUsedUrl') || defaultApiUrl;
|
||||
let urlHistory = JSON.parse(localStorage.getItem('urlHistory')) || [];
|
||||
|
||||
// If urlHistory is empty, add the default localhost URL
|
||||
if (urlHistory.length === 0) {
|
||||
saveUrl(defaultApiUrl)
|
||||
}
|
||||
|
||||
apiUrlInput.value = apiUrl;
|
||||
updateDropdown();
|
||||
|
||||
function updateDropdown() {
|
||||
dropdownMenu.innerHTML = urlHistory.length
|
||||
? urlHistory.map(url => `<div class="dropdown-item">
|
||||
<span class="select-url">${url}</span>
|
||||
<button class="delete-button">🗑️</button>
|
||||
</div>`).join('')
|
||||
: '<div class="dropdown-item">No history</div>';
|
||||
}
|
||||
|
||||
function addMessage(sender, body, avatarUrl) {
|
||||
const messageDiv = document.createElement('div');
|
||||
messageDiv.classList.add('chat-message');
|
||||
|
||||
const avatarDiv = document.createElement('div');
|
||||
avatarDiv.classList.add('message-avatar');
|
||||
avatarDiv.innerHTML = avatarUrl ? `<img src="${avatarUrl}" alt="Avatar">` : `<div class="default-avatar">${sender[0]}</div>`;
|
||||
|
||||
const messageContent = document.createElement('div');
|
||||
messageContent.classList.add('message-content');
|
||||
|
||||
// Generate timestamp
|
||||
const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
|
||||
messageContent.innerHTML = `
|
||||
<div class="message-header">
|
||||
<span class="message-sender">${sender}</span>
|
||||
<span class="message-timestamp">${timestamp}</span>
|
||||
</div>
|
||||
<div class="message-body"></div>
|
||||
`;
|
||||
|
||||
const messageBody = messageContent.querySelector('.message-body');
|
||||
if (typeof body === 'string') {
|
||||
messageBody.textContent = body;
|
||||
} else {
|
||||
messageBody.appendChild(body);
|
||||
}
|
||||
|
||||
messageDiv.appendChild(avatarDiv);
|
||||
messageDiv.appendChild(messageContent);
|
||||
responsesContainer.appendChild(messageDiv);
|
||||
responsesContainer.scrollTop = responsesContainer.scrollHeight;
|
||||
}
|
||||
|
||||
|
||||
dropdownButton.addEventListener('click', () => {
|
||||
dropdownMenu.style.display = dropdownMenu.style.display === 'none' ? 'block' : 'none';
|
||||
});
|
||||
|
||||
dropdownMenu.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('select-url')) {
|
||||
apiUrl = e.target.textContent;
|
||||
apiUrlInput.value = apiUrl;
|
||||
saveUrl(apiUrl);
|
||||
dropdownMenu.style.display = 'none';
|
||||
} else if (e.target.classList.contains('delete-button')) {
|
||||
const parent = e.target.closest('.dropdown-item');
|
||||
const urlToDelete = parent.querySelector('.select-url').textContent;
|
||||
urlHistory = urlHistory.filter(url => url !== urlToDelete);
|
||||
localStorage.setItem('urlHistory', JSON.stringify(urlHistory));
|
||||
updateDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
apiUrlInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
apiUrl = apiUrlInput.value.trim(); // Ensure the latest value is saved
|
||||
saveUrl(apiUrl);
|
||||
}
|
||||
});
|
||||
|
||||
function saveUrl(url) {
|
||||
if (!url.trim()) return;
|
||||
|
||||
// Set the last used URL
|
||||
localStorage.setItem('lastUsedUrl', url);
|
||||
|
||||
// Add to history if it doesn't exist
|
||||
if (!urlHistory.includes(url)) {
|
||||
urlHistory.push(url);
|
||||
localStorage.setItem('urlHistory', JSON.stringify(urlHistory));
|
||||
updateDropdown();
|
||||
}
|
||||
|
||||
addMessage('System', `API URL set to: ${url}`, './system.png');
|
||||
}
|
||||
async function generateImage() {
|
||||
const prompt = promptInput.value.trim();
|
||||
if (!prompt) return;
|
||||
|
||||
addMessage('You', prompt, './user.png');
|
||||
promptInput.value = '';
|
||||
sendButton.disabled = true;
|
||||
sendButton.textContent = 'Generating...';
|
||||
errorMessage.style.display = 'none';
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.set('prompt', prompt);
|
||||
params.set('seed', Math.floor(Math.random() * 1000000).toString());
|
||||
params.set('guidance', '5');
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: params.toString(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to generate image. Status: ${response.status}, Response: ${errorText}`);
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const img = document.createElement('img');
|
||||
img.src = URL.createObjectURL(blob);
|
||||
img.style.maxWidth = '100%';
|
||||
img.style.borderRadius = '8px';
|
||||
|
||||
addMessage('AI', img, './child.jpg');
|
||||
} catch (err) {
|
||||
addMessage('System', `Error generating image: ${err.message}`, './system.png');
|
||||
errorMessage.textContent = `Error generating image: ${err.message}`;
|
||||
errorMessage.style.display = 'block';
|
||||
} finally {
|
||||
sendButton.disabled = false;
|
||||
sendButton.textContent = 'Send';
|
||||
}
|
||||
}
|
||||
|
||||
sendButton.addEventListener('click', generateImage);
|
||||
|
||||
promptInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
generateImage();
|
||||
}
|
||||
});
|
||||
});
|
BIN
demo/webui/child.jpg
Normal file
BIN
demo/webui/child.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
BIN
demo/webui/favicon.ico
Normal file
BIN
demo/webui/favicon.ico
Normal file
Binary file not shown.
304
demo/webui/index.css
Normal file
304
demo/webui/index.css
Normal file
@ -0,0 +1,304 @@
|
||||
/* Ensure full-screen, no scrolling */
|
||||
html, body {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden; /* Prevent scrolling */
|
||||
background-color: black; /* Match chat background */
|
||||
font-family: Arial, sans-serif; /* Improve readability */
|
||||
}
|
||||
|
||||
/* Chat container setup */
|
||||
.chat-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Center chat box */
|
||||
.chat-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background-color: #000;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* Response messages container */
|
||||
.responses-container {
|
||||
overflow-y: auto;
|
||||
align-items: center;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #1e1e1e;
|
||||
margin: 0 auto; /* Center horizontally */
|
||||
}
|
||||
|
||||
/* Mobile responsiveness */
|
||||
@media (max-width: 768px) {
|
||||
.chat-box {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.responses-container {
|
||||
width: 100vw; /* Full width */
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
height: calc(100vh - 120px); /* Adjust height for input and header */
|
||||
}
|
||||
}
|
||||
|
||||
/* Input container */
|
||||
.input-container {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
background-color: #242424;
|
||||
flex-shrink: 0; /* Prevent shrinking */
|
||||
}
|
||||
|
||||
/* Individual chat message */
|
||||
.chat-message {
|
||||
display: flex;
|
||||
align-items: top;
|
||||
margin-bottom: 5px;
|
||||
padding: 10px;
|
||||
word-wrap: break-word;
|
||||
position: relative; /* For positioning options popup */
|
||||
}
|
||||
|
||||
/* Show message options on hover */
|
||||
.chat-message:hover .message-options {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Avatar styling */
|
||||
.message-avatar img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.message-avatar .default-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #ccc;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Message content */
|
||||
.message-content {
|
||||
padding: 0;
|
||||
width: auto;
|
||||
max-width: 80%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Sender name */
|
||||
.message-sender {
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
color: var(--arkavo-orange, red);
|
||||
}
|
||||
|
||||
/* Timestamp */
|
||||
.message-timestamp {
|
||||
font-size: 0.8em;
|
||||
color: #888;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Message body */
|
||||
.message-body {
|
||||
background-color: #333;
|
||||
color:#eee;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Message options */
|
||||
.message-options {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: #444;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* Option button */
|
||||
.option-button {
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.option-button:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
/* Chat input field */
|
||||
.chat-input {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid #444;
|
||||
border-radius: 8px;
|
||||
resize: none;
|
||||
font-size: 1.5rem;
|
||||
margin-right: 10px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Send button */
|
||||
.send-button {
|
||||
padding: 10px 15px;
|
||||
background-color: var(--arkavo-dark-orange, red);
|
||||
color: #fff;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.send-button:hover {
|
||||
background-color: darkred;
|
||||
}
|
||||
|
||||
/* Combined input field */
|
||||
.combined-input {
|
||||
position: relative;
|
||||
align-items: center;
|
||||
font-size: 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.combined-input .chat-input {
|
||||
flex: 1;
|
||||
padding-right: 40px;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 1.5rem;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
/* Dropdown button */
|
||||
.dropdown-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 40px;
|
||||
color: #333;
|
||||
font-size: 1.5rem;
|
||||
background-color: #f0f0f0;
|
||||
border: 1px solid #ccc;
|
||||
border-left: none;
|
||||
border-radius: 0 4px 4px 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dropdown-button:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
/* Dropdown menu */
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
background: black;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
font-size: 1.5rem;
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Dropdown item */
|
||||
.dropdown-item {
|
||||
display: flex;
|
||||
font-size: 1.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
background: #333;
|
||||
color: #f0f0f0;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Delete button */
|
||||
.delete-button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.5rem;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.delete-button:hover {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
/* Scrollbar for Webkit browsers (Chrome, Edge, Safari) */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px; /* Adjust width */
|
||||
height: 8px; /* Adjust height for horizontal scrollbars */
|
||||
}
|
||||
|
||||
/* Scrollbar track (background) */
|
||||
::-webkit-scrollbar-track {
|
||||
background: #1a1a1a; /* Dark background */
|
||||
border-radius: 4px; /* Rounded corners */
|
||||
}
|
||||
|
||||
/* Scrollbar thumb (draggable handle) */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #666; /* Greyish thumb */
|
||||
border-radius: 4px; /* Rounded corners */
|
||||
transition: background 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Hover effect */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #888; /* Lighter grey on hover */
|
||||
}
|
||||
|
||||
/* Firefox Scrollbar */
|
||||
* {
|
||||
scrollbar-width: thin; /* Thinner scrollbar */
|
||||
scrollbar-color: #666 #1a1a1a; /* Thumb color, Track color */
|
||||
}
|
35
demo/webui/index.html
Normal file
35
demo/webui/index.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Chat Interface</title>
|
||||
<link rel="stylesheet" href="./index.css">
|
||||
<link rel="icon" type="image/png" href="/webui/favicon.ico">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<main class="chat-container">
|
||||
<div class="chat-box">
|
||||
<div class="input-container">
|
||||
<div class="combined-input">
|
||||
<input id="apiUrlInput" class="chat-input" type="text" placeholder="Enter API URL" style="width: 100%;">
|
||||
<button id="dropdownButton" class="dropdown-button">▼</button>
|
||||
<div id="dropdownMenu" class="dropdown-menu" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="responsesContainer" class="responses-container"></div>
|
||||
|
||||
<div class="input-container">
|
||||
<textarea id="promptInput" class="chat-input" placeholder="Enter your prompt for image generation" rows="3"></textarea>
|
||||
<button id="sendButton" class="send-button">Send</button>
|
||||
</div>
|
||||
<div id="errorMessage" class="error-message" style="display: none;"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script type="text/javascript" src="./APIChat.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
demo/webui/system.png
Executable file
BIN
demo/webui/system.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
demo/webui/user.png
Normal file
BIN
demo/webui/user.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Loading…
Reference in New Issue
Block a user