Skip to content

Commit

Permalink
File Upload & Assistant Integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Zaki-1052 committed Feb 29, 2024
1 parent e020bda commit 2b01c92
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 38 deletions.
16 changes: 14 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ USER_USERNAME=Username
USER_PASSWORD=Password
GOOGLE_API_KEY=your_google_ai_key_here
MISTRAL_API_KEY=your_mistral_ai_key_here

# Uncomment (remove the '#') from the following lines
# if you'd like to reuse an existing assistant or thread!

###

# ASSISTANT_ID=your_assistant_id_here
# THREAD_ID=your_thread_id_here

###

PORT=3000
HOST=localhost

# Remember to either rename this file to `.env`
# or create a new `.env` file with these variables.
# An OpenAI Key is required for GPT; if unchanged,
Expand All @@ -13,5 +27,3 @@ MISTRAL_API_KEY=your_mistral_ai_key_here
# The Google API Key is only required if using Gemini.
# The Gemini models will simply fail to respond if left blank.
# The same applies for the Mistral API.
PORT=3000
HOST=localhost
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -652,12 +652,17 @@ Now, let's say for the second request, you include the initial request and respo
- [x] Audio
- [x] Model Switching
- [ ] Implement RAG
- [x] Flask
- [ ] Vectors
- [ ] Embeddings
- [ ] Function Calling
- [x] Update ReadMe for Release
- [x] Add Demo Video
- [x] Added Mistral APIs
- [x] File Uploads
- [x] Integrate Assistants
- [x] Refactor
- [ ] Write Docs
### Quick-Start Guide
Expand Down
15 changes: 15 additions & 0 deletions public/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,21 @@ body {
cursor: pointer;
}

#mode-selector {
text-align: center; /* Center align the container */
padding: 6px; /* Add some padding */
margin-bottom: 70px; /* Space before the chat container */
padding: 10px; /* Padding inside the selector */
border-radius: 5px; /* Rounded corners */
border: 1px solid #5f6368; /* Border color */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Shadow effect */
align-content: center; /* Center align the container */
display: block; /* Ensure it's a block-level element */
width: 10%; /* Or any specific width */
margin-left: auto;
margin-right: auto;
}

.select-options {
display: none;
position: absolute;
Expand Down
2 changes: 1 addition & 1 deletion public/geminiMessage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ You act as a helpful, friendly, talented, and intelligent AI assistant, knowledg
You can generate text, translate languages, write different kinds of creative content, and answer questions in an informative manner.
The user provided the following information about themselves:
[This field is currently empty.]
The date is February 2024.
The date is March 2024.
Follow the user's instructions at all times and thoughtfully complete all requests while remaining creative and personable.
You will use your knowledge to answer questions in a comprehensive and informative way, even if they are open ended, challenging, or strange.
You will generate different creative text formats of text content, like poems, code, scripts, musical pieces, email, letters, etc.
Expand Down
2 changes: 1 addition & 1 deletion public/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## You are **GPT-4**, an advanced *Large Language Model* trained by *OpenAI*

- Knowledge cutoff: 2023-04
- Current date: 2024-02
- Current date: 2024-03
- Image input capabilities: **Enabled**

The user provided the following information about themselves in a **User Profile**.
Expand Down
4 changes: 3 additions & 1 deletion public/portal.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
</head>
<body>
<div>
<div id="model-selector-container">
<div class="custom-select" id="selected-model">Select a Model</div>
<div id="model-options" class="select-options">
Expand Down Expand Up @@ -42,13 +43,14 @@
</div>
<textarea id="message-input" placeholder="Type your message here..."></textarea>
<button type="button" id="clipboard-button">📸</button>
<input type="file" id="file-input" accept="image/*"/>
<input type="file" id="file-input" accept="*/*"/>
<button type="button" id="export-button">📤</button>
<button type="button" id="voice-button">🎤</button>
<div id="voice-indicator">Voice Mode ON</div>
<button id="send-button">Send</button>
<div id="upload-status"></div>
</div>
<div class="custom-select" id="mode-selector">Assistants Mode</div>
<script src="script.js"></script>
</body>
</html>
133 changes: 113 additions & 20 deletions public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ fetchConfig();
}

