From 433a6592ee0fc0a1307bf2a93bf7419f11e63c50 Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 16 Oct 2025 07:46:56 -0500 Subject: [PATCH] fixed SDK to newer version and added download file name feature for pdfs --- backend/app.py | 16 ++++++++-- backend/requirements.txt | 2 +- backend/test_api.py | 18 ++++++----- backend/video_processor.py | 28 ++++++++-------- frontend/public/config.js | 14 ++++---- frontend/public/config.json | 14 ++++---- .../src/components/AuthenticatedContent.js | 9 +++--- frontend/src/components/ResultDisplay.js | 5 +-- video_query.py | 32 +++++++++---------- 9 files changed, 75 insertions(+), 63 deletions(-) diff --git a/backend/app.py b/backend/app.py index 90359b5..2913a49 100644 --- a/backend/app.py +++ b/backend/app.py @@ -274,12 +274,14 @@ def generate_pdf(): text_diagrams = data.get('textDiagrams', {}) svg_diagrams = data.get('svgDiagrams', {}) diagram_png_data_urls = data.get('diagramPngs', {}) + video_file_name = data.get('videoFileName', '') # Log detailed request information logger.info(f"Request data: HTML content length: {len(html_content) if html_content else 0}") logger.info(f"Text diagrams received: {len(text_diagrams)}") logger.info(f"SVG diagrams received: {len(svg_diagrams)}") logger.info(f"Diagram PNGs received: {len(diagram_png_data_urls)}") + logger.info(f"Video filename received: {video_file_name if video_file_name else 'None'}") # Comment out full HTML content logging # logger.info("HTML CONTENT RECEIVED START -------------------") @@ -535,7 +537,7 @@ def generate_pdf(): logger.warning(f"SVG_WARN: Could not find div with id='{diagram_id}' for SVG replacement using BeautifulSoup.") # Try to find a code block with matching content from textDiagrams original_code_for_svg = text_diagrams.get(diagram_id) - if original_code_for_svg and os.path.exists(persistent_png_path): + if original_code_for_svg and os.path.exists(temp_png_path): # Try to find matching code blocks code_blocks = soup.find_all('pre') for code_block in code_blocks: @@ -1077,10 +1079,20 @@ def generate_pdf(): except Exception as cleanup_error: logger.warning(f"Could not remove all temporary files: {str(cleanup_error)}") + # Generate PDF filename from video filename + if video_file_name: + # Remove video extension and add .pdf + base_name = os.path.splitext(video_file_name)[0] + pdf_filename = f"{base_name}.pdf" + logger.info(f"Generated PDF filename from video name: {pdf_filename}") + else: + pdf_filename = 'video_query_result.pdf' + logger.info("No video filename provided, using default PDF name") + return jsonify({ 'success': True, 'pdf': pdf_base64, - 'filename': 'video_query_result.pdf' + 'filename': pdf_filename }) except Exception as e: diff --git a/backend/requirements.txt b/backend/requirements.txt index 7e3d68b..3c5a1fa 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -16,7 +16,7 @@ google-api-core==2.25.0rc0 google-api-python-client==2.169.0 google-auth==2.40.0 google-auth-httplib2==0.2.0 -google-generativeai==0.8.5 +google-genai>=1.44.0 googleapis-common-protos==1.70.0 grpcio==1.71.0 grpcio-status==1.71.0 diff --git a/backend/test_api.py b/backend/test_api.py index c24be4e..2d6f359 100644 --- a/backend/test_api.py +++ b/backend/test_api.py @@ -1,4 +1,4 @@ -import google.generativeai as genai +from google import genai import os from dotenv import load_dotenv @@ -8,16 +8,18 @@ load_dotenv() print(f"API Key set: {bool(os.getenv('GOOGLE_API_KEY'))}") try: - # Configure client with API key + # Initialize client with API key api_key = os.getenv("GOOGLE_API_KEY") - genai.configure(api_key=api_key) - + client = genai.Client(api_key=api_key) + # Test connection - model = genai.GenerativeModel('gemini-1.5-pro') - response = model.generate_content('Test the API connection') - + response = client.models.generate_content( + model='gemini-1.5-pro', + contents='Test the API connection' + ) + print("API connection test successful!") print(f"Response: {response.text}") - + except Exception as e: print(f"API error: {e}") \ No newline at end of file diff --git a/backend/video_processor.py b/backend/video_processor.py index b1653c0..fdf0aa8 100644 --- a/backend/video_processor.py +++ b/backend/video_processor.py @@ -1,4 +1,4 @@ -import google.generativeai as genai +from google import genai import mimetypes import time import os @@ -41,10 +41,10 @@ class VideoProcessor: if not self.api_key: logger.error("API key not provided") raise ValueError("API key not provided - set GOOGLE_API_KEY environment variable or pass when initializing") - - # Configure the Gemini client + + # Initialize the Gemini client logger.info("Initializing Gemini API client") - genai.configure(api_key=self.api_key) + self.client = genai.Client(api_key=self.api_key) logger.info("Gemini API client initialized successfully") def send_usage_webhook(self, user_email: str, prompt: str) -> None: @@ -132,10 +132,8 @@ class VideoProcessor: # All uploads use the same method (our chunking happens in the frontend) # Google API may handle large files internally in their own way - video_file = genai.upload_file( - path=video_path, - display_name=os.path.basename(video_path) - ) + # Note: display_name is not supported in the new google-genai SDK + video_file = self.client.files.upload(file=video_path) logger.info(f"Upload successful. File URI: {video_file.uri}") logger.info(f"Initial file state: {video_file.state.name}") @@ -145,7 +143,7 @@ class VideoProcessor: processing_wait_count += 1 logger.info(f"File is still processing. Wait count: {processing_wait_count}") time.sleep(2) # Wait for 2 seconds before checking again - video_file = genai.get_file(name=video_file.name) # Re-fetch file state + video_file = self.client.files.get(name=video_file.name) # Re-fetch file state logger.info(f"Updated file state: {video_file.state.name}") if video_file.state.name != "ACTIVE": @@ -171,12 +169,12 @@ class VideoProcessor: }} ] - # Initialize the model and generate content - logger.info("Initializing GenerativeModel...") - model = genai.GenerativeModel(model_name="gemini-2.5-pro") - + # Generate content using the client logger.info("Sending prompt to Gemini for processing...") - response = model.generate_content(prompt_parts) + response = self.client.models.generate_content( + model='gemini-2.5-pro', + contents=prompt_parts + ) logger.info("Received response from Gemini") # Extract the response content @@ -207,7 +205,7 @@ class VideoProcessor: # Attempt to delete the file from Gemini storage try: logger.info(f"Deleting file from Gemini storage: {video_file.name}") - genai.delete_file(name=video_file.name) + self.client.files.delete(name=video_file.name) logger.info("File deleted successfully from Gemini storage") except Exception as del_err: logger.warning(f"Could not delete file from Gemini storage: {str(del_err)}") diff --git a/frontend/public/config.js b/frontend/public/config.js index 13f23c6..3b9c90b 100644 --- a/frontend/public/config.js +++ b/frontend/public/config.js @@ -1,16 +1,16 @@ window.__APP_CONFIG__ = { "_comment": "Dynamic base path configuration - set basePath to override auto-detection", - "basePath": "/video-query", - "domain": "https://brandtechsandbox.oliver.solutions", + "basePath": "/video_query", + "domain": "https://ai-sandbox.oliver.solutions", "msal": { - "clientId": "01d33c7c-5640-4986-b4db-06af63a7d285", + "clientId": "9079054c-9620-4757-a256-23413042f1ef", "authority": "https://login.microsoftonline.com/e519c2e6-bc6d-4fdf-8d9c-923c2f002385", - "redirectUri": "https://brandtechsandbox.oliver.solutions/video-query/", - "postLogoutRedirectUri": "https://brandtechsandbox.oliver.solutions/video-query/", + "redirectUri": "https://ai-sandbox.oliver.solutions/video_query/", + "postLogoutRedirectUri": "https://ai-sandbox.oliver.solutions/video_query/", "tenantId": "e519c2e6-bc6d-4fdf-8d9c-923c2f002385" }, "api": { - "videoProcessingEndpoint": "https://brandtechsandbox.oliver.solutions/video_query_back/api/process", - "chunkedUploadEndpoint": "https://brandtechsandbox.oliver.solutions/video_query_back" + "videoProcessingEndpoint": "https://ai-sandbox.oliver.solutions/video_query_back/api/process", + "chunkedUploadEndpoint": "https://ai-sandbox.oliver.solutions/video_query_back" } }; \ No newline at end of file diff --git a/frontend/public/config.json b/frontend/public/config.json index 9d29a28..7262b50 100644 --- a/frontend/public/config.json +++ b/frontend/public/config.json @@ -1,16 +1,16 @@ { "_comment": "Dynamic base path configuration - set basePath to override auto-detection", - "basePath": "/video-query", - "domain": "https://brandtechsandbox.oliver.solutions", + "basePath": "/video_query", + "domain": "https://ai-sandbox.oliver.solutions", "msal": { - "clientId": "01d33c7c-5640-4986-b4db-06af63a7d285", + "clientId": "9079054c-9620-4757-a256-23413042f1ef", "authority": "https://login.microsoftonline.com/e519c2e6-bc6d-4fdf-8d9c-923c2f002385", - "redirectUri": "https://brandtechsandbox.oliver.solutions/video-query/", - "postLogoutRedirectUri": "https://brandtechsandbox.oliver.solutions/video-query/", + "redirectUri": "https://ai-sandbox.oliver.solutions/video_query/", + "postLogoutRedirectUri": "https://ai-sandbox.oliver.solutions/video_query/", "tenantId": "e519c2e6-bc6d-4fdf-8d9c-923c2f002385" }, "api": { - "videoProcessingEndpoint": "https://brandtechsandbox.oliver.solutions/video_query_back/api/process", - "chunkedUploadEndpoint": "https://brandtechsandbox.oliver.solutions/video_query_back" + "videoProcessingEndpoint": "https://ai-sandbox.oliver.solutions/video_query_back/api/process", + "chunkedUploadEndpoint": "https://ai-sandbox.oliver.solutions/video_query_back" } } \ No newline at end of file diff --git a/frontend/src/components/AuthenticatedContent.js b/frontend/src/components/AuthenticatedContent.js index a645ddf..67bf1fd 100644 --- a/frontend/src/components/AuthenticatedContent.js +++ b/frontend/src/components/AuthenticatedContent.js @@ -79,10 +79,11 @@ const AuthenticatedContent = (props) => { )} - {props.result && ( diff --git a/frontend/src/components/ResultDisplay.js b/frontend/src/components/ResultDisplay.js index daacb3d..e68d17c 100644 --- a/frontend/src/components/ResultDisplay.js +++ b/frontend/src/components/ResultDisplay.js @@ -3,7 +3,7 @@ import showdown from 'showdown'; import mermaid from 'mermaid'; import { getApiConfig } from '../utils/configLoader'; -const ResultDisplay = ({ result, isLoading, uploadProgress = 0 }) => { +const ResultDisplay = ({ result, isLoading, uploadProgress = 0, fileName = '' }) => { const resultRef = useRef(null); const [htmlContent, setHtmlContent] = useState(''); @@ -279,7 +279,8 @@ const ResultDisplay = ({ result, isLoading, uploadProgress = 0 }) => { { html: htmlToSend, textDiagrams: textDiagrams, - diagramPngs: diagramPngs // Send the base64 PNGs instead of SVGs + diagramPngs: diagramPngs, // Send the base64 PNGs instead of SVGs + videoFileName: fileName // Send the original video filename }, { headers: { diff --git a/video_query.py b/video_query.py index a7cfcac..974de71 100644 --- a/video_query.py +++ b/video_query.py @@ -1,4 +1,4 @@ -import google.generativeai as genai +from google import genai import mimetypes import time import os @@ -31,8 +31,8 @@ def upload_video_and_query(api_key, video_path, prompt): return try: - # Configure the Gemini client - genai.configure(api_key=api_key) + # Initialize the Gemini client + client = genai.Client(api_key=api_key) print(f"Attempting to upload '{video_path}'...") @@ -46,12 +46,10 @@ def upload_video_and_query(api_key, video_path, prompt): print(f"File size ({file_size} bytes) is below threshold...") # Upload the file - all uploads use same method, but we always log the threshold - video_file = genai.upload_file( - path=video_path, - display_name=os.path.basename(video_path) - ) - - print(f"Successfully uploaded file: {video_file.display_name} as {video_file.uri}") + # Note: display_name is not supported in the new google-genai SDK + video_file = client.files.upload(file=video_path) + + print(f"Successfully uploaded file: {os.path.basename(video_path)} as {video_file.uri}") print(f"File state: {video_file.state.name}") # Should ideally be ACTIVE # Ensure the file is ready for use (though upload_file usually handles this) @@ -59,7 +57,7 @@ def upload_video_and_query(api_key, video_path, prompt): while video_file.state.name == "PROCESSING": print("File is still processing. Waiting...") time.sleep(5) # Wait for 5 seconds before checking again - video_file = genai.get_file(name=video_file.name) # Re-fetch file state + video_file = client.files.get(name=video_file.name) # Re-fetch file state print(f"File state: {video_file.state.name}") if video_file.state.name != "ACTIVE": @@ -85,12 +83,12 @@ def upload_video_and_query(api_key, video_path, prompt): }} ] - # 3. Initialize the Generative Model (gemini-2.5-pro for video) - model = genai.GenerativeModel(model_name="gemini-2.5-pro") - print("\nSending prompt to Gemini 2.5 Pro model...") - # 4. Generate content - response = model.generate_content(prompt_parts) + # 3. Generate content using the client + response = client.models.generate_content( + model='gemini-2.5-pro', + contents=prompt_parts + ) # 5. Print the response print("\n--- Gemini Response ---") @@ -113,10 +111,10 @@ def upload_video_and_query(api_key, video_path, prompt): finally: # Optional: Delete the file from Gemini storage if you no longer need it. # Be careful with this in a real application. - # if 'video_file' in locals() and video_file: + # if 'video_file' in locals() and video_file and 'client' in locals(): # try: # print(f"\nAttempting to delete file: {video_file.name}") - # genai.delete_file(name=video_file.name) + # client.files.delete(name=video_file.name) # print("File deleted successfully.") # except Exception as e_del: # print(f"Error deleting file: {e_del}")