Update app.py
Browse files
app.py
CHANGED
|
@@ -6,6 +6,7 @@ import os
|
|
| 6 |
import io
|
| 7 |
import httpx
|
| 8 |
import uuid
|
|
|
|
| 9 |
from datetime import datetime, timezone, timedelta
|
| 10 |
from dotenv import load_dotenv
|
| 11 |
import json
|
|
@@ -330,7 +331,7 @@ HTML_TEMPLATE = """
|
|
| 330 |
<div class="container">
|
| 331 |
<div class="header">
|
| 332 |
<h1>📚 Smart Document Analysis Platform</h1>
|
| 333 |
-
<p>Upload substantial PDF documents
|
| 334 |
<p style="font-size: 0.9em; opacity: 0.8; margin-top: 5px;">💡 Context caching requires minimum token thresholds - larger documents work better</p>
|
| 335 |
</div>
|
| 336 |
|
|
@@ -467,7 +468,7 @@ HTML_TEMPLATE = """
|
|
| 467 |
document.getElementById('cacheId').textContent = result.cache_id;
|
| 468 |
document.getElementById('tokenCount').textContent = result.token_count;
|
| 469 |
document.getElementById('documentName').textContent = result.document_name;
|
| 470 |
-
document.getElementById('modelUsed').textContent = result.model_used || 'gemini-2.
|
| 471 |
document.getElementById('cacheInfo').style.display = 'block';
|
| 472 |
showSuccess('PDF uploaded and cached successfully!');
|
| 473 |
|
|
@@ -511,7 +512,7 @@ HTML_TEMPLATE = """
|
|
| 511 |
document.getElementById('cacheId').textContent = result.cache_id;
|
| 512 |
document.getElementById('tokenCount').textContent = result.token_count;
|
| 513 |
document.getElementById('documentName').textContent = result.document_name;
|
| 514 |
-
document.getElementById('modelUsed').textContent = result.model_used || 'gemini-2.
|
| 515 |
document.getElementById('cacheInfo').style.display = 'block';
|
| 516 |
showSuccess('PDF uploaded and cached successfully!');
|
| 517 |
|
|
@@ -652,48 +653,39 @@ def upload_file():
|
|
| 652 |
# Warn about small files that might not cache
|
| 653 |
if file_size < 1024 * 1024: # Less than 1MB
|
| 654 |
print(f"Warning: Small file uploaded ({file_size_mb:.1f}MB). May not meet minimum token requirements for caching.")
|
| 655 |
-
|
| 656 |
# Read file content
|
| 657 |
file_content = file.read()
|
| 658 |
if not file_content:
|
| 659 |
return jsonify({'success': False, 'error': 'File is empty'})
|
| 660 |
|
| 661 |
-
|
|
|
|
| 662 |
|
| 663 |
-
# Upload to Gemini File API
|
| 664 |
try:
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
temp_file_path = temp_file.name
|
| 670 |
-
|
| 671 |
-
# Upload using file path
|
| 672 |
-
document = client.files.upload(path=temp_file_path)
|
| 673 |
print(f"Document uploaded successfully: {document.name}")
|
| 674 |
-
|
| 675 |
-
# Clean up temporary file
|
| 676 |
-
import os
|
| 677 |
-
os.unlink(temp_file_path)
|
| 678 |
-
|
| 679 |
except Exception as upload_error:
|
| 680 |
print(f"Upload error: {upload_error}")
|
| 681 |
return jsonify({'success': False, 'error': f'Failed to upload file to Gemini: {str(upload_error)}'})
|
| 682 |
|
| 683 |
-
# Create cache with system instruction
|
| 684 |
try:
|
| 685 |
system_instruction = "You are an expert document analyzer. Provide detailed, accurate answers based on the uploaded document content. Always be helpful and thorough in your responses."
|
| 686 |
|
| 687 |
-
# Use the
|
| 688 |
-
|
| 689 |
|
|
|
|
| 690 |
cache = client.caches.create(
|
| 691 |
-
model=
|
| 692 |
config=types.CreateCachedContentConfig(
|
| 693 |
-
display_name=f'PDF document cache - {file.filename}',
|
| 694 |
system_instruction=system_instruction,
|
| 695 |
-
contents=[document],
|
| 696 |
-
ttl="3600s", # 1 hour TTL
|
| 697 |
)
|
| 698 |
)
|
| 699 |
|
|
@@ -730,50 +722,9 @@ def upload_file():
|
|
| 730 |
if "too small" in error_msg or "minimum" in error_msg:
|
| 731 |
return jsonify({
|
| 732 |
'success': False,
|
| 733 |
-
'error': f'Document content is insufficient for caching. Gemini
|
| 734 |
-
'suggestion': 'Upload a longer document with more text content (recommended: 5MB+ with substantial text).'
|
| 735 |
-
'fallback': 'You can still use the document without caching by implementing direct file processing.'
|
| 736 |
})
|
| 737 |
-
elif "invalid" in error_msg or "model" in error_msg:
|
| 738 |
-
# Try fallback to 2.0 Flash
|
| 739 |
-
try:
|
| 740 |
-
cache_fallback = client.caches.create(
|
| 741 |
-
model='gemini-2.0-flash-001',
|
| 742 |
-
config=types.CreateCachedContentConfig(
|
| 743 |
-
display_name=f'PDF document cache - {file.filename}',
|
| 744 |
-
system_instruction=system_instruction,
|
| 745 |
-
contents=[document],
|
| 746 |
-
ttl="3600s",
|
| 747 |
-
)
|
| 748 |
-
)
|
| 749 |
-
print(f"Fallback cache created with 2.0 Flash: {cache_fallback.name}")
|
| 750 |
-
|
| 751 |
-
# Store with fallback model info
|
| 752 |
-
cache_id = str(uuid.uuid4())
|
| 753 |
-
document_caches[cache_id] = {
|
| 754 |
-
'cache_name': cache_fallback.name,
|
| 755 |
-
'document_name': file.filename,
|
| 756 |
-
'document_file_name': document.name,
|
| 757 |
-
'model': 'gemini-2.0-flash-001',
|
| 758 |
-
'created_at': datetime.now().isoformat()
|
| 759 |
-
}
|
| 760 |
-
|
| 761 |
-
token_count = 'Unknown'
|
| 762 |
-
if hasattr(cache_fallback, 'usage_metadata') and cache_fallback.usage_metadata:
|
| 763 |
-
if hasattr(cache_fallback.usage_metadata, 'total_token_count'):
|
| 764 |
-
token_count = cache_fallback.usage_metadata.total_token_count
|
| 765 |
-
|
| 766 |
-
return jsonify({
|
| 767 |
-
'success': True,
|
| 768 |
-
'cache_id': cache_id,
|
| 769 |
-
'token_count': token_count,
|
| 770 |
-
'document_name': file.filename,
|
| 771 |
-
'model_used': 'gemini-2.0-flash-001'
|
| 772 |
-
})
|
| 773 |
-
|
| 774 |
-
except Exception as fallback_error:
|
| 775 |
-
print(f"Fallback cache error: {fallback_error}")
|
| 776 |
-
return jsonify({'success': False, 'error': f'Failed to create cache with both models: {str(fallback_error)}'})
|
| 777 |
else:
|
| 778 |
return jsonify({'success': False, 'error': f'Failed to create cache: {str(cache_error)}'})
|
| 779 |
|
|
@@ -812,8 +763,6 @@ def upload_from_url():
|
|
| 812 |
if content_length < 1024 * 1024: # Less than 1MB
|
| 813 |
print(f"Warning: Small file from URL ({content_length_mb:.1f}MB). May not meet minimum token requirements for caching.")
|
| 814 |
|
| 815 |
-
file_io = io.BytesIO(response.content)
|
| 816 |
-
|
| 817 |
except httpx.TimeoutException:
|
| 818 |
return jsonify({'success': False, 'error': 'Request timeout. Please try a different URL.'})
|
| 819 |
except httpx.HTTPError as e:
|
|
@@ -824,41 +773,33 @@ def upload_from_url():
|
|
| 824 |
if not filename.endswith('.pdf'):
|
| 825 |
filename += '.pdf'
|
| 826 |
|
| 827 |
-
#
|
|
|
|
|
|
|
|
|
|
| 828 |
try:
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as temp_file:
|
| 834 |
-
temp_file.write(response.content)
|
| 835 |
-
temp_file_path = temp_file.name
|
| 836 |
-
|
| 837 |
-
# Upload using file path
|
| 838 |
-
document = client.files.upload(path=temp_file_path)
|
| 839 |
print(f"Document uploaded successfully: {document.name}")
|
| 840 |
-
|
| 841 |
-
# Clean up temporary file
|
| 842 |
-
os.unlink(temp_file_path)
|
| 843 |
-
|
| 844 |
except Exception as upload_error:
|
| 845 |
print(f"Upload error: {upload_error}")
|
| 846 |
return jsonify({'success': False, 'error': f'Failed to upload file to Gemini: {str(upload_error)}'})
|
| 847 |
|
| 848 |
-
# Create cache with system instruction
|
| 849 |
try:
|
| 850 |
system_instruction = "You are an expert document analyzer. Provide detailed, accurate answers based on the uploaded document content. Always be helpful and thorough in your responses."
|
| 851 |
|
| 852 |
-
# Use the
|
| 853 |
-
|
| 854 |
|
|
|
|
| 855 |
cache = client.caches.create(
|
| 856 |
-
model=
|
| 857 |
config=types.CreateCachedContentConfig(
|
| 858 |
-
display_name=f'PDF document cache - {filename}',
|
| 859 |
system_instruction=system_instruction,
|
| 860 |
-
contents=[document],
|
| 861 |
-
ttl="3600s", # 1 hour TTL
|
| 862 |
)
|
| 863 |
)
|
| 864 |
|
|
@@ -869,7 +810,6 @@ def upload_from_url():
|
|
| 869 |
document_caches[cache_id] = {
|
| 870 |
'cache_name': cache.name,
|
| 871 |
'document_name': filename,
|
| 872 |
-
'document_file_name': document.name,
|
| 873 |
'source_url': url,
|
| 874 |
'created_at': datetime.now().isoformat()
|
| 875 |
}
|
|
@@ -891,12 +831,13 @@ def upload_from_url():
|
|
| 891 |
|
| 892 |
except Exception as cache_error:
|
| 893 |
print(f"Cache error: {cache_error}")
|
| 894 |
-
#
|
| 895 |
-
|
|
|
|
| 896 |
return jsonify({
|
| 897 |
'success': False,
|
| 898 |
-
'error': '
|
| 899 |
-
'suggestion': 'Try
|
| 900 |
})
|
| 901 |
else:
|
| 902 |
return jsonify({'success': False, 'error': f'Failed to create cache: {str(cache_error)}'})
|
|
@@ -923,7 +864,7 @@ def ask_question():
|
|
| 923 |
# Generate response using cached content with correct model format
|
| 924 |
try:
|
| 925 |
response = client.models.generate_content(
|
| 926 |
-
model=
|
| 927 |
contents=question,
|
| 928 |
config=types.GenerateContentConfig(
|
| 929 |
cached_content=cache_info['cache_name']
|
|
|
|
| 6 |
import io
|
| 7 |
import httpx
|
| 8 |
import uuid
|
| 9 |
+
import tempfile
|
| 10 |
from datetime import datetime, timezone, timedelta
|
| 11 |
from dotenv import load_dotenv
|
| 12 |
import json
|
|
|
|
| 331 |
<div class="container">
|
| 332 |
<div class="header">
|
| 333 |
<h1>📚 Smart Document Analysis Platform</h1>
|
| 334 |
+
<p>Upload substantial PDF documents for efficient context caching with Gemini API</p>
|
| 335 |
<p style="font-size: 0.9em; opacity: 0.8; margin-top: 5px;">💡 Context caching requires minimum token thresholds - larger documents work better</p>
|
| 336 |
</div>
|
| 337 |
|
|
|
|
| 468 |
document.getElementById('cacheId').textContent = result.cache_id;
|
| 469 |
document.getElementById('tokenCount').textContent = result.token_count;
|
| 470 |
document.getElementById('documentName').textContent = result.document_name;
|
| 471 |
+
document.getElementById('modelUsed').textContent = result.model_used || 'gemini-2.0-flash-001';
|
| 472 |
document.getElementById('cacheInfo').style.display = 'block';
|
| 473 |
showSuccess('PDF uploaded and cached successfully!');
|
| 474 |
|
|
|
|
| 512 |
document.getElementById('cacheId').textContent = result.cache_id;
|
| 513 |
document.getElementById('tokenCount').textContent = result.token_count;
|
| 514 |
document.getElementById('documentName').textContent = result.document_name;
|
| 515 |
+
document.getElementById('modelUsed').textContent = result.model_used || 'gemini-2.0-flash-001';
|
| 516 |
document.getElementById('cacheInfo').style.display = 'block';
|
| 517 |
showSuccess('PDF uploaded and cached successfully!');
|
| 518 |
|
|
|
|
| 653 |
# Warn about small files that might not cache
|
| 654 |
if file_size < 1024 * 1024: # Less than 1MB
|
| 655 |
print(f"Warning: Small file uploaded ({file_size_mb:.1f}MB). May not meet minimum token requirements for caching.")
|
| 656 |
+
|
| 657 |
# Read file content
|
| 658 |
file_content = file.read()
|
| 659 |
if not file_content:
|
| 660 |
return jsonify({'success': False, 'error': 'File is empty'})
|
| 661 |
|
| 662 |
+
# Create BytesIO from content as shown in documentation
|
| 663 |
+
doc_io = io.BytesIO(file_content)
|
| 664 |
|
| 665 |
+
# Upload to Gemini File API using the exact pattern from documentation
|
| 666 |
try:
|
| 667 |
+
document = client.files.upload(
|
| 668 |
+
file=doc_io,
|
| 669 |
+
config=dict(mime_type='application/pdf')
|
| 670 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
print(f"Document uploaded successfully: {document.name}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
except Exception as upload_error:
|
| 673 |
print(f"Upload error: {upload_error}")
|
| 674 |
return jsonify({'success': False, 'error': f'Failed to upload file to Gemini: {str(upload_error)}'})
|
| 675 |
|
| 676 |
+
# Create cache with system instruction using exact pattern from documentation
|
| 677 |
try:
|
| 678 |
system_instruction = "You are an expert document analyzer. Provide detailed, accurate answers based on the uploaded document content. Always be helpful and thorough in your responses."
|
| 679 |
|
| 680 |
+
# Use the model name format from documentation
|
| 681 |
+
model_name = "gemini-2.0-flash-001"
|
| 682 |
|
| 683 |
+
# Create cached content object exactly as shown in documentation
|
| 684 |
cache = client.caches.create(
|
| 685 |
+
model=model_name,
|
| 686 |
config=types.CreateCachedContentConfig(
|
|
|
|
| 687 |
system_instruction=system_instruction,
|
| 688 |
+
contents=[document], # Direct document reference as in docs
|
|
|
|
| 689 |
)
|
| 690 |
)
|
| 691 |
|
|
|
|
| 722 |
if "too small" in error_msg or "minimum" in error_msg:
|
| 723 |
return jsonify({
|
| 724 |
'success': False,
|
| 725 |
+
'error': f'Document content is insufficient for caching. Gemini requires minimum token thresholds. Your document: {file.filename} ({file_size_mb:.1f}MB)',
|
| 726 |
+
'suggestion': 'Upload a longer document with more text content (recommended: 5MB+ with substantial text).'
|
|
|
|
| 727 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
else:
|
| 729 |
return jsonify({'success': False, 'error': f'Failed to create cache: {str(cache_error)}'})
|
| 730 |
|
|
|
|
| 763 |
if content_length < 1024 * 1024: # Less than 1MB
|
| 764 |
print(f"Warning: Small file from URL ({content_length_mb:.1f}MB). May not meet minimum token requirements for caching.")
|
| 765 |
|
|
|
|
|
|
|
| 766 |
except httpx.TimeoutException:
|
| 767 |
return jsonify({'success': False, 'error': 'Request timeout. Please try a different URL.'})
|
| 768 |
except httpx.HTTPError as e:
|
|
|
|
| 773 |
if not filename.endswith('.pdf'):
|
| 774 |
filename += '.pdf'
|
| 775 |
|
| 776 |
+
# Create BytesIO from content as shown in documentation
|
| 777 |
+
doc_io = io.BytesIO(response.content)
|
| 778 |
+
|
| 779 |
+
# Upload to Gemini File API using the exact pattern from documentation
|
| 780 |
try:
|
| 781 |
+
document = client.files.upload(
|
| 782 |
+
file=doc_io,
|
| 783 |
+
config=dict(mime_type='application/pdf')
|
| 784 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 785 |
print(f"Document uploaded successfully: {document.name}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
except Exception as upload_error:
|
| 787 |
print(f"Upload error: {upload_error}")
|
| 788 |
return jsonify({'success': False, 'error': f'Failed to upload file to Gemini: {str(upload_error)}'})
|
| 789 |
|
| 790 |
+
# Create cache with system instruction using exact pattern from documentation
|
| 791 |
try:
|
| 792 |
system_instruction = "You are an expert document analyzer. Provide detailed, accurate answers based on the uploaded document content. Always be helpful and thorough in your responses."
|
| 793 |
|
| 794 |
+
# Use the model name format from documentation
|
| 795 |
+
model_name = "gemini-2.0-flash-001"
|
| 796 |
|
| 797 |
+
# Create cached content object exactly as shown in documentation
|
| 798 |
cache = client.caches.create(
|
| 799 |
+
model=model_name,
|
| 800 |
config=types.CreateCachedContentConfig(
|
|
|
|
| 801 |
system_instruction=system_instruction,
|
| 802 |
+
contents=[document], # Direct document reference as in docs
|
|
|
|
| 803 |
)
|
| 804 |
)
|
| 805 |
|
|
|
|
| 810 |
document_caches[cache_id] = {
|
| 811 |
'cache_name': cache.name,
|
| 812 |
'document_name': filename,
|
|
|
|
| 813 |
'source_url': url,
|
| 814 |
'created_at': datetime.now().isoformat()
|
| 815 |
}
|
|
|
|
| 831 |
|
| 832 |
except Exception as cache_error:
|
| 833 |
print(f"Cache error: {cache_error}")
|
| 834 |
+
# Provide more specific error handling for token requirements
|
| 835 |
+
error_msg = str(cache_error).lower()
|
| 836 |
+
if "too small" in error_msg or "minimum" in error_msg:
|
| 837 |
return jsonify({
|
| 838 |
'success': False,
|
| 839 |
+
'error': f'Document content is insufficient for caching. Gemini requires minimum token thresholds. Document from URL: {filename} ({content_length_mb:.1f}MB)',
|
| 840 |
+
'suggestion': 'Try a longer document with more text content (recommended: 5MB+ with substantial text).'
|
| 841 |
})
|
| 842 |
else:
|
| 843 |
return jsonify({'success': False, 'error': f'Failed to create cache: {str(cache_error)}'})
|
|
|
|
| 864 |
# Generate response using cached content with correct model format
|
| 865 |
try:
|
| 866 |
response = client.models.generate_content(
|
| 867 |
+
model="gemini-2.0-flash-001", # Use model name format from documentation
|
| 868 |
contents=question,
|
| 869 |
config=types.GenerateContentConfig(
|
| 870 |
cached_content=cache_info['cache_name']
|