[Python] Gemini API call not working in python script

Discussão em 'Python' iniciado por Stack, Abril 18, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to get the new gemini flash model to work via an api call but I keep getting this error below

    [2025-04-18 13:01:21] | GEMINI_PROCESSOR | INFO | GeminiProcessor initialized with model: gemini-2.5-pro-exp-03-25
    [2025-04-18 13:01:21] | GEMINI_PROCESSOR | INFO | Processing image: captured_frames\frame_2_20250412_210205.jpg
    [2025-04-18 13:01:21] | GEMINI_PROCESSOR | INFO | Error in API call: 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': '* GenerateContentRequest.contents[1].parts: contents.parts must not be empty.\n', 'status': 'INVALID_ARGUMENT'}}
    Traceback (most recent call last):


    The code class is as follows below

    import json
    import os
    import glob
    from google import genai
    from google.genai import types
    import time
    import cv2
    import numpy as np
    from datetime import datetime
    from logging_setup import setup_logging
    import toml
    import sys


    class GeminiProcessor:
    """Class for processing images with Google's Gemini API to detect objects and calculate depths"""

    def __init__(self, logging_config):
    """Initialize the Gemini API processor"""
    config = toml.load("config.toml")
    self.log = setup_logging('GEMINI_PROCESSOR', logging_config)
    gemini_config = config.get("gemini", {})
    self.output_dir = gemini_config.get("Output_Directory")
    self.results_dir = gemini_config.get("Results_Directory")
    self.image_path = gemini_config.get("image_directory")
    self.model_name = gemini_config.get("model_name")
    self.base_colors = [[0, 0, 255], [0, 255, 0], [255, 0, 0], [0, 255, 255]]
    self.safety_settings = [types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT",threshold="BLOCK_ONLY_HIGH",),]
    self.bounding_box_system_instructions = gemini_config.get("bounding_box_system_instructions")
    self.api_key = gemini_config.get("google_api_key")
    self.client = genai.Client(api_key=self.api_key)
    self.prompt = gemini_config.get("prompt")
    self.init_directories()
    self.log.info("GeminiProcessor initialized with model: %s", self.model_name)

    def init_directories(self):
    """Create necessary output directories"""
    for directory in [self.output_dir, self.results_dir]:
    if directory and not os.path.exists(directory):
    os.makedirs(directory)
    self.log.info(f"Created directory: {directory}")

    def parse_json(self, json_output: str):
    """Parse the JSON output from the Gemini API"""
    if not json_output or not isinstance(json_output, str):
    return "[]"

    lines = json_output.splitlines()
    for i, line in enumerate(lines):
    if line == "```json":
    json_output = "\n".join(lines[i+1:])
    json_output = json_output.split("```")[0]
    break

    return json_output

    def save_parsed_json(self, json_output, image_name=None):
    """Parse and save JSON response to a file"""
    parsed_json = self.parse_json(json_output)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    base_name = f"response_{timestamp}" if image_name is None else f"{image_name}_{timestamp}"
    file_path = f"{self.results_dir}/{base_name}.json"

    try:
    json_data = json.loads(parsed_json)
    with open(file_path, 'w') as f:
    json.dump(json_data, f, indent=4)
    self.log.info(f"JSON response saved to {file_path}")
    return file_path

    except json.JSONDecodeError as e:
    self.log.error(f"Invalid JSON format: {e}")
    with open(file_path, 'w') as f:
    f.write(parsed_json)
    self.log.warning(f"Saved raw text to {file_path}")
    return None

    def plot_bounding_boxes(self, bounding_boxes, image_path: str):
    """Plot bounding boxes on the image"""

    image_files = glob.glob(f"{self.image_path}/*.*")
    if not image_files:
    self.log.error(f"No files found in {self.image_path}")
    return False

    img = cv2.imread(image_files)

    if img is None:
    self.log.error(f"Failed to read image from {image_path}")
    return False

    height, width = img.shape[:2]
    target_width, target_height = 640, 480
    scale = min(target_width/width, target_height/height)
    img_resized = cv2.resize(img, (int(width*scale), int(height*scale)),
    interpolation=cv2.INTER_LANCZOS4)

    try:
    parsed_json = self.parse_json(bounding_boxes)
    boxes = json.loads(parsed_json)

    for i, box in enumerate(boxes):
    color = self.colors[i % len(self.colors)]

    # Convert normalized coordinates to absolute coordinates
    abs_y1 = int(box["box_2d"][0]/1000 * height)
    abs_x1 = int(box["box_2d"][1]/1000 * width)
    abs_y2 = int(box["box_2d"][2]/1000 * height)
    abs_x2 = int(box["box_2d"][3]/1000 * width)

    # Ensure correct order
    if abs_x1 > abs_x2:
    abs_x1, abs_x2 = abs_x2, abs_x1
    if abs_y1 > abs_y2:
    abs_y1, abs_y2 = abs_y2, abs_y1

    box["centroid"] = [(abs_x1 + abs_x2) / 2, (abs_y1 + abs_y2) / 2]

    cv2.rectangle(img_resized, (abs_x1, abs_y1), (abs_x2, abs_y2), color, 2)

    if "label" in box:
    label = box["label"]
    text_size, _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)
    cv2.rectangle(img_resized,
    (abs_x1, abs_y1-5-text_size[1]),
    (abs_x1+text_size[0], abs_y1),
    color, -1)
    cv2.putText(img_resized, label, (abs_x1, abs_y1-5),
    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    base_name = os.path.basename(image_path).split('.')[0] if isinstance(image_path, str) else "image"
    output_path = f"{self.output_dir}/{base_name}_annotated_{timestamp}.jpg"
    cv2.imwrite(output_path, img_resized)
    cv2.imshow("Detected Objects", img_resized)
    cv2.waitKey(1)

    return {
    "annotated_image": img_resized,
    "output_path": output_path,
    "boxes": boxes
    }

    except Exception as e:
    self.log.error(f"Error plotting bounding boxes: {e}")
    return False

    def run(self):
    """Run the Gemini API to process a single image in the directory"""

    client = self.client
    model = self.model_name
    image_path = self.image_path

    try:
    image_files = glob.glob(f"{self.image_path}/*.*")
    if not image_files:
    self.log.error(f"No files found in {self.image_path}")
    return False

    image_path = image_files[0]
    self.log.info(f"Processing image: {image_path}")

    img = cv2.imread(image_path)
    if img is None:
    self.log.error(f"Failed to load image: {image_path}")
    return False

    # temp_path = f"{self.output_dir}/temp_image.jpg"
    # cv2.imwrite(temp_path, img)

    # with open(temp_path, "rb") as f:
    # image_data = f.read()

    # image_parts = [
    # {
    # "mime_type": "image/jpeg",
    # "data": image_data
    # }
    # ]

    # content = [
    # {"text": self.prompt},
    # {"image": image_parts}
    # ]

    response = client.models.generate_content(model=model,
    contents=[self.prompt, img],
    config=types.GenerateContentConfig(
    system_instruction=self.bounding_box_system_instructions,
    temperature=0.5,
    safety_settings=self.safety_settings
    )
    )
    # if os.path.exists(temp_path):
    # os.remove(temp_path)

    if response.text:
    # Delete previous json file
    for results_file in glob.glob(f"{self.results_dir}/*.json"):
    try:
    os.remove(results_file)
    self.log.info(f"Deleted previous result: {results_file}")
    except Exception as e:
    self.log.warning(f"Could not delete file {results_file}: {e}")

    # Save the parsed JSON response
    base_name = os.path.splitext(os.path.basename(image_path))[0]
    json_path = self.save_parsed_json(response.text, base_name)
    result = self.plot_bounding_boxes(response.text, image_path)

    return {
    "response": response.text,
    "json_path": json_path,
    "visualization": result
    }
    else:
    self.log.info("Empty response from API")
    return False

    except Exception as e:
    self.log.info(f"Error in API call: {e}")
    if 'temp_path' in locals() and os.path.exists(image_path):
    os.remove(image_path)
    return False


    below is the initiation in the main script to test it out

    if __name__ == '__main__':
    logging_config = LoggingConfig()
    camera = RealSenseCamera(logging_config)
    apriltag = ApriltagHomography(logging_config)
    api = GeminiProcessor(logging_config)
    transformer = CoordinateTransformer(logging_config)
    api.run()


    the link to the github is https://github.com/google-gemini/cookbook/blob/main/quickstarts/Spatial_understanding.ipynb

    Continue reading...

Compartilhe esta Página