Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io
from dotenv import load_dotenv
import os
from datetime import datetime

from google import genai

Expand All @@ -26,6 +27,7 @@

next_message = ""
next_image = ""
current_file_info = None


def allowed_file(filename):
Expand All @@ -39,7 +41,7 @@ def upload_file():
"""Takes in a file, checks if it is valid,
and saves it for the next request to the API
"""
global next_image
global next_image, current_file_info

if "file" not in request.files:
return jsonify(success=False, message="No file part")
Expand All @@ -56,6 +58,15 @@ def upload_file():
file_stream.seek(0)
next_image = Image.open(file_stream)

# Store file info
current_file_info = {
"filename": filename,
"size": len(file_stream.getvalue()),
"upload_time": datetime.now().strftime("%Y-%m-%d %H:%M"),
"mime_type": file.content_type,
"has_file": True
}

return jsonify(
success=True,
message="File uploaded successfully and added to the conversation",
Expand Down Expand Up @@ -92,11 +103,13 @@ def stream():
def generate():
global next_message
global next_image
global current_file_info
assistant_response_content = ""

if next_image != "":
response = chat_session.send_message_stream([next_message, next_image])
next_image = ""
current_file_info = None
else:
response = chat_session.send_message_stream(next_message)
next_message = ""
Expand All @@ -107,3 +120,26 @@ def generate():

return Response(stream_with_context(generate()),
mimetype="text/event-stream")

@app.route("/get_files", methods=["GET"])
def get_files():
"""Get current file info"""
global current_file_info, next_image

if next_image != "" and current_file_info: # if there is a file, return the file info
return jsonify({
"success": True,
"has_file": True,
"file": {
"filename": current_file_info["filename"],
"size": current_file_info["size"],
"upload_time": current_file_info["upload_time"],
"mime_type": current_file_info["mime_type"]
}
})
else: # if there is no file, return None
return jsonify({
"success": True,
"has_file": False,
"file": None
})
58 changes: 53 additions & 5 deletions static/event-listener.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
// Format file size
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];
}

// Display file info
function populateFiles(data) {
const currentFileItem = document.querySelector('.current-file-item');
const uploadPrompt = document.querySelector('.centered-text');

if (data.has_file && data.file) {
// Display current file info
const file = data.file;

// Update file info
currentFileItem.querySelector('.file-name').textContent = file.filename;
currentFileItem.querySelector('.file-size').textContent = formatFileSize(file.size);
currentFileItem.querySelector('.file-time').textContent = file.upload_time;

// Display file item, hide upload prompt
currentFileItem.style.display = 'flex';
uploadPrompt.style.display = 'none';
} else {
// Display upload prompt when no file
currentFileItem.style.display = 'none';
uploadPrompt.style.display = 'block';
}
}

function refreshFileDisplay() {
fetch('/get_files')
.then(response => response.json())
.then(data => {
if (data.success) {
populateFiles(data);
}
})
.catch(error => {
console.error('Failed to get file info:', error);
});
}

// Refresh file display when page loads
document.addEventListener('DOMContentLoaded', function() {
refreshFileDisplay();
});

document.getElementById("file-upload").addEventListener("change", function (event) {
const file = event.target.files[0];
if (!file) {
Expand All @@ -23,11 +74,8 @@ document.getElementById("file-upload").addEventListener("change", function (even
banner.style.display = "none";
}, 3000);

fetch("/get_files")
.then((response) => response.json())
.then((data) => {
populateFiles(data.assistant_files);
});
// Refresh file display
refreshFileDisplay();
} else {
console.error("Upload failed:", data.message);
// Update and show the banner
Expand Down
48 changes: 48 additions & 0 deletions static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,51 @@ body::after {
border-top: 1px solid #ececf1;
width: 100%;
}

.current-file-container {
margin-top: 12px;
}

.current-file-item {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 12px;
background-color: #f8f9ff;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}

.file-info {
display: flex;
align-items: center;
gap: 12px;
}

.file-icon {
font-size: 24px;
}

.file-details {
display: flex;
flex-direction: column;
gap: 4px;
}

.file-name {
font-weight: 500;
color: #333;
font-size: 14px;
}

.file-size, .file-time {
font-size: 12px;
color: #666;
}

.status-indicator {
color: #4285f4;
font-weight: 500;
font-size: 14px;
}
17 changes: 16 additions & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,22 @@
<div class="demo-text">Demo</div>
</div>
<div id="filesList">
<p id="filesPlaceholder" class="hidden">Files</p>
<div class="current-file-container">
<!-- Current file info -->
<div class="current-file-item" style="display: none;">
<div class="file-info">
<div class="file-icon">📷</div>
<div class="file-details">
<span class="file-name">image.jpg</span>
<span class="file-size">1.0 MB</span>
<span class="file-time">2024-01-01 12:00</span>
</div>
</div>
<div class="file-status">
<span class="status-indicator">✓ Uploaded</span>
</div>
</div>
</div>
</div>
<div class="centered-text">
<svg width="39" height="38" viewBox="0 0 39 38" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down