let isGemini = false;
let assistantsMode = false;
let isAssistants = false;


const modelID = {
Expand Down Expand Up @@ -271,15 +273,38 @@ document.querySelector('.custom-select').addEventListener('click', toggleDropdow
}
}


// Toggle Assistants Mode on clicking the custom-select div
document.getElementById('mode-selector').addEventListener('click', () => {
// Toggle assistantsMode
assistantsMode = !assistantsMode;

// Update the visual indicator for Assistants Mode
const modeSelectorDiv = document.getElementById('mode-selector');
if (assistantsMode) {
modeSelectorDiv.style.backgroundColor = '#4CAF50'; // Example: change background to green
modeSelectorDiv.textContent = 'Assistants Mode ON'; // Update text to indicate mode is on
isAssistants = true;
currentModelID = 'gpt-4-turbo-preview';
} else {
modeSelectorDiv.style.backgroundColor = ''; // Reset background
modeSelectorDiv.textContent = 'Assistants Mode'; // Reset text
isAssistants = false;
}

console.log("Assistants Mode:", assistantsMode); // For debugging
});


function determineEndpoint(modelID) {
if (modelID.startsWith('gemini')) {
isGemini = true;
return `${baseURL}/gemini`; // URL for the Gemini endpoint
} if (assistantsMode = true) {
isAssistants = true;
return `${baseURL}/assistant`;
} else {
isGemini = false;
isAssistants = false;
return `${baseURL}/message`; // URL for the OpenAI endpoint
}
}
Expand Down Expand Up @@ -399,21 +424,20 @@ document.getElementById('model-mistral-large').addEventListener('mouseover', (ev
// Result of Send Button
sendButton.addEventListener('click', async () => {
const message = messageInput.value.trim();
const user_image = document.getElementById('file-input').files[0];
messageInput.value = '';

// Get the selected model's display name and convert it to the actual model ID
setDefaultModel(); // Update default model if needed

if (message || user_image) {
if (message) {
displayMessage(message, 'user');
// Check if it's an image generation request
if (isImageGenerationRequest(message)) {
await handleImageGenerationRequest(message);
} else {
// Existing code to handle regular messages
try {
await sendMessageToServer(message, user_image); // Pass the message, image file, and model to the server
await sendMessageToServer(message); // Pass the message, image file, and model to the server
if (voiceMode) {
// Call to TTS API to read the response
// This will be implemented in the displayMessage function
Expand All @@ -436,7 +460,16 @@ sendButton.addEventListener('click', async () => {

// Function to export chat history based on the type (conversation or gemini)
function exportChatHistory() {
const historyType = isGemini ? 'gemini' : 'conversation';
// Determine the history type based on isGemini and isAssistants flags
let historyType;
if (isGemini) {
historyType = 'gemini';
} else if (isAssistants) {
historyType = 'assistants';
} else {
historyType = 'conversation';
}

console.log("Exporting chat history for:", historyType);
const exportUrl = '/export-chat-html?type=' + historyType;
fetch(exportUrl)
Expand All @@ -456,7 +489,14 @@ sendButton.addEventListener('click', async () => {

// Modify exportChatOnShutdown to use the isGemini flag
function exportChatOnShutdown() {
const historyType = isGemini ? 'gemini' : 'conversation';
let historyType;
if (isGemini) {
historyType = 'gemini';
} else if (isAssistants) {
historyType = 'assistants';
} else {
historyType = 'conversation';
}
exportChatHistory(historyType);
}

Expand Down Expand Up @@ -591,17 +631,41 @@ function exportChatOnShutdown() {
// END

// Functions for handling image input files

let fileId;
// Placeholder function for clipboard button (to be implemented)
document.getElementById('clipboard-button').addEventListener('click', () => {
document.getElementById('file-input').click(); // Trigger file input
});
document.getElementById('file-input').addEventListener('change', handleFileSelect, false);

function handleFileSelect(event) {
const file = event.target.files[0];
selectedImage = file;
document.getElementById('file-input').addEventListener('change', async (event) => {
let file = event.target.files[0];
// Check if the file is an image by looking at its MIME type
if (file && file.type.startsWith('image/')) {
selectedImage = file; // If it's an image, set it as the selectedImage
file = null;
} else if (file) {
fileUrl = await uploadFile(file);
}
});

async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);

try {
const response = await fetch(`${baseURL}/upload-file`, {
method: 'POST',
body: formData,
});
const data = await response.json();
return data.fileId; // Update according to the actual response structure
} catch (error) {
console.error('Error uploading file:', error);
// Handle error appropriately
}
}



// Defining the messages sent

Expand Down Expand Up @@ -638,20 +702,45 @@ async function uploadImageAndGetUrl(imageFile) {

// Send the message to the server and handle the response

async function sendMessageToServer(message) {
let initialize = false;
let messageCounter = 0;
let file;
let fileUrl;

async function sendMessageToServer(message) {
let imageUrl = null;
let imageFilename = null;
if (selectedImage) {
imageUrl = await uploadImageAndGetUrl(selectedImage);
// Extract filename from the imageUrl
imageFilename = imageUrl.split('/').pop();
}
if (file) {
// If it's not an image, treat it as a different type of file
fileUrl = await uploadFile(file); // Assume uploadFile is a function similar to uploadImageAndGetUrl for handling other files
// Extract filename from the fileUrl if necessary
const filename = fileUrl.split('/').pop();
// Proceed with any additional logic needed after the file upload
}

const instructions = await fetchInstructions();

// Prepare the payload with the current model ID
let payload, endpoint;
const instructions = await fetchInstructions();
if (isAssistants === true) {
if (messageCounter === 0) {
isFirstMessage = true
messageCounter +=1
} else {
isFirstMessage = false;
}
payload = {
message: message,
modelID: currentModelID,
instructions: instructions,
file: fileUrl, // Existing image handling for OpenAI
initialize: isFirstMessage
};
endpoint = 'http://localhost:3000/assistant'; // OpenAI endpoint
} else {
if (currentModelID.startsWith('gemini')) {
// Prepare the payload for Google Gemini API
payload = {
Expand All @@ -666,11 +755,12 @@ async function uploadImageAndGetUrl(imageFile) {
message: message,
modelID: currentModelID,
instructions: instructions,
image: imageUrl // Existing image handling for OpenAI
image: imageUrl, // Existing image handling for OpenAI
file: fileUrl
};
endpoint = `${baseURL}/message`; // OpenAI endpoint
}

}
try {
const response = await fetch(endpoint, {
method: 'POST',
Expand All @@ -692,6 +782,8 @@ async function uploadImageAndGetUrl(imageFile) {
if (endpoint.includes('gemini')) {
// Direct text response from Gemini API
messageContent = data.text || 'No response received.';
} else if (endpoint.includes('assistant')) {
messageContent = data.text.text || 'No response received.';
} else {
// Response from GPT API, expected to have a 'text' property
messageContent = data.text || 'No response received.';
Expand Down Expand Up @@ -724,6 +816,7 @@ async function uploadImageAndGetUrl(imageFile) {
}



// code for showing the message and speaking it

// Display the message in the chat box
Expand Down Expand Up @@ -823,9 +916,9 @@ function updateUploadStatus(message) {
// Modifying handleFileSelect function to include upload status update
document.getElementById('file-input').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file && file.type.startsWith('image/')) {
updateUploadStatus('Image Uploaded: ' + file.name);
if (file) { // Removed the type check for demonstration purposes
updateUploadStatus('File Uploaded: ' + file.name);
} else {
updateUploadStatus('No image selected');
updateUploadStatus('No file selected or unsupported file type');
}
});
Loading

0 comments on commit 2b01c92

Please sign in to comment.