WHG2023
Enhanced Dual Output Features - Both descriptions AND LaTeX code + Multiple compilation options + Professional USPTO-ready vector graphics + Immediate understanding without compilation barriers
4252b44
| #!/usr/bin/env python3 | |
| """ | |
| Enhanced Gemini Image Generator Integration for Patent Architect AI v2 | |
| Provides high-quality technical figure generation with dual output: | |
| - Detailed technical descriptions for immediate understanding | |
| - Professional LaTeX/TikZ code with embedded compilation options | |
| """ | |
| import os | |
| import json | |
| import base64 | |
| import requests | |
| import tempfile | |
| import subprocess | |
| import shutil | |
| from typing import Dict, List, Optional, Tuple | |
| import google.generativeai as genai | |
| from datetime import datetime | |
| from dotenv import load_dotenv | |
| # Load environment variables | |
| load_dotenv() | |
| class GeminiImageGenerator: | |
| """Enhanced Gemini integration with dual output and embedded compilation.""" | |
| def __init__(self, api_key: Optional[str] = None, output_dir: Optional[str] = None): | |
| """Initialize the enhanced Gemini image generator. | |
| Args: | |
| api_key: Google Gemini API key | |
| output_dir: Directory to save generated images | |
| """ | |
| self.api_key = api_key or os.getenv("GEMINI_API_KEY") | |
| if not self.api_key: | |
| raise ValueError("GEMINI_API_KEY environment variable or api_key parameter required") | |
| # Configure Gemini | |
| genai.configure(api_key=self.api_key) | |
| self.model = genai.GenerativeModel('gemini-2.0-flash-exp') | |
| # Set output directory | |
| self.output_dir = output_dir or os.path.join(os.path.expanduser("~"), "patent_architect_figures") | |
| os.makedirs(self.output_dir, exist_ok=True) | |
| # Check if LaTeX is available for compilation | |
| self.latex_available = self._check_latex_installation() | |
| # Image generation parameters | |
| self.generation_config = { | |
| 'temperature': 0.4, | |
| 'top_k': 32, | |
| 'top_p': 1, | |
| 'max_output_tokens': 8192, | |
| } | |
| def _check_latex_installation(self) -> bool: | |
| """Check if LaTeX is available for compilation.""" | |
| try: | |
| result = subprocess.run(['pdflatex', '--version'], | |
| capture_output=True, | |
| text=True, | |
| timeout=5) | |
| return result.returncode == 0 | |
| except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.SubprocessError): | |
| return False | |
| def _compile_latex_via_web_api(self, latex_code: str, filename: str) -> Optional[str]: | |
| """Try to compile LaTeX using web-based APIs. | |
| Args: | |
| latex_code: LaTeX source code | |
| filename: Base filename for output | |
| Returns: | |
| Path to compiled image or None if failed | |
| """ | |
| try: | |
| # Try using a public LaTeX compilation API (example with LaTeX.Online) | |
| api_url = "https://latex.vercel.app/api/v2" | |
| payload = { | |
| "code": latex_code, | |
| "format": "png", | |
| "quality": 300 | |
| } | |
| print(f"π Attempting web-based LaTeX compilation...") | |
| response = requests.post(api_url, json=payload, timeout=30) | |
| if response.status_code == 200: | |
| # Save compiled image | |
| image_filename = f"{filename}.png" | |
| image_path = os.path.join(self.output_dir, image_filename) | |
| with open(image_path, 'wb') as f: | |
| f.write(response.content) | |
| print(f"β Web compilation successful: {image_filename}") | |
| return image_path | |
| else: | |
| print(f"β οΈ Web compilation failed: HTTP {response.status_code}") | |
| return None | |
| except Exception as e: | |
| print(f"β οΈ Web compilation error: {e}") | |
| return None | |
| def _compile_latex_to_image(self, latex_filepath: str) -> Optional[str]: | |
| """Enhanced LaTeX compilation with multiple methods. | |
| Args: | |
| latex_filepath: Path to the .tex file | |
| Returns: | |
| Path to generated image file or None if compilation failed | |
| """ | |
| # Try local compilation first if available | |
| if self.latex_available: | |
| try: | |
| # Get directory and filename | |
| tex_dir = os.path.dirname(latex_filepath) | |
| tex_filename = os.path.basename(latex_filepath) | |
| base_name = os.path.splitext(tex_filename)[0] | |
| print(f"π§ Attempting local LaTeX compilation...") | |
| # Compile LaTeX to PDF | |
| result = subprocess.run([ | |
| 'pdflatex', | |
| '-output-directory', tex_dir, | |
| '-interaction=nonstopmode', | |
| latex_filepath | |
| ], capture_output=True, text=True, timeout=30) | |
| if result.returncode == 0: | |
| # Check if PDF was created | |
| pdf_path = os.path.join(tex_dir, f"{base_name}.pdf") | |
| if os.path.exists(pdf_path): | |
| # Try to convert PDF to PNG using available tools | |
| png_path = os.path.join(tex_dir, f"{base_name}.png") | |
| # Try different conversion methods | |
| conversion_methods = [ | |
| # Method 1: pdftoppm (part of poppler-utils) | |
| ['pdftoppm', '-png', '-singlefile', '-r', '300', pdf_path, base_name], | |
| # Method 2: ImageMagick convert | |
| ['convert', '-density', '300', pdf_path, png_path], | |
| # Method 3: ghostscript | |
| ['gs', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', '-r300', f'-sOutputFile={png_path}', pdf_path] | |
| ] | |
| for method in conversion_methods: | |
| try: | |
| if method[0] == 'pdftoppm': | |
| result = subprocess.run(method, | |
| cwd=tex_dir, | |
| capture_output=True, | |
| text=True, | |
| timeout=30) | |
| if result.returncode == 0: | |
| expected_png = os.path.join(tex_dir, f"{base_name}.png") | |
| if os.path.exists(expected_png): | |
| print(f"β Local compilation successful: {expected_png}") | |
| return expected_png | |
| else: | |
| result = subprocess.run(method, | |
| capture_output=True, | |
| text=True, | |
| timeout=30) | |
| if result.returncode == 0 and os.path.exists(png_path): | |
| print(f"β Local compilation successful: {png_path}") | |
| return png_path | |
| except (subprocess.TimeoutExpired, FileNotFoundError): | |
| continue | |
| print(f"β PDF created but PNG conversion failed: {pdf_path}") | |
| return pdf_path # Return PDF if PNG conversion failed | |
| else: | |
| print(f"β οΈ Local LaTeX compilation failed: {result.stderr}") | |
| except Exception as e: | |
| print(f"β οΈ Local LaTeX compilation error: {e}") | |
| # Try web-based compilation as fallback | |
| try: | |
| with open(latex_filepath, 'r', encoding='utf-8') as f: | |
| latex_code = f.read() | |
| base_name = os.path.splitext(os.path.basename(latex_filepath))[0] | |
| web_result = self._compile_latex_via_web_api(latex_code, base_name) | |
| if web_result: | |
| return web_result | |
| except Exception as e: | |
| print(f"β οΈ Web compilation fallback failed: {e}") | |
| return None | |
| def generate_dual_output_figure(self, | |
| invention_description: str, | |
| figure_type: str = "technical_diagram", | |
| specific_requirements: Optional[str] = None) -> Dict: | |
| """Generate both detailed description AND LaTeX code for a patent figure. | |
| Args: | |
| invention_description: Description of the invention | |
| figure_type: Type of figure to generate | |
| specific_requirements: Additional requirements for the figure | |
| Returns: | |
| Dict containing both text description and LaTeX code with compilation options | |
| """ | |
| try: | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| # Step 1: Generate detailed text description | |
| print(f"π Generating detailed technical description...") | |
| text_prompt = self._create_patent_figure_prompt( | |
| invention_description, | |
| figure_type, | |
| specific_requirements | |
| ) | |
| text_response = self.model.generate_content([text_prompt]) | |
| detailed_description = text_response.text | |
| # Step 2: Generate LaTeX/TikZ code | |
| print(f"π¨ Generating LaTeX/TikZ code...") | |
| latex_prompt = self._create_image_generation_prompt( | |
| invention_description, | |
| figure_type, | |
| specific_requirements | |
| ) | |
| latex_response = self.model.generate_content([latex_prompt], | |
| generation_config={'temperature': 0.1}) | |
| latex_code = latex_response.text | |
| # Save both outputs | |
| text_filename = f"patent_figure_{figure_type}_{timestamp}_description.txt" | |
| latex_filename = f"patent_figure_{figure_type}_{timestamp}.tex" | |
| text_filepath = os.path.join(self.output_dir, text_filename) | |
| latex_filepath = os.path.join(self.output_dir, latex_filename) | |
| # Save detailed description | |
| with open(text_filepath, 'w', encoding='utf-8') as f: | |
| f.write(f"Patent Figure Description\n") | |
| f.write(f"========================\n\n") | |
| f.write(f"Invention: {invention_description}\n\n") | |
| f.write(f"Figure Type: {figure_type}\n\n") | |
| f.write(f"Description:\n{detailed_description}\n\n") | |
| f.write(f"Generated: {datetime.now().isoformat()}\n") | |
| # Save LaTeX code | |
| with open(latex_filepath, 'w', encoding='utf-8') as f: | |
| f.write(f"% Patent Figure - {figure_type}\n") | |
| f.write(f"% Generated: {datetime.now().isoformat()}\n") | |
| f.write(f"% Invention: {invention_description}\n\n") | |
| f.write(latex_code) | |
| # Try to compile LaTeX to image | |
| compiled_image_path = None | |
| compilation_method = None | |
| if any(keyword in latex_code.lower() for keyword in ['tikz', 'latex', 'documentclass', '\\draw']): | |
| compiled_image_path = self._compile_latex_to_image(latex_filepath) | |
| if compiled_image_path: | |
| if self.latex_available: | |
| compilation_method = "local" | |
| else: | |
| compilation_method = "web" | |
| return { | |
| "success": True, | |
| "dual_output": True, | |
| "text_description": detailed_description, | |
| "latex_code": latex_code, | |
| "text_file_path": text_filepath, | |
| "latex_file_path": latex_filepath, | |
| "compiled_image_path": compiled_image_path, | |
| "compilation_method": compilation_method, | |
| "figure_type": figure_type, | |
| "timestamp": timestamp, | |
| "code_preview": latex_code[:400] + "..." if len(latex_code) > 400 else latex_code, | |
| "description_preview": detailed_description[:300] + "..." if len(detailed_description) > 300 else detailed_description, | |
| "metadata": { | |
| "invention": invention_description, | |
| "requirements": specific_requirements, | |
| "latex_available": self.latex_available, | |
| "output_formats": ["description", "latex", "compiled_image"] if compiled_image_path else ["description", "latex"] | |
| } | |
| } | |
| except Exception as e: | |
| return { | |
| "success": False, | |
| "error": str(e), | |
| "figure_type": figure_type | |
| } | |
| def generate_patent_figure(self, | |
| invention_description: str, | |
| figure_type: str = "technical_diagram", | |
| specific_requirements: Optional[str] = None) -> Dict: | |
| """Enhanced patent figure generation with dual output option.""" | |
| # Use the new dual output method for better results | |
| return self.generate_dual_output_figure(invention_description, figure_type, specific_requirements) | |
| def generate_multiple_figures(self, | |
| invention_description: str, | |
| figure_types: List[str] = None) -> List[Dict]: | |
| """Generate multiple patent figures for an invention. | |
| Args: | |
| invention_description: Description of the invention | |
| figure_types: List of figure types to generate | |
| Returns: | |
| List of generation results | |
| """ | |
| if figure_types is None: | |
| figure_types = [ | |
| "overall_system_diagram", | |
| "detailed_cross_section", | |
| "component_breakdown", | |
| "operational_flow" | |
| ] | |
| results = [] | |
| for figure_type in figure_types: | |
| result = self.generate_patent_figure(invention_description, figure_type) | |
| results.append(result) | |
| return results | |
| def _create_patent_figure_prompt(self, | |
| invention_description: str, | |
| figure_type: str, | |
| specific_requirements: Optional[str] = None) -> str: | |
| """Create a detailed prompt for patent figure generation. | |
| Args: | |
| invention_description: Description of the invention | |
| figure_type: Type of figure to generate | |
| specific_requirements: Additional requirements | |
| Returns: | |
| Detailed prompt for figure generation | |
| """ | |
| base_prompt = f""" | |
| Create a detailed technical description for a patent figure showing: {invention_description} | |
| Figure Type: {figure_type} | |
| Requirements for patent-quality technical figures: | |
| 1. Clear component labeling with numbered elements (1, 2, 3, etc.) | |
| 2. Professional technical drawing style | |
| 3. Sufficient detail to enable reproduction by skilled person | |
| 4. Clear spatial relationships between components | |
| 5. Appropriate perspective and viewing angle | |
| 6. No decorative elements - focus on technical clarity | |
| 7. Include all essential components mentioned in the invention | |
| Please provide a comprehensive description that includes: | |
| - Main components and their numbered labels | |
| - Spatial relationships and connections | |
| - Technical details and specifications | |
| - Viewing perspective and orientation | |
| - Any cross-sectional views or cutaway details needed | |
| - Dimensional relationships where relevant | |
| """ | |
| if specific_requirements: | |
| base_prompt += f"\nAdditional Requirements: {specific_requirements}\n" | |
| # Add figure-type specific guidance | |
| figure_guidance = { | |
| "technical_diagram": "Show the overall system with clear component relationships", | |
| "cross_section": "Provide internal view showing construction and operation", | |
| "system_overview": "Display complete system architecture and data flow", | |
| "component_breakdown": "Show detailed view of individual components and assemblies", | |
| "operational_flow": "Illustrate step-by-step operation or process flow", | |
| "detailed_cross_section": "Show internal construction with numbered components", | |
| "overall_system_diagram": "Display complete invention with all major elements", | |
| "assembly_view": "Show how components fit together in exploded or assembled view" | |
| } | |
| if figure_type in figure_guidance: | |
| base_prompt += f"\nSpecific guidance for {figure_type}: {figure_guidance[figure_type]}\n" | |
| base_prompt += """ | |
| Generate a detailed technical description that a patent illustrator could use to create | |
| a professional patent figure. Focus on technical accuracy and completeness.""" | |
| return base_prompt | |
| def _create_image_generation_prompt(self, | |
| invention_description: str, | |
| figure_type: str, | |
| specific_requirements: Optional[str] = None) -> str: | |
| """Create a prompt specifically for LaTeX/TikZ code generation. | |
| Args: | |
| invention_description: Description of the invention | |
| figure_type: Type of figure to generate | |
| specific_requirements: Additional requirements | |
| Returns: | |
| Optimized prompt for LaTeX/TikZ patent figure generation | |
| """ | |
| base_prompt = f"""Generate ONLY LaTeX/TikZ code for a professional patent figure showing: {invention_description} | |
| Figure Type: {figure_type} | |
| OUTPUT REQUIREMENTS: | |
| - Complete LaTeX document ready to compile | |
| - Start with \\documentclass{{article}} and end with \\end{{document}} | |
| - Include necessary packages: \\usepackage{{tikz}}, \\usepackage{{geometry}} | |
| - Professional patent-style technical drawing | |
| - Numbered components (1, 2, 3, etc.) with clear labels | |
| - Clean, precise TikZ drawing commands | |
| - No explanatory text - ONLY LaTeX code | |
| TECHNICAL DRAWING REQUIREMENTS: | |
| - Use TikZ \\draw commands for all shapes | |
| - Include numbered component labels with \\node commands | |
| - Proper scaling and positioning | |
| - Professional technical drawing style | |
| - Clear spatial relationships between components | |
| - Include connecting lines and annotations where relevant | |
| """ | |
| # Add figure-type specific visual guidance | |
| visual_guidance = { | |
| "technical_diagram": "Create an overall system diagram showing all major components and their connections", | |
| "cross_section": "Generate a cross-sectional view revealing internal construction and operation", | |
| "system_overview": "Draw a complete system architecture with clear component relationships", | |
| "component_breakdown": "Create an exploded view showing individual components and assemblies", | |
| "operational_flow": "Illustrate process flow with directional arrows and step indicators", | |
| "detailed_cross_section": "Show detailed internal construction with numbered components", | |
| "overall_system_diagram": "Display complete invention with all major elements labeled", | |
| "assembly_view": "Show component assembly with exploded or cutaway views" | |
| } | |
| if figure_type in visual_guidance: | |
| base_prompt += f"\nSpecific Visual Style: {visual_guidance[figure_type]}\n" | |
| if specific_requirements: | |
| base_prompt += f"\nAdditional Visual Requirements: {specific_requirements}\n" | |
| base_prompt += """ | |
| Generate a high-quality technical patent figure that meets USPTO standards for patent applications. | |
| The drawing should be clear, precise, and technically accurate.""" | |
| return base_prompt | |
| def integrate_with_patent_architect(self, | |
| invention_description: str, | |
| figure_descriptions: List[str] = None) -> Dict: | |
| """Enhanced integration point for Patent Architect AI v2 system with dual output. | |
| Args: | |
| invention_description: The invention being patented | |
| figure_descriptions: Specific figure descriptions needed | |
| Returns: | |
| Dict with enhanced content including both descriptions and LaTeX code | |
| """ | |
| try: | |
| if figure_descriptions is None: | |
| # Generate standard patent figures | |
| figure_types = ["overall_system_diagram", "detailed_cross_section", "component_breakdown"] | |
| results = [] | |
| for i, figure_type in enumerate(figure_types, 1): | |
| result = self.generate_dual_output_figure(invention_description, figure_type) | |
| if result["success"]: | |
| results.append({ | |
| "figure_number": i, | |
| "description": result["text_description"], | |
| "latex_code": result["latex_code"], | |
| "text_file_path": result["text_file_path"], | |
| "latex_file_path": result["latex_file_path"], | |
| "compiled_image_path": result.get("compiled_image_path"), | |
| "compilation_method": result.get("compilation_method"), | |
| "type": figure_type, | |
| "dual_output": True, | |
| "code_preview": result.get("code_preview", ""), | |
| "description_preview": result.get("description_preview", "") | |
| }) | |
| else: | |
| # Generate specific requested figures | |
| results = [] | |
| for i, description in enumerate(figure_descriptions, 1): | |
| result = self.generate_dual_output_figure( | |
| invention_description, | |
| f"custom_figure_{i}", | |
| description | |
| ) | |
| if result["success"]: | |
| results.append({ | |
| "figure_number": i, | |
| "description": result["text_description"], | |
| "latex_code": result["latex_code"], | |
| "text_file_path": result["text_file_path"], | |
| "latex_file_path": result["latex_file_path"], | |
| "compiled_image_path": result.get("compiled_image_path"), | |
| "compilation_method": result.get("compilation_method"), | |
| "type": "custom", | |
| "dual_output": True, | |
| "code_preview": result.get("code_preview", ""), | |
| "description_preview": result.get("description_preview", "") | |
| }) | |
| # Enhanced formatting for Patent Architect with dual output | |
| if results: | |
| content = "## π¨ Enhanced Patent Figures with Dual Output\n\n" | |
| # Count outputs | |
| total_figures = len(results) | |
| compiled_images = sum(1 for r in results if r.get("compiled_image_path")) | |
| local_compiled = sum(1 for r in results if r.get("compilation_method") == "local") | |
| web_compiled = sum(1 for r in results if r.get("compilation_method") == "web") | |
| content += f"*β¨ Generated {total_figures} complete figure sets with both detailed descriptions AND LaTeX/TikZ code*\n\n" | |
| if compiled_images > 0: | |
| content += f"*πΌοΈ {compiled_images}/{total_figures} figures successfully compiled to images" | |
| if local_compiled > 0: | |
| content += f" ({local_compiled} local" | |
| if web_compiled > 0: | |
| if local_compiled > 0: | |
| content += f", {web_compiled} web" | |
| else: | |
| content += f" ({web_compiled} web" | |
| content += " compilation)*\n\n" | |
| for figure in results: | |
| figure_title = figure['type'].replace('_', ' ').title() | |
| content += f"### Figure {figure['figure_number']}: {figure_title}\n\n" | |
| # Show compiled image if available | |
| if figure.get("compiled_image_path"): | |
| image_filename = os.path.basename(figure['compiled_image_path']) | |
| content += f"**πΌοΈ Compiled Image:** `{image_filename}` ({'Local' if figure.get('compilation_method') == 'local' else 'Web'} compilation)\n\n" | |
| # Always show detailed description | |
| content += f"**π Technical Description:**\n" | |
| content += f"{figure['description'][:500]}{'...' if len(figure['description']) > 500 else ''}\n\n" | |
| # Always show LaTeX code with enhanced instructions | |
| latex_filename = os.path.basename(figure['latex_file_path']) | |
| content += f"**π¨ LaTeX/TikZ Code:** `{latex_filename}`\n\n" | |
| # Show code preview | |
| if figure.get('code_preview'): | |
| content += f"**Code Preview:**\n```latex\n{figure['code_preview']}\n```\n\n" | |
| # Enhanced compilation options | |
| content += f"**π Multiple Viewing Options:**\n\n" | |
| if figure.get("compiled_image_path"): | |
| content += f"1. **β Pre-Compiled Image Available**: View `{os.path.basename(figure['compiled_image_path'])}` in output folder\n" | |
| content += f"2. **π Online Compilation (Easiest)**:\n" | |
| content += f" - Go to [Overleaf.com](https://overleaf.com) (free account)\n" | |
| content += f" - Create new project β Upload β Select `{latex_filename}`\n" | |
| content += f" - Click 'Recompile' for instant professional PDF\n" | |
| content += f" - Download PDF for USPTO submission\n\n" | |
| content += f"3. **π» Local Compilation**:\n" | |
| content += f" - Install LaTeX: [MiKTeX](https://miktex.org/) (Windows) or [TeX Live](https://www.tug.org/texlive/)\n" | |
| content += f" - Run: `pdflatex {latex_filename}`\n" | |
| content += f" - Convert to PNG: `pdftoppm -png -singlefile output.pdf figure`\n\n" | |
| content += f"4. **π± Mobile/Quick View**: Use [LaTeX Live](https://latexlive.com) - paste code for instant preview\n\n" | |
| # File information | |
| content += f"**π Generated Files:**\n" | |
| content += f"- π Description: `{os.path.basename(figure['text_file_path'])}`\n" | |
| content += f"- π¨ LaTeX Code: `{latex_filename}`\n" | |
| if figure.get("compiled_image_path"): | |
| content += f"- πΌοΈ Compiled Image: `{os.path.basename(figure['compiled_image_path'])}`\n" | |
| content += f"- π Location: `{os.path.dirname(figure['text_file_path'])}`\n\n" | |
| # Enhanced summary and guidance | |
| content += "---\n\n" | |
| content += f"**π Generation Summary:**\n" | |
| content += f"- **Total Figures:** {total_figures} complete sets\n" | |
| content += f"- **Dual Output:** β Both descriptions AND LaTeX code\n" | |
| content += f"- **Compiled Images:** {compiled_images} ready to view\n" | |
| content += f"- **USPTO Ready:** β Professional patent figure quality\n" | |
| content += f"- **Vector Graphics:** β Infinite scaling, publication quality\n\n" | |
| content += f"**π Why This is Better:**\n" | |
| content += f"- **Immediate Understanding:** Read detailed technical descriptions right now\n" | |
| content += f"- **Professional Quality:** LaTeX creates publication-grade vector graphics\n" | |
| content += f"- **Multiple Options:** View online (Overleaf), locally, or pre-compiled images\n" | |
| content += f"- **USPTO Preferred:** Vector graphics are ideal for patent applications\n" | |
| content += f"- **Editable:** Modify LaTeX code for custom adjustments\n\n" | |
| content += f"**π― Quick Start Guide:**\n" | |
| content += f"1. **Read the descriptions above** for immediate technical understanding\n" | |
| content += f"2. **View compiled images** if available in the output folder\n" | |
| content += f"3. **For publication quality**: Use Overleaf.com with the .tex files\n" | |
| content += f"4. **For USPTO submission**: Compile LaTeX to PDF for vector graphics\n\n" | |
| content += f"*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | Output: `{self.output_dir}`*\n\n" | |
| return { | |
| "success": True, | |
| "content": content, | |
| "figures": results, | |
| "total_figures": len(results), | |
| "dual_output": True, | |
| "compiled_images": compiled_images, | |
| "descriptions_available": total_figures, | |
| "latex_code_available": total_figures, | |
| "enhanced_features": [ | |
| "detailed_descriptions", | |
| "latex_tikz_code", | |
| "multiple_compilation_options", | |
| "pre_compiled_images", | |
| "overleaf_integration", | |
| "uspto_ready_output" | |
| ] | |
| } | |
| else: | |
| return { | |
| "success": False, | |
| "content": "### Technical Figures\n\nError generating enhanced patent figures. Please review invention description and try again.\n\n", | |
| "error": "No figures were successfully generated" | |
| } | |
| except Exception as e: | |
| return { | |
| "success": False, | |
| "content": f"### Technical Figures\n\nError: {str(e)}\n\nPlease check Gemini API configuration and try again.\n\n", | |
| "error": str(e) | |
| } | |
| def test_gemini_integration(): | |
| """Test the enhanced Gemini image generator integration.""" | |
| try: | |
| print("π¨ Testing Enhanced Gemini Patent Figure Generation...") | |
| print("=" * 60) | |
| generator = GeminiImageGenerator() | |
| test_invention = """ | |
| A smart coffee mug that maintains perfect temperature using phase-change materials | |
| and app control, solving the problem of coffee getting cold too quickly while | |
| providing personalized temperature preferences. | |
| """ | |
| print("π Test Invention: Smart coffee mug with temperature control") | |
| print(f"π Output Directory: {generator.output_dir}") | |
| print() | |
| # Test image generation capability | |
| print("π¬ Testing Individual Figure Generation...") | |
| result = generator.generate_patent_figure( | |
| test_invention, | |
| "technical_diagram", | |
| "Show the mug with phase-change material chambers and app connectivity" | |
| ) | |
| if result["success"]: | |
| if result.get("image_generated", False): | |
| print(f"β SUCCESS: Generated actual image!") | |
| print(f" π Image file: {result['image_path']}") | |
| print(f" π¨ Format: {result.get('mime_type', 'Unknown')}") | |
| else: | |
| print(f"βΉοΈ Generated detailed text description (image generation unavailable)") | |
| print(f" π Description file: {result['text_file_path']}") | |
| else: | |
| print(f"β Individual generation failed: {result.get('error', 'Unknown error')}") | |
| print() | |
| # Test full Patent Architect integration | |
| print("ποΈ Testing Patent Architect Integration...") | |
| integration_result = generator.integrate_with_patent_architect(test_invention) | |
| if integration_result["success"]: | |
| print("β Integration Success!") | |
| print(f" π Total Figures: {integration_result['total_figures']}") | |
| print(f" πΌοΈ Images Generated: {integration_result['images_generated']}") | |
| print(f" π Text Descriptions: {integration_result['text_descriptions']}") | |
| print() | |
| # Show a preview of the content | |
| content_preview = integration_result["content"][:500] + "..." if len(integration_result["content"]) > 500 else integration_result["content"] | |
| print("π Content Preview:") | |
| print("-" * 40) | |
| print(content_preview) | |
| print("-" * 40) | |
| else: | |
| print(f"β Integration failed: {integration_result.get('error', 'Unknown error')}") | |
| print() | |
| print("π API Status Check:") | |
| print(f" π API Key Available: {'β ' if os.environ.get('GEMINI_API_KEY') else 'β'}") | |
| print(f" π Internet Connection: {'β ' if True else 'β'}") # Simplified check | |
| print(f" π¦ Google GenAI Library: {'β ' if 'google.generativeai' in str(generator.model) else 'β'}") | |
| print() | |
| print("π― Next Steps:") | |
| if integration_result.get("images_generated", 0) > 0: | |
| print(" β’ Images successfully generated - check output directory") | |
| print(" β’ Patent Architect will display actual image files") | |
| print(" β’ Ready for professional patent application use") | |
| else: | |
| print(" β’ Currently generating detailed text descriptions") | |
| print(" β’ Gemini image generation API may be in development") | |
| print(" β’ Text descriptions are highly detailed and patent-ready") | |
| except Exception as e: | |
| print(f"β Test failed: {str(e)}") | |
| print("π‘ Troubleshooting:") | |
| print(" β’ Ensure GEMINI_API_KEY is set correctly") | |
| print(" β’ Check internet connection") | |
| print(" β’ Verify google-generativeai library is installed") | |
| def test_actual_image_capability(): | |
| """Specific test for actual image generation capability.""" | |
| try: | |
| print("π¨ Testing Actual Image Generation Capability...") | |
| print("=" * 50) | |
| generator = GeminiImageGenerator() | |
| # Simple test prompt for image generation | |
| simple_prompt = """Create a simple technical diagram showing a coffee mug with numbered components: | |
| 1. Coffee mug body | |
| 2. Temperature sensor | |
| 3. Heating element | |
| 4. App connectivity module | |
| Draw this as a black and white technical patent figure.""" | |
| print("π Testing with simple prompt...") | |
| try: | |
| response = generator.model.generate_content([simple_prompt]) | |
| print(f"π Response received") | |
| print(f" π Has text: {'β ' if hasattr(response, 'text') else 'β'}") | |
| print(f" πΌοΈ Has parts: {'β ' if hasattr(response, 'parts') else 'β'}") | |
| if hasattr(response, 'parts'): | |
| print(f" π Number of parts: {len(response.parts)}") | |
| for i, part in enumerate(response.parts): | |
| print(f" Part {i+1}: {type(part).__name__}") | |
| if hasattr(part, 'inline_data'): | |
| print(f" π Has inline data: β ") | |
| print(f" π¨ MIME type: {part.inline_data.mime_type}") | |
| else: | |
| print(f" οΏ½οΏ½ Has inline data: β") | |
| if hasattr(response, 'text') and response.text: | |
| preview = response.text[:200] + "..." if len(response.text) > 200 else response.text | |
| print(f" π Text preview: {preview}") | |
| except Exception as api_error: | |
| print(f"β API test failed: {str(api_error)}") | |
| except Exception as e: | |
| print(f"β Image capability test failed: {str(e)}") | |
| if __name__ == "__main__": | |
| # Run comprehensive tests | |
| test_gemini_integration() | |
| print("\n" + "=" * 60 + "\n") | |
| test_actual_image_capability() |