import os import json import requests import sys import base64 from typing import List, Optional, Dict, Any def generate_subjective_questions(image_path: str) -> Optional[Dict[Any, Any]]: """ Transcribes and structures subjective questions from an image using the Gemini API. """ api_key = os.environ.get("GEMINI_API_KEY") if not api_key: print("Error: GEMINI_API_KEY environment variable is not set.", file=sys.stderr) return None # Read and encode image try: with open(image_path, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') except Exception as e: print(f"Error reading image file: {e}", file=sys.stderr) return None model_id = "gemini-flash-latest" url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_id}:generateContent?key={api_key}" headers = {'Content-Type': 'application/json'} prompt_text = """ Analyze the provided image. It contains a list of subjective questions (handwritten or printed). Task: 1. **Transcribe** each question exactly as written. 2. **Identify the Topic:** Determine the subject or topic for each question (e.g., "Ascomycetes", "Thermodynamics"). If the header specifies a topic, use that. 3. **Structure:** Return the data in the specified JSON format. 4. **Numbering:** Use the question number found in the image. If the image contains multiple questions, extract all of them. """ request_body = { "contents": [ { "role": "user", "parts": [ { "inline_data": { "mime_type": "image/jpeg", # Assuming JPEG/PNG, API is flexible with image/* usually, but let's send jpeg or png based on file if needed, usually jpeg works for generic "data": encoded_string } }, { "text": prompt_text } ] } ], "generationConfig": { "responseMimeType": "application/json", "responseSchema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "array", "items": { "type": "object", "properties": { "question_topic": {"type": "string"}, "question_html": {"type": "string"}, "question_number_within_topic": {"type": "string"} }, "required": ["question_topic", "question_html", "question_number_within_topic"] } } }, "required": ["success", "data"] } } } try: response = requests.post(url, headers=headers, json=request_body, timeout=120) response.raise_for_status() response_json = response.json() # Extract text from candidate candidate = response_json.get('candidates', [{}])[0] content = candidate.get('content', {}) parts = content.get('parts', []) if not parts: print("Error: Gemini generated no content.") return None text = parts[0]['text'] return json.loads(text) except requests.exceptions.RequestException as e: print(f"Error during Gemini API call: {e}", file=sys.stderr) if e.response: print(f"Response: {e.response.text}", file=sys.stderr) return None except json.JSONDecodeError as e: print(f"Error parsing JSON response: {e}", file=sys.stderr) print(f"Raw text: {text}", file=sys.stderr) return None if __name__ == "__main__": # Test the function result = generate_subjective_questions("Ascomycetes") if result: print(json.dumps(result, indent=2))