Implement file upload and chunked upload support for /api/analyze

- Modified /api/analyze to accept file uploads for all users
- Restricted file_path parameter to admin users only
- Added chunked file upload support with upload_id, chunk_number, total_chunks
- Updated API documentation with file upload examples and chunked upload guide
- Files are temporarily stored and cleaned up after processing
parent 860b19cb
...@@ -257,29 +257,96 @@ ...@@ -257,29 +257,96 @@
<span class="param-type">string (optional)</span> <span class="param-type">string (optional)</span>
<div class="param-desc">Analysis prompt (default: "Describe this image.")</div> <div class="param-desc">Analysis prompt (default: "Describe this image.")</div>
</div> </div>
<div class="param-item">
<span class="param-name">file</span>
<span class="param-type">file upload (required*)</span>
<div class="param-desc">Media file to upload and analyze</div>
</div>
<div class="param-item"> <div class="param-item">
<span class="param-name">file_path</span> <span class="param-name">file_path</span>
<span class="param-type">string (required)</span> <span class="param-type">string (admin only)</span>
<div class="param-desc">Path to the media file to analyze</div> <div class="param-desc">Path to existing media file on server (admin users only)</div>
</div> </div>
<div class="param-item"> <div class="param-item">
<span class="param-name">interval</span> <span class="param-name">interval</span>
<span class="param-type">integer (optional)</span> <span class="param-type">integer (optional)</span>
<div class="param-desc">Frame sampling interval for videos (default: 10)</div> <div class="param-desc">Frame sampling interval for videos (default: 10)</div>
</div> </div>
<div class="param-item">
<span class="param-name">upload_id</span>
<span class="param-type">string (optional)</span>
<div class="param-desc">Unique identifier for chunked uploads</div>
</div>
<div class="param-item">
<span class="param-name">chunk_number</span>
<span class="param-type">integer (optional)</span>
<div class="param-desc">Current chunk number (0-based) for chunked uploads</div>
</div>
<div class="param-item">
<span class="param-name">total_chunks</span>
<span class="param-type">integer (optional)</span>
<div class="param-desc">Total number of chunks for chunked uploads</div>
</div>
<div class="param-item">
<span class="param-name">filename</span>
<span class="param-type">string (optional)</span>
<div class="param-desc">Original filename for chunked uploads</div>
</div>
</div>
<div class="alert alert-info" style="margin-top: 1rem; padding: 0.75rem; background: #dbeafe; border: 1px solid #93c5fd; border-radius: 6px;">
<i class="fas fa-info-circle" style="color: #2563eb;"></i>
<strong style="color: #1e40af;">Note:</strong> Either <code>file</code> upload or <code>file_path</code> (admin only) must be provided. Chunked uploads are supported for large files.
</div> </div>
</div> </div>
<div class="curl-section"> <div class="curl-section">
<h4><i class="fas fa-terminal"></i> Curl Example</h4> <h4><i class="fas fa-terminal"></i> Curl Examples</h4>
<h5>File Upload:</h5>
<div class="code-block">curl -X POST -H "Authorization: Bearer YOUR_API_TOKEN" \ <div class="code-block">curl -X POST -H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \ -F "model_path=Qwen/Qwen2.5-VL-7B-Instruct" \
-d '{ -F "prompt=Describe this video" \
"model_path": "Qwen/Qwen2.5-VL-7B-Instruct", -F "interval=30" \
"prompt": "Describe this video", -F "file=@/path/to/video.mp4" \
"file_path": "/path/to/video.mp4", {{ request.host_url }}api/analyze</div>
"interval": 30
}' {{ request.host_url }}api/analyze</div> <h5 style="margin-top: 1rem;">File Path (Admin Only):</h5>
<div class="code-block">curl -X POST -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-F "model_path=Qwen/Qwen2.5-VL-7B-Instruct" \
-F "prompt=Describe this video" \
-F "file_path=/server/path/to/video.mp4" \
-F "interval=30" \
{{ request.host_url }}api/analyze</div>
<h5 style="margin-top: 1rem;">Chunked Upload:</h5>
<div class="code-block"># Upload file in chunks (useful for large files)
# First chunk
curl -X POST -H "Authorization: Bearer YOUR_API_TOKEN" \
-F "upload_id=my_upload_123" \
-F "chunk_number=0" \
-F "total_chunks=3" \
-F "filename=large_video.mp4" \
-F "file=@chunk_0.mp4" \
{{ request.host_url }}api/analyze
# Second chunk
curl -X POST -H "Authorization: Bearer YOUR_API_TOKEN" \
-F "upload_id=my_upload_123" \
-F "chunk_number=1" \
-F "total_chunks=3" \
-F "filename=large_video.mp4" \
-F "file=@chunk_1.mp4" \
{{ request.host_url }}api/analyze
# Final chunk (triggers analysis)
curl -X POST -H "Authorization: Bearer YOUR_API_TOKEN" \
-F "upload_id=my_upload_123" \
-F "chunk_number=2" \
-F "total_chunks=3" \
-F "filename=large_video.mp4" \
-F "model_path=Qwen/Qwen2.5-VL-7B-Instruct" \
-F "prompt=Describe this video" \
-F "file=@chunk_2.mp4" \
{{ request.host_url }}api/analyze</div>
</div> </div>
<div class="response-section"> <div class="response-section">
......
...@@ -118,19 +118,88 @@ def api_analyze(): ...@@ -118,19 +118,88 @@ def api_analyze():
return json.dumps({'error': 'Insufficient tokens'}), 402 return json.dumps({'error': 'Insufficient tokens'}), 402
# Process analysis request # Process analysis request
model_path = request.json.get('model_path', 'Qwen/Qwen2.5-VL-7B-Instruct') model_path = request.form.get('model_path', 'Qwen/Qwen2.5-VL-7B-Instruct')
prompt = request.json.get('prompt', 'Describe this image.') prompt = request.form.get('prompt', 'Describe this image.')
file_path = request.json.get('file_path') interval = int(request.form.get('interval', 10))
interval = request.json.get('interval', 10)
# Handle file upload
if not file_path: uploaded_file = request.files.get('file')
return json.dumps({'error': 'file_path is required'}), 400 file_path = request.form.get('file_path')
# Check permissions for file_path usage
if file_path and user.get('role') != 'admin':
return json.dumps({'error': 'file_path parameter is only available to admin users'}), 403
media_path = None
if uploaded_file and uploaded_file.filename:
# Handle chunked upload
chunk_number = request.form.get('chunk_number')
total_chunks = request.form.get('total_chunks')
upload_id = request.form.get('upload_id', f"user_{user['id']}_upload")
if chunk_number is not None and total_chunks is not None:
# Handle chunked upload
import os
import tempfile
chunk_dir = os.path.join(tempfile.gettempdir(), 'vidai_chunks', upload_id)
os.makedirs(chunk_dir, exist_ok=True)
chunk_number = int(chunk_number)
total_chunks = int(total_chunks)
# Save chunk
chunk_path = os.path.join(chunk_dir, f'chunk_{chunk_number:04d}')
uploaded_file.save(chunk_path)
# Check if all chunks received
received_chunks = len([f for f in os.listdir(chunk_dir) if f.startswith('chunk_')])
if received_chunks == total_chunks:
# Reassemble file
final_filename = request.form.get('filename', uploaded_file.filename)
media_path = os.path.join(tempfile.gettempdir(), f'vidai_complete_{upload_id}_{final_filename}')
with open(media_path, 'wb') as final_file:
for i in range(total_chunks):
chunk_path = os.path.join(chunk_dir, f'chunk_{i:04d}')
with open(chunk_path, 'rb') as chunk_file:
final_file.write(chunk_file.read())
# Clean up chunks
import shutil
shutil.rmtree(chunk_dir)
return json.dumps({
'status': 'upload_complete',
'message': 'File upload completed, starting analysis...'
})
else:
return json.dumps({
'status': 'chunk_received',
'chunks_received': received_chunks,
'total_chunks': total_chunks
})
else:
# Handle regular file upload
import tempfile
import os
with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded_file.filename)[1]) as tmp:
uploaded_file.save(tmp.name)
media_path = tmp.name
elif file_path:
# Handle file path (admin only)
if not os.path.exists(file_path):
return json.dumps({'error': 'File not found'}), 404
media_path = file_path
else:
return json.dumps({'error': 'Either file upload or file_path (admin only) is required'}), 400
# Send to backend for processing # Send to backend for processing
data = { data = {
'model_path': model_path, 'model_path': model_path,
'prompt': prompt, 'prompt': prompt,
'local_path': file_path, 'local_path': media_path,
'interval': interval, 'interval': interval,
'user_id': user['id'] 'user_id': user['id']
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment