WHG2023
commited on
Commit
·
137c880
1
Parent(s):
4252b44
feat: Implement full agentic workflow with dual image generation
Browse filesThis commit introduces a true, stateful agentic negotiation process orchestrated by a Chief Strategist Agent. Key features include Segmind Ideogram API integration for conceptual images, real-time LaTeX compilation for viewable technical figures, and a complete, strategy-aligned patent draft generation.
- app.py +168 -733
- real_ai_agents_implementation.py +282 -513
- requirements.txt +7 -6
app.py
CHANGED
@@ -2,670 +2,179 @@ import gradio as gr
|
|
2 |
import os
|
3 |
import requests
|
4 |
import json
|
5 |
-
from typing import Dict, List
|
6 |
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
7 |
|
8 |
# Load environment variables from .env file
|
9 |
load_dotenv()
|
10 |
|
11 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
try:
|
13 |
from gemini_image_generator import GeminiImageGenerator
|
14 |
GEMINI_IMAGE_AVAILABLE = True
|
15 |
except ImportError:
|
16 |
GEMINI_IMAGE_AVAILABLE = False
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
#
|
31 |
-
|
32 |
-
from nebius_image_generator import integrate_with_patent_architect
|
33 |
-
NEBIUS_AVAILABLE = True
|
34 |
-
except ImportError:
|
35 |
-
NEBIUS_AVAILABLE = False
|
36 |
-
|
37 |
-
# Configuration for HuggingFace Spaces - no environment variables needed
|
38 |
-
|
39 |
-
# --- Configuration ---
|
40 |
-
# Using the clean Groq-only backend (reliable, no proxy issues)
|
41 |
-
MODAL_BACKEND_URL = "https://gebhardt-wolfh--patent-architect-groq-fastapi-app.modal.run"
|
42 |
-
# Alternative backends:
|
43 |
-
# - Nebius with images (experimental): "https://gebhardt-wolfh--patent-architect-nebius-clean-fastapi-app.modal.run"
|
44 |
-
# - Clean backend: "https://gebhardt-wolfh--patent-architect-clean-fastapi-app.modal.run"
|
45 |
-
|
46 |
-
# --- Enhanced Agent Personalities for Strategy Demo ---
|
47 |
-
AGENT_PERSONALITIES = {
|
48 |
-
"Technical Analysis Agent": {
|
49 |
-
"personality": "Technical Deep-Dive Specialist",
|
50 |
-
"thinking_style": "Analyzing technical mechanisms and specifications",
|
51 |
-
"catchphrase": "Understanding the physics behind the innovation",
|
52 |
-
"bias": "Demand detailed technical explanations and identify knowledge gaps",
|
53 |
-
"negotiation_weight": 0.20,
|
54 |
-
"expertise": "Technical feasibility, mechanism analysis, specification requirements"
|
55 |
-
},
|
56 |
-
"Prior Art Agent": {
|
57 |
-
"personality": "Patent Detective",
|
58 |
-
"thinking_style": "Comprehensive patent landscape analysis",
|
59 |
-
"catchphrase": "Finding every relevant patent and publication",
|
60 |
-
"bias": "Exhaustive prior art search across multiple technology domains",
|
61 |
-
"negotiation_weight": 0.25,
|
62 |
-
"expertise": "Patent databases, academic literature, international filings"
|
63 |
-
},
|
64 |
-
"Invention Summary Agent": {
|
65 |
-
"personality": "Technical Writer",
|
66 |
-
"thinking_style": "Creating precise technical narratives",
|
67 |
-
"catchphrase": "Crafting clear and compelling technical stories",
|
68 |
-
"bias": "Maximize technical clarity while highlighting true innovation",
|
69 |
-
"negotiation_weight": 0.15,
|
70 |
-
"expertise": "Technical writing, invention disclosure, differentiation"
|
71 |
-
},
|
72 |
-
"Figure Drafter Agent": {
|
73 |
-
"personality": "Technical Illustrator",
|
74 |
-
"thinking_style": "Designing patent drawings and diagrams",
|
75 |
-
"catchphrase": "Visual documentation of technical concepts",
|
76 |
-
"bias": "Ensure complete visual documentation of invention",
|
77 |
-
"negotiation_weight": 0.15,
|
78 |
-
"expertise": "Technical drawings, patent figures, visual communication"
|
79 |
-
},
|
80 |
-
"Claims Strategy Agent": {
|
81 |
-
"personality": "Patent Attorney",
|
82 |
-
"thinking_style": "Strategic patent claim optimization",
|
83 |
-
"catchphrase": "Crafting bulletproof patent claims",
|
84 |
-
"bias": "Balance broad protection with technical accuracy and grantability",
|
85 |
-
"negotiation_weight": 0.25,
|
86 |
-
"expertise": "Claim drafting, patent law, prosecution strategy"
|
87 |
-
}
|
88 |
-
}
|
89 |
-
|
90 |
-
# Enhanced IP Opportunity Categories with more specificity
|
91 |
-
IP_OPPORTUNITIES = [
|
92 |
-
{"type": "Core Technology Patent", "description": "Main invention with detailed technical claims"},
|
93 |
-
{"type": "Method Patents", "description": "Process and algorithmic innovations"},
|
94 |
-
{"type": "System Integration Patents", "description": "Combination with other technologies"},
|
95 |
-
{"type": "Application-Specific Patents", "description": "Industry-specific implementations"},
|
96 |
-
{"type": "Improvement Patents", "description": "Enhanced versions and optimizations"},
|
97 |
-
{"type": "Defensive Patents", "description": "Block competitor strategies"}
|
98 |
-
]
|
99 |
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
# If we have real AI results, use them for enhanced analysis
|
104 |
-
if real_ai_results and real_ai_results.get("available"):
|
105 |
-
markdown = f"### 🤖 Real AI Agent Analysis\n\n"
|
106 |
-
|
107 |
-
results = real_ai_results["results"]
|
108 |
-
readiness_score = real_ai_results["readiness_score"]
|
109 |
-
assessment = real_ai_results["assessment"]
|
110 |
-
|
111 |
-
# Technical Completeness
|
112 |
-
tech_analysis = real_ai_results.get("technical_analysis", {})
|
113 |
-
tech_score = tech_analysis.get("completeness_score", 0) * 100
|
114 |
-
risk_level = tech_analysis.get("prosecution_risk", "Unknown")
|
115 |
-
missing_elements = tech_analysis.get("missing_elements", [])
|
116 |
-
|
117 |
-
markdown += f"**🔬 Technical Completeness Agent:** {tech_score:.1f}%\n"
|
118 |
-
markdown += f"📊 Prosecution Risk: **{risk_level}**\n"
|
119 |
-
if missing_elements:
|
120 |
-
markdown += f"⚠️ Missing Critical Elements: {len(missing_elements)}\n"
|
121 |
-
for element in missing_elements[:2]: # Show first 2
|
122 |
-
markdown += f" • **{element.get('element_type', 'Unknown')}**: {element.get('suggestion', 'Needs improvement')}\n"
|
123 |
-
markdown += "\n"
|
124 |
-
|
125 |
-
# Prior Art Analysis
|
126 |
-
prior_art = real_ai_results.get("prior_art_analysis", {})
|
127 |
-
risk_assessment = prior_art.get("risk_assessment", {})
|
128 |
-
competitors = prior_art.get("key_competitors", [])
|
129 |
-
|
130 |
-
markdown += f"**🔍 Prior Art Landscape Agent:**\n"
|
131 |
-
markdown += f"📊 Risk Level: **{risk_assessment.get('overall_risk', 'Medium')}**\n"
|
132 |
-
if competitors:
|
133 |
-
markdown += f"🏢 Key Competitors: {len(competitors)}\n"
|
134 |
-
for comp in competitors[:2]: # Show first 2
|
135 |
-
markdown += f" • **{comp.get('company', 'Unknown')}**: {comp.get('patent_count', 0)} patents\n"
|
136 |
-
markdown += "\n"
|
137 |
-
|
138 |
-
# Claim Architecture
|
139 |
-
claim_analysis = real_ai_results.get("claim_analysis", {})
|
140 |
-
claim_strength = claim_analysis.get("claim_strength", {})
|
141 |
-
overall_strength = claim_strength.get("overall_strength", 0) * 100
|
142 |
-
|
143 |
-
markdown += f"**⚖️ Claim Architecture Agent:** {overall_strength:.1f}%\n"
|
144 |
-
markdown += f"📊 Grantability: **{claim_strength.get('grantability', 'Unknown')}**\n\n"
|
145 |
-
|
146 |
-
# Overall Assessment
|
147 |
-
markdown += f"**🎯 OVERALL READINESS ASSESSMENT:**\n"
|
148 |
-
markdown += f"**Score:** {readiness_score*100:.1f}% - **{assessment}**\n\n"
|
149 |
|
150 |
-
#
|
151 |
-
|
152 |
-
costs = results.get("estimated_costs", "Unknown")
|
153 |
-
markdown += f"**📈 Business Planning:**\n"
|
154 |
-
markdown += f"• **Timeline:** {timeline}\n"
|
155 |
-
markdown += f"• **Estimated Costs:** {costs}\n\n"
|
156 |
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
# Fallback to original negotiation display
|
167 |
-
total_weight = sum(AGENT_PERSONALITIES[agent["name"]]["negotiation_weight"] for agent in agent_responses if agent["name"] in AGENT_PERSONALITIES)
|
168 |
-
|
169 |
-
negotiations = []
|
170 |
-
for agent in agent_responses:
|
171 |
-
if agent["name"] in AGENT_PERSONALITIES:
|
172 |
-
personality = AGENT_PERSONALITIES[agent["name"]]
|
173 |
-
weight = personality["negotiation_weight"]
|
174 |
-
influence = (weight / total_weight) * 100 if total_weight > 0 else 0
|
175 |
-
|
176 |
-
# Enhanced negotiation points with technical depth
|
177 |
-
agent_type = agent["name"].split()[0].lower()
|
178 |
-
if agent_type == "technical":
|
179 |
-
position = f"Technical gaps identified: Missing mechanism details, frequency analysis specs, signal processing algorithms"
|
180 |
-
concern_level = "High"
|
181 |
-
elif agent_type == "prior":
|
182 |
-
num_patents = agent.get("num_patents", 1)
|
183 |
-
if num_patents < 10:
|
184 |
-
position = f"Shallow search: Only {num_patents} patents found. Missing ultrasonic sensors, acoustic emission, vibration analysis domains"
|
185 |
-
concern_level = "High"
|
186 |
-
else:
|
187 |
-
position = f"Comprehensive analysis: {num_patents} patents analyzed across multiple domains"
|
188 |
-
concern_level = "Low"
|
189 |
-
elif agent_type == "invention":
|
190 |
-
position = f"Technical clarity: Low - needs specific mechanism explanation, frequency ranges, sensor specifications"
|
191 |
-
concern_level = "Medium"
|
192 |
-
elif agent_type == "figure":
|
193 |
-
position = f"Visual documentation: Incomplete - needs actual technical drawings with numbered components"
|
194 |
-
concern_level = "Medium"
|
195 |
-
elif agent_type == "claims":
|
196 |
-
position = f"Claims analysis: Too broad, likely not novel - need specific technical limitations"
|
197 |
-
concern_level = "High"
|
198 |
-
else:
|
199 |
-
position = personality['bias']
|
200 |
-
concern_level = "Medium"
|
201 |
|
202 |
-
|
203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
"concern_level": concern_level,
|
210 |
-
"status_color": status_color,
|
211 |
-
"status": "Reviewing" if len(agent_responses) <= 3 else "Complete"
|
212 |
-
})
|
213 |
-
|
214 |
-
# Build markdown display with detailed feedback
|
215 |
-
markdown = f"### Multi-Agent Technical Review (Step {len(agent_responses)}/5)\n\n"
|
216 |
-
|
217 |
-
for neg in negotiations:
|
218 |
-
status_text = "(Active Review)" if neg["status"] == "Reviewing" else "(Complete)"
|
219 |
-
markdown += f"**{neg['name']}** {status_text} - {neg['influence']:.0f}% influence {neg['status_color']}\n"
|
220 |
-
markdown += f"Assessment: {neg['position']}\n"
|
221 |
-
markdown += f"Concern Level: {neg['concern_level']}\n\n"
|
222 |
-
|
223 |
-
# Calculate realistic consensus based on technical concerns
|
224 |
-
high_concerns = sum(1 for neg in negotiations if neg['concern_level'] == 'High')
|
225 |
-
medium_concerns = sum(1 for neg in negotiations if neg['concern_level'] == 'Medium')
|
226 |
-
|
227 |
-
if high_concerns >= 2:
|
228 |
-
consensus_level = 45
|
229 |
-
patentability_score = 4.5
|
230 |
-
outcome = "Major technical gaps identified. Invention needs significant development before patent filing."
|
231 |
-
elif high_concerns == 1 and medium_concerns >= 1:
|
232 |
-
consensus_level = 65
|
233 |
-
patentability_score = 6.5
|
234 |
-
outcome = "Technical issues identified. Requires expert review and refinement."
|
235 |
-
elif medium_concerns >= 2:
|
236 |
-
consensus_level = 75
|
237 |
-
patentability_score = 7.5
|
238 |
-
outcome = "Good foundation with areas for improvement. Recommend technical enhancement."
|
239 |
-
else:
|
240 |
-
consensus_level = 85
|
241 |
-
patentability_score = 8.5
|
242 |
-
outcome = "Strong technical foundation. Ready for expert patent attorney review."
|
243 |
-
|
244 |
-
markdown += f"**Technical Consensus:** {consensus_level}% - **Realistic Patentability Score: {patentability_score:.1f}/10**\n\n"
|
245 |
-
markdown += f"**Outcome:** {outcome}\n\n"
|
246 |
-
|
247 |
-
# Add specific recommendations based on critique
|
248 |
-
markdown += "**Expert Recommendations:**\n"
|
249 |
-
if high_concerns >= 1:
|
250 |
-
markdown += "• Conduct deeper technical development before patent filing\n"
|
251 |
-
markdown += "• Engage patent attorney for comprehensive prior art search\n"
|
252 |
-
markdown += "• Define specific technical mechanism and parameters\n"
|
253 |
-
markdown += "• Identify true novel contribution vs. existing art\n"
|
254 |
-
else:
|
255 |
-
markdown += "• Ready for professional patent attorney review\n"
|
256 |
-
markdown += "• Consider filing provisional patent for priority\n"
|
257 |
-
|
258 |
return markdown
|
259 |
|
260 |
-
def
|
261 |
-
"""Generates IP opportunity cards from backend data."""
|
262 |
-
if not opportunities:
|
263 |
-
return ""
|
264 |
-
|
265 |
-
html = """
|
266 |
-
<div style="background: #f8f9fa; border-radius: 10px; padding: 20px; margin: 20px 0;">
|
267 |
-
<h4 style="color: #333; margin-bottom: 15px;">Discovered IP Opportunities</h4>
|
268 |
-
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px;">
|
269 |
"""
|
270 |
-
|
271 |
-
|
272 |
-
score = opp.get("score", 75)
|
273 |
-
color = "#28a745" if score >= 85 else "#ffc107" if score >= 75 else "#17a2b8"
|
274 |
-
|
275 |
-
opp_info = next((o for o in IP_OPPORTUNITIES if o["type"] == opp.get("type")), IP_OPPORTUNITIES[0])
|
276 |
-
|
277 |
-
html += f"""
|
278 |
-
<div style="background: white; border: 2px solid {color}; border-radius: 8px; padding: 15px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
279 |
-
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
280 |
-
<h6 style="color: #333; margin: 0; font-size: 1.1em;">{opp.get('type', 'Opportunity')}</h6>
|
281 |
-
<span style="background: {color}; color: white; padding: 3px 8px; border-radius: 12px; font-size: 0.8em; font-weight: bold;">
|
282 |
-
{score}/100
|
283 |
-
</span>
|
284 |
-
</div>
|
285 |
-
<p style="color: #666; font-size: 0.9em; margin: 5px 0;">{opp.get('description', '')}</p>
|
286 |
-
<p style="color: #28a745; font-weight: bold; font-size: 0.8em; margin: 5px 0;">
|
287 |
-
Market: {opp.get('market_size', 'N/A')}
|
288 |
-
</p>
|
289 |
-
</div>
|
290 |
-
"""
|
291 |
-
|
292 |
-
html += """
|
293 |
-
</div>
|
294 |
-
</div>
|
295 |
"""
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
"
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
try:
|
304 |
-
# Initialize the coordinator
|
305 |
-
coordinator = InterAgentCoordinator()
|
306 |
-
|
307 |
-
# Run comprehensive analysis
|
308 |
-
results = coordinator.orchestrate_patent_development(invention_disclosure)
|
309 |
-
|
310 |
-
return {
|
311 |
-
"available": True,
|
312 |
-
"results": results,
|
313 |
-
"readiness_score": results.get("overall_readiness_score", 0),
|
314 |
-
"assessment": results.get("readiness_assessment", "Unknown"),
|
315 |
-
"technical_analysis": results.get("technical_completeness", {}),
|
316 |
-
"prior_art_analysis": results.get("prior_art_landscape", {}),
|
317 |
-
"claim_analysis": results.get("claim_architecture", {})
|
318 |
-
}
|
319 |
-
except Exception as e:
|
320 |
-
return {"available": False, "error": str(e)}
|
321 |
|
322 |
-
|
323 |
-
"""Enhanced patent section formatting with technical analysis and image generation."""
|
324 |
-
|
325 |
-
# Enhanced Figure Drafter Agent with Gemini and Nebius integration
|
326 |
-
if agent_name == "Figure Drafter Agent":
|
327 |
-
try:
|
328 |
-
# Try Gemini first (preferred for high-quality patent figures)
|
329 |
-
if GEMINI_IMAGE_AVAILABLE and os.environ.get("GEMINI_API_KEY"):
|
330 |
-
try:
|
331 |
-
print("🎨 Activating Gemini 2.0 Flash for patent figure generation...")
|
332 |
-
generator = GeminiImageGenerator()
|
333 |
-
|
334 |
-
# Extract invention description from content or use a default
|
335 |
-
# Look for invention context in the content
|
336 |
-
if "SUMMARY OF THE INVENTION" in content:
|
337 |
-
# Extract from summary section
|
338 |
-
start = content.find("SUMMARY OF THE INVENTION") + len("SUMMARY OF THE INVENTION")
|
339 |
-
end = content.find("'. This would include", start) if "'. This would include" in content[start:] else len(content)
|
340 |
-
invention_context = content[start:end].strip()[:800]
|
341 |
-
# Clean up the context
|
342 |
-
invention_context = invention_context.replace("The present invention relates to", "").replace("The present invention provides", "").strip()
|
343 |
-
else:
|
344 |
-
# Fallback: extract a reasonable description from the available content
|
345 |
-
invention_context = "Passive acoustic liquid level detection system with machine learning analysis"
|
346 |
-
|
347 |
-
print(f"🔍 Extracted invention context: {invention_context[:100]}...")
|
348 |
-
|
349 |
-
gemini_result = generator.integrate_with_patent_architect(invention_context)
|
350 |
-
|
351 |
-
if gemini_result.get("success"):
|
352 |
-
# COMPLETELY REPLACE the backend content with Gemini-generated content
|
353 |
-
content = gemini_result["content"]
|
354 |
-
|
355 |
-
# Check if we have dual output (descriptions + LaTeX)
|
356 |
-
if gemini_result.get("dual_output"):
|
357 |
-
# Enhanced dual output available
|
358 |
-
descriptions_available = gemini_result.get("descriptions_available", 0)
|
359 |
-
latex_available = gemini_result.get("latex_code_available", 0)
|
360 |
-
compiled_images = gemini_result.get("compiled_images", 0)
|
361 |
-
|
362 |
-
content += f"\n\n*🚀 Enhanced Dual Output: {descriptions_available} technical descriptions + {latex_available} LaTeX/TikZ code sets generated*\n\n"
|
363 |
-
|
364 |
-
if compiled_images > 0:
|
365 |
-
content += f"*🖼️ {compiled_images} figures successfully compiled to images - View immediately in output folder*\n\n"
|
366 |
-
|
367 |
-
content += f"*💡 Best Experience: Read descriptions above, then use LaTeX code with Overleaf.com for professional figures*\n\n"
|
368 |
-
|
369 |
-
# Update thought to reflect dual output
|
370 |
-
thought = f"Generated comprehensive dual output with {descriptions_available} detailed technical descriptions AND {latex_available} professional LaTeX/TikZ code sets. Users can read descriptions immediately and compile LaTeX for USPTO-ready vector graphics."
|
371 |
-
|
372 |
-
elif gemini_result.get("images_generated", 0) > 0:
|
373 |
-
if gemini_result.get("latex_generated", 0) > 0:
|
374 |
-
content += "\n\n*🎨 Generated LaTeX/TikZ code using Google Gemini 2.0 Flash - Compile with pdflatex to create professional patent figures*\n\n"
|
375 |
-
content += f"*💡 To view images: Compile the .tex files in `{os.path.expanduser('~')}/patent_architect_figures/`*\n\n"
|
376 |
-
thought = "Generated professional LaTeX/TikZ code for patent figures using Google Gemini 2.0 Flash. Code can be compiled to create high-quality technical drawings with numbered components and USPTO-ready formatting."
|
377 |
-
else:
|
378 |
-
content += "\n\n*🎨 Generated visual patent figures using Google Gemini 2.0 Flash - Professional images ready for USPTO submission*\n\n"
|
379 |
-
thought = "Generated high-quality patent figures using Google Gemini 2.0 Flash with professional technical drawings, numbered components, and USPTO-ready formatting."
|
380 |
-
else:
|
381 |
-
content += "\n\n*📝 Generated detailed patent figure descriptions using Google Gemini 2.0 Flash - Professional technical specifications*\n\n"
|
382 |
-
thought = "Generated detailed technical specifications for patent figures using Google Gemini 2.0 Flash with professional patent formatting."
|
383 |
-
|
384 |
-
print("✅ Gemini image generation successful - Backend content replaced")
|
385 |
-
|
386 |
-
else:
|
387 |
-
print(f"❌ Gemini generation failed: {gemini_result.get('error', 'Unknown error')}")
|
388 |
-
|
389 |
-
except Exception as e:
|
390 |
-
print(f"❌ Gemini integration error: {e}")
|
391 |
-
|
392 |
-
# Fallback to Nebius if Gemini failed or unavailable
|
393 |
-
elif NEBIUS_AVAILABLE and not image_urls:
|
394 |
-
try:
|
395 |
-
if "figure" in content.lower() or "drawing" in content.lower():
|
396 |
-
figure_descriptions = [
|
397 |
-
"Cross-sectional view showing main components",
|
398 |
-
"System diagram showing connections"
|
399 |
-
]
|
400 |
-
|
401 |
-
from dotenv import load_dotenv
|
402 |
-
load_dotenv()
|
403 |
-
|
404 |
-
if os.environ.get("NEBIUS_API_KEY"):
|
405 |
-
nebius_result = integrate_with_patent_architect(
|
406 |
-
invention_description="Technical invention with numbered components",
|
407 |
-
figure_descriptions=figure_descriptions
|
408 |
-
)
|
409 |
-
|
410 |
-
if nebius_result.get("success"):
|
411 |
-
content = nebius_result["content"]
|
412 |
-
image_urls = nebius_result.get("image_urls", [])
|
413 |
-
content += "\n\n*🖼️ Generated using Nebius AI - Enhanced with visual diagrams*\n\n"
|
414 |
-
print("✅ Nebius image generation successful")
|
415 |
-
|
416 |
-
except Exception as e:
|
417 |
-
print(f"❌ Nebius integration error: {e}")
|
418 |
-
|
419 |
-
# If no image generation available, enhance the text-based content
|
420 |
-
else:
|
421 |
-
# Check if this is Groq's "no image generation" content
|
422 |
-
if "image generation is not available with groq" in content.lower() or "since image generation is not available" in content.lower():
|
423 |
-
# Replace Groq's limitation message with enhancement message
|
424 |
-
content = content.replace(
|
425 |
-
"Generated detailed text descriptions for patent figures since image generation is not available with Groq.",
|
426 |
-
"Enhanced patent figure descriptions with detailed technical specifications."
|
427 |
-
)
|
428 |
-
content = content.replace(
|
429 |
-
"Since image generation is not available with Groq, here are detailed descriptions",
|
430 |
-
"Enhanced technical figure descriptions with professional patent formatting"
|
431 |
-
)
|
432 |
-
content += f"\n\n*💡 To enable professional image generation: Set GEMINI_API_KEY environment variable and get API key from https://makersuite.google.com/app/apikey*\n\n"
|
433 |
-
|
434 |
-
# Add critique-based improvements to figure descriptions
|
435 |
-
content += "\n\n### 🎯 Figure Enhancement Recommendations:\n"
|
436 |
-
content += "• **Missing Elements:** Numbered components, dimension lines, material callouts\n"
|
437 |
-
content += "• **Technical Precision:** Frequency response curves, signal processing flow\n"
|
438 |
-
content += "• **Patent Standards:** USPTO figure requirements compliance\n"
|
439 |
-
content += "• **Professional Quality:** Vector graphics suitable for patent submission\n\n"
|
440 |
-
|
441 |
-
print("✅ Enhanced Groq content with detailed recommendations")
|
442 |
-
|
443 |
-
except Exception as e:
|
444 |
-
print(f"❌ Figure generation error: {e}")
|
445 |
-
content += f"\n\n*⚠️ Image generation unavailable. Please check API configuration.*\n\n"
|
446 |
-
|
447 |
-
# Enhanced Prior Art Agent feedback
|
448 |
-
elif agent_name == "Prior Art Agent":
|
449 |
-
# Count sources and provide detailed analysis
|
450 |
-
num_sources = len(sources) if sources else 0
|
451 |
-
|
452 |
-
if num_sources < 10:
|
453 |
-
content += f"\n\n### ⚠️ Prior Art Search Limitations:\n"
|
454 |
-
content += f"• **Sources Found:** Only {num_sources} patents/publications\n"
|
455 |
-
content += f"• **Missing Domains:** Ultrasonic sensors, acoustic emission monitoring, vibration analysis\n"
|
456 |
-
content += f"• **Incomplete Coverage:** International patents, academic literature, industry standards\n"
|
457 |
-
content += f"• **Recommendation:** Comprehensive search required before filing\n\n"
|
458 |
-
|
459 |
-
content += f"### 🔍 Suggested Additional Search Terms:\n"
|
460 |
-
content += f"• Ultrasonic level detection patents\n"
|
461 |
-
content += f"• Acoustic emission sensors\n"
|
462 |
-
content += f"• Passive vibration monitoring\n"
|
463 |
-
content += f"• Machine learning signal processing\n"
|
464 |
-
content += f"• Non-invasive liquid measurement\n\n"
|
465 |
-
|
466 |
-
# Enhanced Claims Strategy Agent feedback
|
467 |
-
elif agent_name == "Claims Drafter Agent": # Fixed: Backend sends "Claims Drafter Agent"
|
468 |
-
# Analyze claims for common issues
|
469 |
-
if "acoustic sensor" in content.lower() and "passive" in content.lower():
|
470 |
-
content += f"\n\n### ⚠️ Claims Analysis - Critical Issues:\n"
|
471 |
-
content += f"• **Overly Broad:** Claims 1 likely lacks novelty (passive acoustic sensors exist)\n"
|
472 |
-
content += f"• **Missing Specificity:** No technical limitations on frequency analysis method\n"
|
473 |
-
content += f"• **Weak Differentiation:** Doesn't capture unique ML training approach\n"
|
474 |
-
content += f"• **Patent Risk:** Current claims may be rejected for obviousness\n\n"
|
475 |
-
|
476 |
-
content += f"### 🎯 Recommended Claim Improvements:\n"
|
477 |
-
content += f"• Focus on specific frequency change detection method\n"
|
478 |
-
content += f"• Add ML model architecture and training claims\n"
|
479 |
-
content += f"• Include anomaly detection for bubbles/splashes\n"
|
480 |
-
content += f"• Define technical parameters (frequency ranges, sensitivity)\n\n"
|
481 |
-
|
482 |
-
# Format agent response with enhanced personality
|
483 |
-
if agent_name in AGENT_PERSONALITIES:
|
484 |
-
personality = AGENT_PERSONALITIES[agent_name]
|
485 |
-
|
486 |
-
formatted = f"### {agent_name}\n\n"
|
487 |
-
|
488 |
-
# Add thinking process if available
|
489 |
-
if thought:
|
490 |
-
formatted += f"**Agent Analysis:**\n{thought}\n\n"
|
491 |
-
|
492 |
-
formatted += content
|
493 |
-
|
494 |
-
# Add enhanced strategy note with expertise
|
495 |
-
formatted += f"\n\n*Strategy: {personality['bias']}*\n"
|
496 |
-
formatted += f"*Expertise: {personality.get('expertise', 'General patent analysis')}*\n\n"
|
497 |
-
|
498 |
-
else:
|
499 |
-
# Fallback for unknown agents
|
500 |
-
formatted = f"### {agent_name}\n\n"
|
501 |
-
if thought:
|
502 |
-
formatted += f"**Analysis:** {thought}\n\n"
|
503 |
-
formatted += content
|
504 |
-
|
505 |
-
# Add sources if available with enhanced formatting
|
506 |
-
if sources and len(sources) > 0:
|
507 |
-
formatted += "\n\n**📚 Prior Art Sources:**\n"
|
508 |
-
for i, source in enumerate(sources, 1):
|
509 |
-
if source.get('url'):
|
510 |
-
formatted += f"{i}. [{source.get('title', 'Patent Source')}]({source.get('url')})\n"
|
511 |
-
|
512 |
-
# Add search quality assessment
|
513 |
-
if len(sources) < 10:
|
514 |
-
formatted += f"\n*⚠️ Limited search results ({len(sources)} sources). Comprehensive search recommended.*\n"
|
515 |
-
|
516 |
-
return formatted
|
517 |
|
518 |
-
def run_patent_architect_in_ui(invention_disclosure):
|
519 |
-
"""Enhanced UI function with agent personalities and IP discovery."""
|
520 |
if not invention_disclosure:
|
521 |
-
|
522 |
-
|
523 |
-
"opportunities": gr.HTML.update(value="<h3>IP Opportunities</h3><p>Enter invention to discover patent opportunities</p>"),
|
524 |
-
"negotiation": gr.Markdown.update(value="### Agent Negotiation\n\nAgents will negotiate optimal strategy"),
|
525 |
-
"prior_art": gr.Markdown.update(value="### Prior Art Analysis\n\n*This section will show the analysis of existing patents and technologies related to your invention.*"),
|
526 |
-
"summary": gr.Markdown.update(value="### Invention Summary\n\n*This section will contain the professional Background of the Invention and Summary of the Invention sections.*"),
|
527 |
-
"figures": gr.Markdown.update(value="### Technical Figures\n\n*This section will display the generated patent-style technical drawings with numbered components.*"),
|
528 |
-
"claims": gr.Markdown.update(value="### Patent Claims\n\n*This section will contain the numbered patent claims that legally define the scope of your invention.*"),
|
529 |
-
"status": "Enhanced Patent Architect v2 - Ready for rigorous technical analysis",
|
530 |
-
}
|
531 |
-
yield list(outputs.values())
|
532 |
return
|
533 |
|
534 |
-
if not
|
535 |
-
|
536 |
-
|
|
|
537 |
return
|
538 |
-
|
539 |
-
# Initialize all sections with clean interface
|
540 |
-
opportunities_html = create_ip_opportunity_cards([])
|
541 |
-
|
542 |
-
# Run real AI analysis if available
|
543 |
-
real_ai_results = None
|
544 |
-
if REAL_AI_AGENTS_AVAILABLE:
|
545 |
-
status = "🤖 Running Real AI Agent Analysis..."
|
546 |
-
yield opportunities_html, "### Real AI Analysis\n\nRunning comprehensive technical analysis...", "### Prior Art Analysis\n\n*Waiting for technical analysis...*", "### Invention Summary\n\n*Waiting for analysis...*", "### Technical Figures\n\n*Waiting for analysis...*", "### Patent Claims\n\n*Waiting for analysis...*", status
|
547 |
|
548 |
-
|
549 |
-
|
550 |
-
if real_ai_results.get("available"):
|
551 |
-
status = f"✅ Real AI Analysis Complete - Readiness: {real_ai_results['readiness_score']*100:.1f}%"
|
552 |
-
else:
|
553 |
-
status = f"⚠️ Real AI Analysis Failed: {real_ai_results.get('error', 'Unknown error')}"
|
554 |
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
yield opportunities_html, negotiation_display, prior_art_section, summary_section, figures_section, claims_section, status
|
563 |
-
|
564 |
-
try:
|
565 |
-
print(f"Connecting to Patent Architect backend: {MODAL_BACKEND_URL}")
|
566 |
|
567 |
-
#
|
568 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
569 |
|
570 |
-
|
571 |
-
f"{
|
572 |
-
json={"invention_disclosure": invention_disclosure},
|
573 |
-
timeout=1800, # 30 minute timeout for full patent generation
|
574 |
-
stream=True
|
575 |
-
) as response:
|
576 |
-
response.raise_for_status()
|
577 |
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
opportunities_html = create_ip_opportunity_cards(opportunities)
|
602 |
-
prior_art_section = "### Prior Art Analysis\n\n*Prior Art Specialist is searching patent databases...*"
|
603 |
-
status = f"Step {step_info} Complete: IP Opportunity Agent found {len(opportunities)} new avenues"
|
604 |
-
yield opportunities_html, negotiation_display, prior_art_section, summary_section, figures_section, claims_section, status
|
605 |
-
continue
|
606 |
-
|
607 |
-
agent_name = data.get("agent_name", "Patent Agent")
|
608 |
-
content = data.get("content", "")
|
609 |
-
thought = data.get("thought", "")
|
610 |
-
sources = data.get("sources", [])
|
611 |
-
image_urls = data.get("image_urls", [])
|
612 |
-
|
613 |
-
formatted_content = format_patent_section(agent_name, content, thought, sources, image_urls)
|
614 |
-
|
615 |
-
# Update the appropriate section based on the agent's designated section_type
|
616 |
-
if section_type == "prior_art":
|
617 |
-
prior_art_section = formatted_content
|
618 |
-
summary_section = "### Invention Summary\n\n*Technical Writer is crafting your invention story...*"
|
619 |
-
|
620 |
-
# Update negotiation based on real patent count
|
621 |
-
num_patents = len(sources)
|
622 |
-
agent_responses = [{"name": agent_name, "num_patents": num_patents}]
|
623 |
-
negotiation_display = create_agent_negotiation_display(agent_responses, real_ai_results)
|
624 |
-
|
625 |
-
elif section_type == "summary":
|
626 |
-
summary_section = formatted_content
|
627 |
-
figures_section = "### Technical Figures\n\n*Technical Illustrator is designing patent drawings...*"
|
628 |
-
|
629 |
-
# This assumes prior_art ran first and initialized agent_responses
|
630 |
-
agent_responses.append({"name": agent_name})
|
631 |
-
negotiation_display = create_agent_negotiation_display(agent_responses, real_ai_results)
|
632 |
-
|
633 |
-
elif section_type == "figures":
|
634 |
-
figures_section = formatted_content
|
635 |
-
claims_section = "### Patent Claims\n\n*Patent Attorney is optimizing claim scope...*"
|
636 |
-
|
637 |
-
agent_responses.append({"name": agent_name})
|
638 |
-
negotiation_display = create_agent_negotiation_display(agent_responses, real_ai_results)
|
639 |
-
|
640 |
-
elif section_type == "claims":
|
641 |
-
claims_section = formatted_content
|
642 |
-
|
643 |
-
agent_responses.append({"name": agent_name})
|
644 |
-
negotiation_display = create_agent_negotiation_display(agent_responses, real_ai_results)
|
645 |
-
|
646 |
-
# Enhanced status with agent personality
|
647 |
-
if agent_name in AGENT_PERSONALITIES:
|
648 |
-
personality = AGENT_PERSONALITIES[agent_name]["personality"]
|
649 |
-
status = f"Step {step_info} Complete: {personality} has finished their analysis"
|
650 |
-
else:
|
651 |
-
status = f"Step {step_info} Complete: {agent_name} finished"
|
652 |
-
|
653 |
-
elif event_status == "assembling":
|
654 |
-
status = event.get("log", "Assembling patent application...")
|
655 |
-
|
656 |
-
elif event_status == "complete":
|
657 |
-
status = "Patent Application Complete - Ready for review and filing"
|
658 |
-
|
659 |
-
yield opportunities_html, negotiation_display, prior_art_section, summary_section, figures_section, claims_section, status
|
660 |
-
|
661 |
-
except json.JSONDecodeError as e:
|
662 |
-
print(f"Could not decode JSON from stream: {decoded_line}")
|
663 |
-
continue
|
664 |
|
665 |
-
|
666 |
-
|
667 |
-
status = "Connection Failed"
|
668 |
-
yield opportunities_html, negotiation_display, prior_art_section, summary_section, figures_section, claims_section, status
|
669 |
|
670 |
with gr.Blocks(theme=gr.themes.Base(primary_hue="green", neutral_hue="slate"), title="Patent Architect v2") as demo:
|
671 |
gr.HTML("""
|
@@ -709,7 +218,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue="green", neutral_hue="slate"), t
|
|
709 |
color: #00ff41;
|
710 |
opacity: 0.8;
|
711 |
position: relative;
|
712 |
-
z-index: 1;">POWERED BY GEMINI
|
713 |
</div>
|
714 |
""")
|
715 |
|
@@ -795,25 +304,17 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue="green", neutral_hue="slate"), t
|
|
795 |
invention_input = gr.Textbox(
|
796 |
lines=12,
|
797 |
label="Neural Disclosure Interface",
|
798 |
-
placeholder="""
|
799 |
-
|
800 |
-
|
801 |
-
▶ Technical architecture and component flow
|
802 |
-
▶ Novelty differentiators vs existing systems
|
803 |
-
▶ Advantage metrics and performance data
|
804 |
-
▶ Technical specifications and parameters
|
805 |
-
|
806 |
-
EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizing phase-change material matrices with neural app integration, eliminating thermal degradation issues through adaptive preference algorithms..."
|
807 |
-
""",
|
808 |
-
info="Enhanced neural processing requires detailed technical specifications"
|
809 |
)
|
810 |
|
811 |
-
generate_btn = gr.Button("INITIATE
|
812 |
|
813 |
status_display = gr.Textbox(
|
814 |
label="System Status",
|
815 |
interactive=False,
|
816 |
-
value="
|
817 |
)
|
818 |
|
819 |
gr.HTML("""
|
@@ -824,7 +325,6 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
824 |
</div>
|
825 |
""")
|
826 |
|
827 |
-
# Enhanced Technical Intelligence Dashboard
|
828 |
gr.HTML("""
|
829 |
<div style="background: linear-gradient(45deg, #0a0a0a, #1a1a1a);
|
830 |
border: 1px solid #ff8c00;
|
@@ -836,25 +336,14 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
836 |
text-shadow: 0 0 5px #ff8c00;
|
837 |
font-size: 1.6em;
|
838 |
margin: 0;
|
839 |
-
text-transform: uppercase;">
|
840 |
</div>
|
841 |
""")
|
842 |
|
843 |
with gr.Row():
|
844 |
-
with gr.Column():
|
845 |
-
|
846 |
-
|
847 |
-
border: 1px solid #00ff41;
|
848 |
-
padding: 15px;
|
849 |
-
color: #00ff41;
|
850 |
-
font-family: 'Courier New', monospace;">
|
851 |
-
<h3 style="color: #00ff41; margin: 0;">IP OPPORTUNITY MATRIX</h3>
|
852 |
-
<p style="color: #ff8c00;">Patent vectors will materialize here</p>
|
853 |
-
</div>
|
854 |
-
""")
|
855 |
-
with gr.Column():
|
856 |
-
negotiation_display = gr.Markdown("### AGENT NEGOTIATION PROTOCOL\n\nMulti-agent consensus algorithm initializing...")
|
857 |
-
|
858 |
gr.HTML("""
|
859 |
<div style="height: 2px;
|
860 |
background: linear-gradient(90deg, #ff8c00, #ffff00, #00ff41, #ff8c00);
|
@@ -874,47 +363,46 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
874 |
text-shadow: 0 0 5px #00ff41;
|
875 |
font-size: 1.6em;
|
876 |
margin: 0;
|
877 |
-
text-transform: uppercase;">
|
878 |
</div>
|
879 |
""")
|
880 |
|
881 |
with gr.Tabs():
|
882 |
-
with gr.TabItem("PRIOR ART
|
883 |
prior_art_output = gr.Markdown(
|
884 |
-
value="### Prior Art Analysis\n\
|
885 |
)
|
886 |
with gr.TabItem("TECHNICAL SUMMARY"):
|
887 |
summary_output = gr.Markdown(
|
888 |
-
value="### Invention Summary\n\
|
889 |
)
|
890 |
with gr.TabItem("TECHNICAL FIGURES"):
|
891 |
figures_output = gr.Markdown(
|
892 |
-
value="### Technical Figures\n\
|
893 |
)
|
894 |
with gr.TabItem("PATENT CLAIMS"):
|
895 |
claims_output = gr.Markdown(
|
896 |
-
value="### Patent Claims\n\
|
897 |
)
|
898 |
|
899 |
generate_btn.click(
|
900 |
fn=run_patent_architect_in_ui,
|
901 |
inputs=[invention_input],
|
902 |
-
outputs=[
|
903 |
)
|
904 |
|
905 |
gr.Examples(
|
906 |
[
|
907 |
-
["
|
908 |
-
["A modular vertical farming system with adaptive LED lighting using full-spectrum arrays (400-700nm) controlled by neural network analysis of plant reflectance spectra. The system employs RGB+NIR sensors to monitor chlorophyll content and adjusts light intensity (50-1000 μmol/m²/s) and spectrum ratios based on growth stage detection. Machine learning models trained on 500+ crop cycles optimize photosynthetic photon flux density while reducing energy consumption by 35% compared to static lighting systems."],
|
909 |
-
["A real-time presentation skills assessment device using micro-expression analysis with 60fps facial recognition and voice stress analysis at 16kHz sampling. The system employs convolutional neural networks trained on 10,000+ presentation recordings to detect confidence indicators including facial micro-movements, vocal pitch variations (±50Hz accuracy), and gesture patterns. Feedback is provided through bone conduction audio and haptic vibration patterns calibrated to individual baseline metrics."],
|
910 |
],
|
911 |
inputs=[invention_input],
|
912 |
-
label="
|
913 |
)
|
914 |
|
915 |
gr.HTML("""
|
916 |
<style>
|
917 |
-
/*
|
918 |
.gradio-button.primary {
|
919 |
background: linear-gradient(45deg, #00ff41, #ffff00) !important;
|
920 |
border: 2px solid #00ff41 !important;
|
@@ -935,13 +423,11 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
935 |
border-color: #ffff00 !important;
|
936 |
}
|
937 |
|
938 |
-
/* Dark theme for the overall interface */
|
939 |
.gradio-container {
|
940 |
background: #0a0a0a !important;
|
941 |
font-family: 'Courier New', monospace !important;
|
942 |
}
|
943 |
|
944 |
-
/* Tab styling */
|
945 |
.tab-nav button {
|
946 |
background: linear-gradient(45deg, #1a1a1a, #0a0a0a) !important;
|
947 |
border: 1px solid #00ff41 !important;
|
@@ -957,7 +443,6 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
957 |
box-shadow: 0 0 10px #00ff41 !important;
|
958 |
}
|
959 |
|
960 |
-
/* Input field styling */
|
961 |
.gr-textbox {
|
962 |
background: linear-gradient(45deg, #0a0a0a, #1a1a1a) !important;
|
963 |
border: 1px solid #00ff41 !important;
|
@@ -970,69 +455,19 @@ EXAMPLE NEURAL INPUT: "Autonomous beverage temperature regulation system utilizi
|
|
970 |
box-shadow: 0 0 10px #ffff00 !important;
|
971 |
}
|
972 |
|
973 |
-
/* Remove default fonts and prevent loading errors */
|
974 |
* {
|
975 |
font-family: 'Courier New', monospace !important;
|
976 |
}
|
977 |
-
|
978 |
-
/* Scanline effect overlay */
|
979 |
-
body::before {
|
980 |
-
content: '';
|
981 |
-
position: fixed;
|
982 |
-
top: 0;
|
983 |
-
left: 0;
|
984 |
-
width: 100%;
|
985 |
-
height: 100%;
|
986 |
-
background: repeating-linear-gradient(
|
987 |
-
0deg,
|
988 |
-
transparent,
|
989 |
-
transparent 2px,
|
990 |
-
rgba(0,255,65,0.03) 2px,
|
991 |
-
rgba(0,255,65,0.03) 4px
|
992 |
-
);
|
993 |
-
pointer-events: none;
|
994 |
-
z-index: 1000;
|
995 |
-
}
|
996 |
</style>
|
997 |
-
|
998 |
-
<script>
|
999 |
-
// Suppress browser errors and warnings
|
1000 |
-
const originalConsoleError = console.error;
|
1001 |
-
console.error = function(...args) {
|
1002 |
-
const message = args.join(' ');
|
1003 |
-
if (message.includes('manifest.json') ||
|
1004 |
-
message.includes('Failed to load resource') ||
|
1005 |
-
message.includes('postMessage') ||
|
1006 |
-
message.includes('preload CSS') ||
|
1007 |
-
message.includes('.woff2')) {
|
1008 |
-
return; // Skip these specific errors
|
1009 |
-
}
|
1010 |
-
originalConsoleError.apply(console, args);
|
1011 |
-
};
|
1012 |
-
|
1013 |
-
// Add glitch effect to title
|
1014 |
-
document.addEventListener('DOMContentLoaded', function() {
|
1015 |
-
const title = document.querySelector('h1');
|
1016 |
-
if (title) {
|
1017 |
-
setInterval(() => {
|
1018 |
-
if (Math.random() < 0.1) {
|
1019 |
-
title.style.textShadow = '2px 0 #ff8c00, -2px 0 #00ff41';
|
1020 |
-
setTimeout(() => {
|
1021 |
-
title.style.textShadow = '0 0 10px #00ff41, 0 0 20px #00ff41, 0 0 30px #00ff41';
|
1022 |
-
}, 100);
|
1023 |
-
}
|
1024 |
-
}, 2000);
|
1025 |
-
}
|
1026 |
-
});
|
1027 |
-
</script>
|
1028 |
""")
|
1029 |
|
1030 |
if __name__ == "__main__":
|
1031 |
-
print("PATENT ARCHITECT v2 -
|
1032 |
-
print(f"Backend: {
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
|
|
1036 |
demo.queue().launch(
|
1037 |
share=False,
|
1038 |
show_error=True
|
|
|
2 |
import os
|
3 |
import requests
|
4 |
import json
|
5 |
+
from typing import Dict, List, Generator, Optional
|
6 |
from dotenv import load_dotenv
|
7 |
+
import base64
|
8 |
+
import tempfile
|
9 |
+
import re
|
10 |
+
import urllib.parse
|
11 |
|
12 |
# Load environment variables from .env file
|
13 |
load_dotenv()
|
14 |
|
15 |
+
# --- New Agentic Backend Integration ---
|
16 |
+
try:
|
17 |
+
from real_ai_agents_implementation import AgenticNegotiator, NegotiationState
|
18 |
+
AGENTIC_BACKEND_AVAILABLE = True
|
19 |
+
except ImportError as e:
|
20 |
+
print(f"Failed to import agentic backend: {e}")
|
21 |
+
AGENTIC_BACKEND_AVAILABLE = False
|
22 |
+
|
23 |
+
# Keep Gemini Image Generator for LaTeX compilation
|
24 |
try:
|
25 |
from gemini_image_generator import GeminiImageGenerator
|
26 |
GEMINI_IMAGE_AVAILABLE = True
|
27 |
except ImportError:
|
28 |
GEMINI_IMAGE_AVAILABLE = False
|
29 |
|
30 |
+
def compile_latex_to_image(latex_code: str) -> Optional[str]:
|
31 |
+
"""Try to compile LaTeX code to an image using a web service."""
|
32 |
+
if not latex_code:
|
33 |
+
return None
|
34 |
+
try:
|
35 |
+
# Prepare the LaTeX code by finding the relevant part
|
36 |
+
# A more robust regex to find either a full document or just a tikzpicture
|
37 |
+
match = re.search(r'(\\documentclass.*?\\end{document})|(\\begin{tikzpicture}.*?\\end{tikzpicture})', latex_code, re.DOTALL)
|
38 |
+
if match:
|
39 |
+
# Prioritize the full document if both are somehow present, otherwise take what was found
|
40 |
+
content_to_render = match.group(1) if match.group(1) else match.group(2)
|
41 |
+
else:
|
42 |
+
# Fallback if no standard block is found
|
43 |
+
content_to_render = latex_code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
+
# URL encode the LaTeX content for the API
|
46 |
+
encoded_latex = urllib.parse.quote(content_to_render)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
+
# Use a reliable web service for compilation
|
49 |
+
api_url = f"https://latex.codecogs.com/png.latex?{encoded_latex}"
|
|
|
|
|
|
|
|
|
50 |
|
51 |
+
response = requests.get(api_url, timeout=20)
|
52 |
+
if response.status_code == 200 and response.headers.get('content-type', '').startswith('image/'):
|
53 |
+
# Convert the successful image response to a base64 data URI
|
54 |
+
image_b64 = base64.b64encode(response.content).decode('utf-8')
|
55 |
+
return f"data:image/png;base64,{image_b64}"
|
56 |
+
else:
|
57 |
+
print(f"LaTeX compilation failed with status: {response.status_code}")
|
58 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
+
except Exception as e:
|
61 |
+
print(f"An error occurred during LaTeX compilation: {e}")
|
62 |
+
return None
|
63 |
+
|
64 |
+
def create_negotiation_transcript_display(transcript: List[Dict]) -> str:
|
65 |
+
"""Creates a markdown display for the agent negotiation transcript."""
|
66 |
+
if not transcript:
|
67 |
+
return "### Agent Negotiation Log\n\n*Awaiting instructions...*"
|
68 |
+
|
69 |
+
markdown = "### Agent Negotiation Log\n\n---\n\n"
|
70 |
+
for entry in transcript:
|
71 |
+
agent = entry.get('agent', 'System')
|
72 |
+
message = entry.get('message', '')
|
73 |
+
|
74 |
+
# Make the agent name bold and add color
|
75 |
+
if agent == "Chief Strategist":
|
76 |
+
color = "#ff8c00" # Orange
|
77 |
+
elif agent == "Conceptual Artist":
|
78 |
+
color = "#da70d6" # Orchid
|
79 |
+
elif agent == "System":
|
80 |
+
color = "#ff4d4d" # Red
|
81 |
+
else:
|
82 |
+
color = "#00ff41" # Green
|
83 |
|
84 |
+
markdown += f"<p style='color: {color}; margin-bottom: 5px;'><strong>🤖 {agent}:</strong></p>\n"
|
85 |
+
markdown += f"<p style='margin-left: 20px; margin-top: 0px;'>{message}</p>\n\n"
|
86 |
+
markdown += "---\n\n"
|
87 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
return markdown
|
89 |
|
90 |
+
def run_patent_architect_in_ui(invention_disclosure: str) -> Generator[List, None, None]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
"""
|
92 |
+
This is the new main UI function that runs the true agentic workflow.
|
93 |
+
It no longer calls an external backend.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
"""
|
95 |
+
# Initial state for all output fields
|
96 |
+
negotiation_html = create_negotiation_transcript_display([])
|
97 |
+
prior_art_section = "### Prior Art Analysis\n\n*Awaiting agent analysis...*"
|
98 |
+
summary_section = "### Invention Summary\n\n*Awaiting agent analysis...*"
|
99 |
+
figures_section = "### Technical Figures\n\n*Awaiting agent analysis...*"
|
100 |
+
claims_section = "### Patent Claims\n\n*Awaiting agent analysis...*"
|
101 |
+
status = "System Initialized."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
+
yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
|
|
|
|
105 |
if not invention_disclosure:
|
106 |
+
status = "Please provide an invention disclosure."
|
107 |
+
yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
return
|
109 |
|
110 |
+
if not AGENTIC_BACKEND_AVAILABLE:
|
111 |
+
status = "ERROR: The agentic backend is not available. Check server logs."
|
112 |
+
negotiation_html = create_negotiation_transcript_display([{"agent": "System", "message": "CRITICAL ERROR: Could not import `AgenticNegotiator`. The application cannot run."}])
|
113 |
+
yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
|
114 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
+
# --- Start the Real Agentic Workflow ---
|
117 |
+
negotiator = AgenticNegotiator(invention_disclosure)
|
|
|
|
|
|
|
|
|
118 |
|
119 |
+
final_state = None
|
120 |
+
for state in negotiator.run_negotiation():
|
121 |
+
final_state = state
|
122 |
+
|
123 |
+
# Update negotiation transcript
|
124 |
+
negotiation_html = create_negotiation_transcript_display(state.negotiation_transcript)
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
+
# Update status from the last message
|
127 |
+
if state.negotiation_transcript:
|
128 |
+
last_entry = state.negotiation_transcript[-1]
|
129 |
+
status = f"Active Agent: {last_entry['agent']}"
|
130 |
+
|
131 |
+
# As prior art becomes available, display it
|
132 |
+
if state.prior_art_analysis:
|
133 |
+
pa_data = state.prior_art_analysis
|
134 |
+
prior_art_section = f"### Prior Art & Strategy\n\n"
|
135 |
+
if state.strategic_mandate:
|
136 |
+
prior_art_section += f"**Strategic Mandate:**\n> {state.strategic_mandate}\n\n---\n\n"
|
137 |
+
prior_art_section += f"**Landscape Summary:** {pa_data.get('landscape_summary', 'N/A')}\n\n"
|
138 |
+
prior_art_section += f"**Key Concepts Identified:**\n"
|
139 |
+
for concept in pa_data.get('key_concepts', []):
|
140 |
+
prior_art_section += f"- {concept}\n"
|
141 |
+
prior_art_section += "\n**Simulated Representative Prior Art:**\n"
|
142 |
+
for art in pa_data.get('simulated_prior_art', []):
|
143 |
+
prior_art_section += f"- {art}\n"
|
144 |
+
|
145 |
+
# As sections get generated, display them
|
146 |
+
if state.technical_summary:
|
147 |
+
summary_section = f"### Invention Summary\n\n{state.technical_summary}"
|
148 |
|
149 |
+
if state.patent_claims:
|
150 |
+
claims_section = f"### Patent Claims\n\n{state.patent_claims}"
|
|
|
|
|
|
|
|
|
|
|
151 |
|
152 |
+
# Handle both Ideogram image and LaTeX figure description
|
153 |
+
if state.ideogram_image_b64 or state.figure_description:
|
154 |
+
figures_section = "### Technical Figures\n\n"
|
155 |
+
|
156 |
+
# Display the Ideogram image if it exists
|
157 |
+
if state.ideogram_image_b64:
|
158 |
+
figures_section += "### Conceptual Image (from Ideogram API)\n"
|
159 |
+
image_html = f"<img src='data:image/jpeg;base64,{state.ideogram_image_b64}' alt='Generated Conceptual Image' style='max-width: 100%; height: auto; border: 2px solid #ff8c00;'>"
|
160 |
+
figures_section += image_html + "\n\n---\n\n"
|
161 |
+
|
162 |
+
# Display the LaTeX figure description and compiled image if it exists
|
163 |
+
if state.figure_description:
|
164 |
+
figures_section += "### Technical Figure (from LaTeX)\n"
|
165 |
+
compiled_latex_image_uri = compile_latex_to_image(state.figure_description)
|
166 |
+
if compiled_latex_image_uri:
|
167 |
+
figures_section += f"<img src='{compiled_latex_image_uri}' alt='Compiled LaTeX Figure' style='max-width: 100%; height: auto; border: 2px solid #00ff41; background: white; padding: 10px;'>\n\n"
|
168 |
+
else:
|
169 |
+
figures_section += "*LaTeX compilation failed. Displaying raw code.*\n\n"
|
170 |
+
|
171 |
+
figures_section += "#### Raw LaTeX/TikZ Code:\n"
|
172 |
+
figures_section += state.figure_description
|
173 |
+
|
174 |
+
yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
|
176 |
+
status = "Agentic Negotiation Complete."
|
177 |
+
yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
|
|
|
|
|
178 |
|
179 |
with gr.Blocks(theme=gr.themes.Base(primary_hue="green", neutral_hue="slate"), title="Patent Architect v2") as demo:
|
180 |
gr.HTML("""
|
|
|
218 |
color: #00ff41;
|
219 |
opacity: 0.8;
|
220 |
position: relative;
|
221 |
+
z-index: 1;">POWERED BY GEMINI & IDEOGRAM 3.0 + AUTONOMOUS AI AGENTS</p>
|
222 |
</div>
|
223 |
""")
|
224 |
|
|
|
304 |
invention_input = gr.Textbox(
|
305 |
lines=12,
|
306 |
label="Neural Disclosure Interface",
|
307 |
+
placeholder="""Enter your invention disclosure here. Be as detailed as possible.
|
308 |
+
The agentic system will analyze your input, formulate a patent strategy, and generate a draft application based on that strategy.""",
|
309 |
+
info="The new agentic backend requires a detailed technical disclosure to function effectively."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
)
|
311 |
|
312 |
+
generate_btn = gr.Button("INITIATE AGENTIC NEGOTIATION", variant="primary", size="lg")
|
313 |
|
314 |
status_display = gr.Textbox(
|
315 |
label="System Status",
|
316 |
interactive=False,
|
317 |
+
value="AGENTIC WORKFLOW READY"
|
318 |
)
|
319 |
|
320 |
gr.HTML("""
|
|
|
325 |
</div>
|
326 |
""")
|
327 |
|
|
|
328 |
gr.HTML("""
|
329 |
<div style="background: linear-gradient(45deg, #0a0a0a, #1a1a1a);
|
330 |
border: 1px solid #ff8c00;
|
|
|
336 |
text-shadow: 0 0 5px #ff8c00;
|
337 |
font-size: 1.6em;
|
338 |
margin: 0;
|
339 |
+
text-transform: uppercase;">LIVE AGENT NEGOTIATION & STRATEGY</h2>
|
340 |
</div>
|
341 |
""")
|
342 |
|
343 |
with gr.Row():
|
344 |
+
with gr.Column(scale=2):
|
345 |
+
negotiation_display = gr.HTML("...")
|
346 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
gr.HTML("""
|
348 |
<div style="height: 2px;
|
349 |
background: linear-gradient(90deg, #ff8c00, #ffff00, #00ff41, #ff8c00);
|
|
|
363 |
text-shadow: 0 0 5px #00ff41;
|
364 |
font-size: 1.6em;
|
365 |
margin: 0;
|
366 |
+
text-transform: uppercase;">STRATEGY-ALIGNED PATENT DRAFT</h2>
|
367 |
</div>
|
368 |
""")
|
369 |
|
370 |
with gr.Tabs():
|
371 |
+
with gr.TabItem("PRIOR ART & STRATEGY"):
|
372 |
prior_art_output = gr.Markdown(
|
373 |
+
value="### Prior Art Analysis\n\n*Results of the Prior Art Detective's investigation will appear here.*"
|
374 |
)
|
375 |
with gr.TabItem("TECHNICAL SUMMARY"):
|
376 |
summary_output = gr.Markdown(
|
377 |
+
value="### Invention Summary\n\n*The Technical Writer's summary, aligned with the final strategy, will appear here.*"
|
378 |
)
|
379 |
with gr.TabItem("TECHNICAL FIGURES"):
|
380 |
figures_output = gr.Markdown(
|
381 |
+
value="### Technical Figures\n\n*The Figure Drafter's output, illustrating the core strategic concept, will appear here.*"
|
382 |
)
|
383 |
with gr.TabItem("PATENT CLAIMS"):
|
384 |
claims_output = gr.Markdown(
|
385 |
+
value="### Patent Claims\n\n*The Claims Drafter's claims, focused on the strategic mandate, will appear here.*"
|
386 |
)
|
387 |
|
388 |
generate_btn.click(
|
389 |
fn=run_patent_architect_in_ui,
|
390 |
inputs=[invention_input],
|
391 |
+
outputs=[negotiation_display, prior_art_output, summary_output, figures_output, claims_output, status_display]
|
392 |
)
|
393 |
|
394 |
gr.Examples(
|
395 |
[
|
396 |
+
["My invention is a smart coffee mug that uses a novel phase-change material to keep coffee at a perfect temperature. It also has a mobile app that connects via Bluetooth to let the user set their preferred temperature. The key innovation is a machine learning algorithm that learns the user's drinking habits to pre-warm or cool the mug, optimizing energy use."],
|
397 |
+
["A modular vertical farming system with adaptive LED lighting using full-spectrum arrays (400-700nm) controlled by neural network analysis of plant reflectance spectra. The system employs RGB+NIR sensors to monitor chlorophyll content and adjusts light intensity (50-1000 μmol/m²/s) and spectrum ratios based on growth stage detection. Machine learning models trained on 500+ crop cycles optimize photosynthetic photon flux density while reducing energy consumption by 35% compared to static lighting systems."],
|
|
|
398 |
],
|
399 |
inputs=[invention_input],
|
400 |
+
label="HIGH-SPECIFICATION TECHNICAL INPUT EXAMPLES"
|
401 |
)
|
402 |
|
403 |
gr.HTML("""
|
404 |
<style>
|
405 |
+
/* Style remains the same */
|
406 |
.gradio-button.primary {
|
407 |
background: linear-gradient(45deg, #00ff41, #ffff00) !important;
|
408 |
border: 2px solid #00ff41 !important;
|
|
|
423 |
border-color: #ffff00 !important;
|
424 |
}
|
425 |
|
|
|
426 |
.gradio-container {
|
427 |
background: #0a0a0a !important;
|
428 |
font-family: 'Courier New', monospace !important;
|
429 |
}
|
430 |
|
|
|
431 |
.tab-nav button {
|
432 |
background: linear-gradient(45deg, #1a1a1a, #0a0a0a) !important;
|
433 |
border: 1px solid #00ff41 !important;
|
|
|
443 |
box-shadow: 0 0 10px #00ff41 !important;
|
444 |
}
|
445 |
|
|
|
446 |
.gr-textbox {
|
447 |
background: linear-gradient(45deg, #0a0a0a, #1a1a1a) !important;
|
448 |
border: 1px solid #00ff41 !important;
|
|
|
455 |
box-shadow: 0 0 10px #ffff00 !important;
|
456 |
}
|
457 |
|
|
|
458 |
* {
|
459 |
font-family: 'Courier New', monospace !important;
|
460 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
462 |
""")
|
463 |
|
464 |
if __name__ == "__main__":
|
465 |
+
print("PATENT ARCHITECT v2 - True Agentic Negotiation Workflow")
|
466 |
+
print(f"Agentic Backend: {'ONLINE' if AGENTIC_BACKEND_AVAILABLE else 'OFFLINE'}")
|
467 |
+
if not os.getenv("GEMINI_API_KEY"):
|
468 |
+
print("⚠️ WARNING: GEMINI_API_KEY environment variable not set. Gemini-powered agents will not function.")
|
469 |
+
if not os.getenv("SEGMIND_API_KEY"):
|
470 |
+
print("⚠️ WARNING: SEGMIND_API_KEY environment variable not set. Ideogram image generation will not function.")
|
471 |
demo.queue().launch(
|
472 |
share=False,
|
473 |
show_error=True
|
real_ai_agents_implementation.py
CHANGED
@@ -1,551 +1,320 @@
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
These agents address actual patent attorney pain points with measurable business value.
|
7 |
"""
|
8 |
|
9 |
-
import
|
10 |
import json
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
-
#
|
16 |
@dataclass
|
17 |
-
class
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
SOFTWARE = "software"
|
28 |
-
CHEMICAL = "chemical"
|
29 |
-
|
30 |
-
# ============================================================================
|
31 |
-
# AGENT 1: Technical Completeness Validator
|
32 |
-
# ============================================================================
|
33 |
-
|
34 |
-
class TechnicalCompletenessAgent:
|
35 |
-
"""
|
36 |
-
Real AI agent that ensures patent applications meet technical disclosure requirements.
|
37 |
-
|
38 |
-
Addresses: 35 U.S.C. §112 rejections for inadequate disclosure ($5K-15K prosecution costs)
|
39 |
-
"""
|
40 |
-
|
41 |
-
def __init__(self):
|
42 |
-
self.required_elements = {
|
43 |
-
InventionType.MECHANICAL: {
|
44 |
-
'materials': {
|
45 |
-
'importance': 'critical',
|
46 |
-
'examples': ['steel, aluminum, carbon fiber', 'specific alloy compositions'],
|
47 |
-
'suggestion': 'Specify materials used in each component with properties'
|
48 |
-
},
|
49 |
-
'dimensions': {
|
50 |
-
'importance': 'important',
|
51 |
-
'examples': ['length: 10-50cm', 'thickness: 2-5mm'],
|
52 |
-
'suggestion': 'Provide dimensional ranges that enable reproduction'
|
53 |
-
}
|
54 |
-
},
|
55 |
-
InventionType.ELECTRICAL: {
|
56 |
-
'voltages': {
|
57 |
-
'importance': 'critical',
|
58 |
-
'examples': ['5V DC', '120-240V AC', '3.3V logic levels'],
|
59 |
-
'suggestion': 'Specify all operating voltages and power requirements'
|
60 |
-
},
|
61 |
-
'frequencies': {
|
62 |
-
'importance': 'critical',
|
63 |
-
'examples': ['2.4GHz WiFi', '60Hz AC', '100MHz-1GHz'],
|
64 |
-
'suggestion': 'Define frequency ranges for all signals'
|
65 |
-
}
|
66 |
-
},
|
67 |
-
InventionType.SOFTWARE: {
|
68 |
-
'algorithms': {
|
69 |
-
'importance': 'critical',
|
70 |
-
'examples': ['machine learning (CNN)', 'sorting algorithm', 'encryption (AES-256)'],
|
71 |
-
'suggestion': 'Describe core algorithms with sufficient detail for implementation'
|
72 |
-
},
|
73 |
-
'performance_metrics': {
|
74 |
-
'importance': 'important',
|
75 |
-
'examples': ['response time: <100ms', 'accuracy: >95%', 'throughput: 1000 requests/sec'],
|
76 |
-
'suggestion': 'Provide quantitative performance specifications'
|
77 |
-
}
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
def classify_invention_type(self, invention_text: str) -> InventionType:
|
82 |
-
"""Classify invention type based on description content."""
|
83 |
-
text_lower = invention_text.lower()
|
84 |
-
|
85 |
-
if any(term in text_lower for term in ['algorithm', 'software', 'app', 'machine learning', 'ai']):
|
86 |
-
return InventionType.SOFTWARE
|
87 |
-
elif any(term in text_lower for term in ['electrical', 'electronic', 'circuit', 'voltage', 'sensor']):
|
88 |
-
return InventionType.ELECTRICAL
|
89 |
-
elif any(term in text_lower for term in ['chemical', 'composition', 'reaction', 'compound']):
|
90 |
-
return InventionType.CHEMICAL
|
91 |
-
else:
|
92 |
-
return InventionType.MECHANICAL
|
93 |
-
|
94 |
-
def detect_element_presence(self, invention_text: str, element_type: str) -> bool:
|
95 |
-
"""Detect if a technical element is adequately described."""
|
96 |
-
text_lower = invention_text.lower()
|
97 |
-
|
98 |
-
element_patterns = {
|
99 |
-
'materials': [r'\b\w+\s*(?:steel|aluminum|plastic|carbon|alloy|material)\b'],
|
100 |
-
'dimensions': [r'\b\d+\s*(?:mm|cm|m|inch|ft)\b'],
|
101 |
-
'voltages': [r'\b\d+\.?\d*\s*[vV]\b'],
|
102 |
-
'frequencies': [r'\b\d+\.?\d*\s*(?:Hz|khz|mhz|ghz)\b'],
|
103 |
-
'algorithms': [r'\b(?:algorithm|method|process|neural|cnn|lstm)\b'],
|
104 |
-
'performance_metrics': [r'\b\d+\.?\d*\s*(?:%|percent|accuracy|ms|seconds)\b']
|
105 |
-
}
|
106 |
-
|
107 |
-
patterns = element_patterns.get(element_type, [])
|
108 |
-
return any(re.search(pattern, text_lower) for pattern in patterns)
|
109 |
-
|
110 |
-
def analyze_disclosure(self, invention_text: str) -> Dict:
|
111 |
-
"""
|
112 |
-
Analyze invention disclosure for technical completeness.
|
113 |
-
|
114 |
-
Returns:
|
115 |
-
Dict with completeness analysis, missing elements, and recommendations
|
116 |
-
"""
|
117 |
-
invention_type = self.classify_invention_type(invention_text)
|
118 |
-
required_elements = self.required_elements.get(invention_type, {})
|
119 |
-
|
120 |
-
analysis_results = []
|
121 |
-
missing_critical = 0
|
122 |
-
missing_important = 0
|
123 |
-
|
124 |
-
for element_name, element_config in required_elements.items():
|
125 |
-
is_present = self.detect_element_presence(invention_text, element_name)
|
126 |
-
|
127 |
-
element_analysis = TechnicalElement(
|
128 |
-
element_type=element_name,
|
129 |
-
importance=element_config['importance'],
|
130 |
-
present=is_present,
|
131 |
-
suggestion=element_config['suggestion'],
|
132 |
-
examples=element_config['examples']
|
133 |
-
)
|
134 |
-
|
135 |
-
analysis_results.append(element_analysis)
|
136 |
-
|
137 |
-
if not is_present:
|
138 |
-
if element_config['importance'] == 'critical':
|
139 |
-
missing_critical += 1
|
140 |
-
elif element_config['importance'] == 'important':
|
141 |
-
missing_important += 1
|
142 |
-
|
143 |
-
# Calculate completeness score
|
144 |
-
total_elements = len(required_elements)
|
145 |
-
present_elements = sum(1 for el in analysis_results if el.present)
|
146 |
-
completeness_score = (present_elements / total_elements * 100) if total_elements > 0 else 0
|
147 |
-
|
148 |
-
# Determine prosecution risk
|
149 |
-
if missing_critical > 0:
|
150 |
-
prosecution_risk = "HIGH - Critical elements missing, likely §112 rejection"
|
151 |
-
elif missing_important > 1:
|
152 |
-
prosecution_risk = "MEDIUM - Important elements missing, possible objections"
|
153 |
-
else:
|
154 |
-
prosecution_risk = "LOW - Technical disclosure appears adequate"
|
155 |
-
|
156 |
-
return {
|
157 |
-
'invention_type': invention_type.value,
|
158 |
-
'completeness_score': completeness_score,
|
159 |
-
'prosecution_risk': prosecution_risk,
|
160 |
-
'missing_critical': missing_critical,
|
161 |
-
'missing_important': missing_important,
|
162 |
-
'missing_elements': [
|
163 |
-
{
|
164 |
-
'element': el.element_type,
|
165 |
-
'importance': el.importance,
|
166 |
-
'suggestion': el.suggestion,
|
167 |
-
'examples': el.examples
|
168 |
-
}
|
169 |
-
for el in analysis_results if not el.present
|
170 |
-
]
|
171 |
-
}
|
172 |
|
173 |
-
#
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
176 |
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
"""
|
186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
|
188 |
-
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
"""
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
|
|
|
|
195 |
|
196 |
-
|
197 |
-
'key_competitors': key_competitors,
|
198 |
-
'prosecution_risks': prosecution_risks,
|
199 |
-
'whitespace_opportunities': whitespace_opportunities,
|
200 |
-
'landscape_summary': self._create_landscape_summary(key_competitors, prosecution_risks)
|
201 |
-
}
|
202 |
-
|
203 |
-
def _identify_key_competitors(self, invention_text: str) -> List[Dict]:
|
204 |
-
"""Identify key competitors based on invention description."""
|
205 |
-
if 'coffee' in invention_text.lower():
|
206 |
-
return [
|
207 |
-
{'company': 'Ember Technologies', 'patents': 45, 'focus': 'Temperature control'},
|
208 |
-
{'company': 'YETI Holdings', 'patents': 23, 'focus': 'Insulation technology'}
|
209 |
-
]
|
210 |
-
elif 'sensor' in invention_text.lower():
|
211 |
-
return [
|
212 |
-
{'company': 'Honeywell', 'patents': 1200, 'focus': 'Industrial sensors'},
|
213 |
-
{'company': 'Bosch', 'patents': 890, 'focus': 'Automotive sensors'}
|
214 |
-
]
|
215 |
-
else:
|
216 |
-
return [
|
217 |
-
{'company': 'Generic Tech Corp', 'patents': 150, 'focus': 'Related technology'}
|
218 |
-
]
|
219 |
-
|
220 |
-
def _assess_prosecution_risks(self, invention_text: str) -> Dict:
|
221 |
-
"""Assess risks for patent prosecution."""
|
222 |
-
text_lower = invention_text.lower()
|
223 |
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
|
|
234 |
|
235 |
-
|
236 |
-
'overall_risk': risk_level,
|
237 |
-
'risk_factors': risk_factors,
|
238 |
-
'mitigation_strategies': [
|
239 |
-
'Focus on specific technical improvements',
|
240 |
-
'Emphasize novel combination of features'
|
241 |
-
]
|
242 |
-
}
|
243 |
-
|
244 |
-
def _find_whitespace_opportunities(self, invention_text: str) -> List[Dict]:
|
245 |
-
"""Find whitespace opportunities in the patent landscape."""
|
246 |
-
return [
|
247 |
-
{
|
248 |
-
'opportunity': 'Mobile app integration',
|
249 |
-
'description': 'Limited patents on smartphone-controlled devices in this space',
|
250 |
-
'potential_value': 'High - growing IoT market'
|
251 |
-
},
|
252 |
-
{
|
253 |
-
'opportunity': 'Machine learning optimization',
|
254 |
-
'description': 'Few patents combine your core technology with ML algorithms',
|
255 |
-
'potential_value': 'Medium - emerging technology trend'
|
256 |
-
}
|
257 |
-
]
|
258 |
-
|
259 |
-
def _create_landscape_summary(self, competitors: List[Dict], risks: Dict) -> str:
|
260 |
-
"""Create a summary of the competitive landscape."""
|
261 |
-
total_competitors = len(competitors)
|
262 |
-
total_patents = sum(comp.get('patents', 0) for comp in competitors)
|
263 |
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
|
|
270 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
|
272 |
-
|
273 |
-
# AGENT 3: Claim Architecture Strategist
|
274 |
-
# ============================================================================
|
275 |
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
"""
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
"""
|
290 |
-
prosecution_risks = prior_art_analysis.get('prosecution_risks', {})
|
291 |
-
|
292 |
-
# Design claim pyramid based on risk assessment
|
293 |
-
claim_pyramid = self._design_claim_pyramid(prosecution_risks)
|
294 |
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
'claim_pyramid': claim_pyramid,
|
300 |
-
'claim_strength_analysis': claim_strength,
|
301 |
-
'recommendation_summary': self._create_recommendation_summary(claim_strength)
|
302 |
}
|
303 |
-
|
304 |
-
def _design_claim_pyramid(self, prosecution_risks: Dict) -> Dict:
|
305 |
-
"""Design strategic claim pyramid."""
|
306 |
-
risk_level = prosecution_risks.get('overall_risk', 'MEDIUM')
|
307 |
-
|
308 |
-
if risk_level == 'HIGH':
|
309 |
-
# Conservative approach for high-risk fields
|
310 |
-
independent_claims = [
|
311 |
-
{'claim_number': 1, 'type': 'apparatus', 'scope': 'narrow', 'strategy': 'Specific implementation'}
|
312 |
-
]
|
313 |
-
else:
|
314 |
-
# More aggressive approach for lower-risk fields
|
315 |
-
independent_claims = [
|
316 |
-
{'claim_number': 1, 'type': 'apparatus', 'scope': 'broad', 'strategy': 'Cover core invention'},
|
317 |
-
{'claim_number': 8, 'type': 'method', 'scope': 'broad', 'strategy': 'Protect process aspects'}
|
318 |
-
]
|
319 |
-
|
320 |
-
return {
|
321 |
-
'independent_claims': independent_claims,
|
322 |
-
'dependent_claims': [
|
323 |
-
{'claim_number': 2, 'depends_on': 1, 'strategy': 'Narrow fallback position'},
|
324 |
-
{'claim_number': 3, 'depends_on': 1, 'strategy': 'Alternative limitation'}
|
325 |
-
]
|
326 |
-
}
|
327 |
-
|
328 |
-
def _analyze_claim_strength(self, claim_pyramid: Dict, prosecution_risks: Dict) -> Dict:
|
329 |
-
"""Analyze strength of proposed claims."""
|
330 |
-
risk_level = prosecution_risks.get('overall_risk', 'MEDIUM')
|
331 |
-
|
332 |
-
# Calculate strength based on risk level and claim scope
|
333 |
-
if risk_level == 'HIGH':
|
334 |
-
overall_strength = 60 # Conservative claims in crowded field
|
335 |
-
elif risk_level == 'MEDIUM':
|
336 |
-
overall_strength = 75 # Balanced approach
|
337 |
-
else:
|
338 |
-
overall_strength = 85 # Aggressive claims in open field
|
339 |
-
|
340 |
-
return {
|
341 |
-
'overall_strength': overall_strength,
|
342 |
-
'grantability': 'Good' if overall_strength > 70 else 'Moderate',
|
343 |
-
'recommendations': self._generate_strength_recommendations(overall_strength)
|
344 |
-
}
|
345 |
-
|
346 |
-
def _generate_strength_recommendations(self, strength: float) -> List[str]:
|
347 |
-
"""Generate recommendations for improving claim strength."""
|
348 |
-
recommendations = []
|
349 |
-
|
350 |
-
if strength < 70:
|
351 |
-
recommendations.append("Consider narrowing independent claims to improve grantability")
|
352 |
-
recommendations.append("Add more specific technical limitations")
|
353 |
-
|
354 |
-
recommendations.append("Ensure all claims are fully supported by specification")
|
355 |
-
recommendations.append("Consider adding method claims if not present")
|
356 |
-
|
357 |
-
return recommendations
|
358 |
-
|
359 |
-
def _create_recommendation_summary(self, claim_strength: Dict) -> str:
|
360 |
-
"""Create summary of claim architecture recommendations."""
|
361 |
-
overall_strength = claim_strength.get('overall_strength', 0)
|
362 |
-
|
363 |
-
if overall_strength >= 80:
|
364 |
-
assessment = "STRONG - Claims appear well-positioned for prosecution"
|
365 |
-
elif overall_strength >= 65:
|
366 |
-
assessment = "GOOD - Claims have solid foundation with room for improvement"
|
367 |
-
else:
|
368 |
-
assessment = "NEEDS WORK - Claims require significant refinement"
|
369 |
-
|
370 |
-
return f"""
|
371 |
-
Claim Architecture Assessment: {assessment}
|
372 |
-
Overall Strength: {overall_strength:.0f}/100
|
373 |
-
|
374 |
-
Key Recommendations:
|
375 |
-
• Focus on specific technical differentiation
|
376 |
-
• Prepare multiple claim strategies for prosecution
|
377 |
-
• Ensure strong specification support
|
378 |
-
"""
|
379 |
|
380 |
-
|
381 |
-
|
382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
def __init__(self):
|
390 |
self.agents = {
|
391 |
-
|
392 |
-
|
393 |
-
|
|
|
|
|
|
|
394 |
}
|
395 |
-
|
396 |
-
def
|
397 |
-
"""
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
#
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
"
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
"""Estimate prosecution timeline based on readiness."""
|
465 |
-
if readiness_score >= 80:
|
466 |
-
return "12-18 months to allowance (well-prepared application)"
|
467 |
-
elif readiness_score >= 65:
|
468 |
-
return "18-24 months to allowance (likely 1-2 office actions)"
|
469 |
-
else:
|
470 |
-
return "24-36 months to allowance (multiple office actions expected)"
|
471 |
-
|
472 |
-
def _estimate_costs(self, readiness_score: float) -> str:
|
473 |
-
"""Estimate prosecution costs based on readiness."""
|
474 |
-
if readiness_score >= 80:
|
475 |
-
return "$8,000-12,000 (minimal prosecution required)"
|
476 |
-
elif readiness_score >= 65:
|
477 |
-
return "$12,000-18,000 (moderate prosecution complexity)"
|
478 |
else:
|
479 |
-
|
|
|
480 |
|
481 |
-
# ============================================================================
|
482 |
-
# TESTING AND VALIDATION
|
483 |
-
# ============================================================================
|
484 |
|
485 |
-
|
486 |
-
|
487 |
-
|
|
|
|
|
|
|
488 |
print("=" * 60)
|
489 |
|
490 |
-
|
|
|
|
|
|
|
491 |
test_invention = """
|
492 |
-
|
493 |
-
and smartphone app control. The mug includes a double-wall design with PCM chambers
|
494 |
-
that store and release thermal energy. A temperature sensor monitors the coffee
|
495 |
-
temperature and communicates with a mobile app via Bluetooth. The app allows users
|
496 |
-
to set preferred temperatures and receive notifications when coffee is ready.
|
497 |
-
|
498 |
-
The system uses a microcontroller to manage thermal regulation and wireless
|
499 |
-
communication. Machine learning algorithms analyze user preferences to optimize
|
500 |
-
heating patterns over time.
|
501 |
"""
|
502 |
|
503 |
-
|
504 |
-
coordinator = InterAgentCoordinator()
|
505 |
-
results = coordinator.orchestrate_patent_development(test_invention)
|
506 |
-
|
507 |
-
# Display results
|
508 |
-
print("\n📊 ANALYSIS RESULTS:")
|
509 |
-
print("=" * 40)
|
510 |
-
|
511 |
-
# Technical Analysis Results
|
512 |
-
technical = results['technical_analysis']
|
513 |
-
print(f"\n🔬 Technical Completeness: {technical['completeness_score']:.1f}%")
|
514 |
-
print(f" Prosecution Risk: {technical['prosecution_risk']}")
|
515 |
-
print(f" Missing Critical Elements: {technical['missing_critical']}")
|
516 |
-
if technical['missing_elements']:
|
517 |
-
print(" Missing Elements:")
|
518 |
-
for element in technical['missing_elements'][:3]:
|
519 |
-
print(f" • {element['element']}: {element['suggestion']}")
|
520 |
-
|
521 |
-
# Prior Art Results
|
522 |
-
prior_art = results['prior_art_analysis']
|
523 |
-
print(f"\n🔍 Prior Art Analysis:")
|
524 |
-
print(f" Risk Level: {prior_art['prosecution_risks']['overall_risk']}")
|
525 |
-
print(f" Key Competitors: {len(prior_art['key_competitors'])}")
|
526 |
-
for competitor in prior_art['key_competitors'][:2]:
|
527 |
-
print(f" • {competitor['company']}: {competitor['patents']} patents")
|
528 |
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
print(
|
538 |
-
print(f"
|
539 |
-
print(f"
|
540 |
-
print(f"
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
print("• Technical completeness validation prevents §112 rejections")
|
546 |
-
print("• Prior art landscape analysis reduces prosecution surprises")
|
547 |
-
print("• Claim architecture optimization maximizes patent value")
|
548 |
-
print("• Integrated assessment provides realistic business planning")
|
549 |
|
550 |
if __name__ == "__main__":
|
551 |
-
|
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
+
True Agentic Implementation for Patent Architect AI v2
|
4 |
+
This version implements a genuine, stateful, multi-agent negotiation workflow
|
5 |
+
where agent outputs dynamically influence subsequent agent actions.
|
|
|
6 |
"""
|
7 |
|
8 |
+
import os
|
9 |
import json
|
10 |
+
import re
|
11 |
+
import base64
|
12 |
+
import requests
|
13 |
+
from typing import Dict, List, Optional, Tuple, Generator
|
14 |
+
from dataclasses import dataclass, field
|
15 |
+
import google.generativeai as genai
|
16 |
+
from dotenv import load_dotenv
|
17 |
+
|
18 |
+
# --- Configuration ---
|
19 |
+
load_dotenv()
|
20 |
+
# Configure Gemini
|
21 |
+
try:
|
22 |
+
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
23 |
+
GEMINI_AVAILABLE = True
|
24 |
+
except (ValueError, TypeError) as e:
|
25 |
+
print(f"Gemini API key not found or invalid: {e}")
|
26 |
+
GEMINI_AVAILABLE = False
|
27 |
+
|
28 |
|
29 |
+
# --- Data Structures ---
|
30 |
@dataclass
|
31 |
+
class NegotiationState:
|
32 |
+
invention_disclosure: str
|
33 |
+
key_concepts: List[str] = field(default_factory=list)
|
34 |
+
prior_art_analysis: Dict = field(default_factory=dict)
|
35 |
+
strategic_mandate: str = ""
|
36 |
+
technical_summary: str = ""
|
37 |
+
patent_claims: str = ""
|
38 |
+
figure_description: str = ""
|
39 |
+
ideogram_image_b64: str = ""
|
40 |
+
negotiation_transcript: List[Dict] = field(default_factory=list)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
# --- Base Agent Class ---
|
43 |
+
class BaseAgent:
|
44 |
+
def __init__(self, model_name='gemini-1.5-flash'):
|
45 |
+
if not GEMINI_AVAILABLE:
|
46 |
+
self.model = None
|
47 |
+
return
|
48 |
+
self.model = genai.GenerativeModel(model_name)
|
49 |
|
50 |
+
def _execute_prompt(self, prompt: str) -> str:
|
51 |
+
if not self.model:
|
52 |
+
return f"Error: The '{self.__class__.__name__}' agent could not run because the Gemini API is not configured. Please set the GEMINI_API_KEY."
|
53 |
+
try:
|
54 |
+
response = self.model.generate_content(prompt)
|
55 |
+
return response.text
|
56 |
+
except Exception as e:
|
57 |
+
print(f"Error executing prompt for {self.__class__.__name__}: {e}")
|
58 |
+
return f"Error: Could not get a response from the model. Details: {e}"
|
59 |
+
|
60 |
+
# --- Specialized Agents ---
|
61 |
+
class PriorArtDetective(BaseAgent):
|
62 |
+
def analyze(self, invention_disclosure: str) -> Dict:
|
63 |
+
prompt = f"""
|
64 |
+
Analyze the following invention disclosure to identify the key technical concepts and potential areas of prior art.
|
65 |
+
Invention: "{invention_disclosure}"
|
66 |
+
|
67 |
+
1. List the 3-5 most important technical keywords or concepts.
|
68 |
+
2. For each concept, generate a list of 2-3 realistic-sounding, representative prior art titles that likely exist.
|
69 |
+
3. Based on these, write a brief, 2-3 sentence summary of the prior art landscape, assessing how crowded it might be.
|
70 |
+
|
71 |
+
Return the response as a JSON object with keys: "key_concepts", "simulated_prior_art", and "landscape_summary".
|
72 |
"""
|
73 |
+
response_text = self._execute_prompt(prompt)
|
74 |
+
try:
|
75 |
+
# Clean the response text before parsing
|
76 |
+
clean_response = response_text.strip().replace("```json", "").replace("```", "")
|
77 |
+
return json.loads(clean_response)
|
78 |
+
except json.JSONDecodeError:
|
79 |
+
return {
|
80 |
+
"key_concepts": [],
|
81 |
+
"simulated_prior_art": [],
|
82 |
+
"landscape_summary": "Error parsing prior art analysis from LLM response.",
|
83 |
+
}
|
84 |
+
|
85 |
+
class ChiefStrategistAgent(BaseAgent):
|
86 |
+
def formulate_strategy(self, invention_disclosure: str, prior_art_analysis: Dict) -> str:
|
87 |
+
prompt = f"""
|
88 |
+
You are a Chief Patent Strategist. Your job is to determine the strongest angle for a successful patent application.
|
89 |
|
90 |
+
Invention Disclosure:
|
91 |
+
"{invention_disclosure}"
|
92 |
+
|
93 |
+
Prior Art Analysis:
|
94 |
+
- Key Concepts: {prior_art_analysis.get('key_concepts', [])}
|
95 |
+
- Simulated Prior Art: {prior_art_analysis.get('simulated_prior_art', [])}
|
96 |
+
- Landscape Summary: {prior_art_analysis.get('landscape_summary', '')}
|
97 |
+
|
98 |
+
Based on the above, formulate a clear, one-sentence "Strategic Mandate". This mandate will direct all other agents. It must identify the single most patentable aspect of the invention to focus on.
|
99 |
+
|
100 |
+
Example Mandates:
|
101 |
+
- "The strategic focus shall be on the novel method for data encryption, not the hardware implementation."
|
102 |
+
- "The patentability of this invention rests on the unique chemical composition of the coating material."
|
103 |
+
- "We will patent the specific algorithm for adaptive lighting control, as the general hardware is well-known."
|
104 |
+
|
105 |
+
Formulate the Strategic Mandate for the provided invention.
|
106 |
"""
|
107 |
+
return self._execute_prompt(prompt)
|
108 |
+
|
109 |
+
class TechnicalWriterAgent(BaseAgent):
|
110 |
+
def write_summary(self, invention_disclosure: str, strategic_mandate: str) -> str:
|
111 |
+
prompt = f"""
|
112 |
+
You are a professional patent writer. Your task is to write a "Summary of the Invention" section for a patent application.
|
113 |
|
114 |
+
Invention Disclosure: "{invention_disclosure}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
+
**CRITICAL INSTRUCTION:** You must follow this Strategic Mandate provided by the Chief Strategist:
|
117 |
+
**Strategic Mandate: "{strategic_mandate}"**
|
118 |
+
|
119 |
+
Write a concise, professional summary (2-3 paragraphs). Ensure that the summary heavily emphasizes the aspect highlighted in the Strategic Mandate as the core of the invention.
|
120 |
+
"""
|
121 |
+
return self._execute_prompt(prompt)
|
122 |
+
|
123 |
+
class ClaimsDrafterAgent(BaseAgent):
|
124 |
+
def draft_claims(self, invention_disclosure: str, strategic_mandate: str) -> str:
|
125 |
+
prompt = f"""
|
126 |
+
You are a patent attorney specializing in claim drafting.
|
127 |
|
128 |
+
Invention Disclosure: "{invention_disclosure}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
+
**CRITICAL INSTRUCTION:** Your claim set MUST be aligned with the following mandate:
|
131 |
+
**Strategic Mandate: "{strategic_mandate}"**
|
132 |
+
|
133 |
+
Draft a set of 5-7 patent claims.
|
134 |
+
- The independent claim (Claim 1) must be directly focused on the feature identified in the Strategic Mandate.
|
135 |
+
- Dependent claims should add further specifics and variations.
|
136 |
+
- Ensure the claims are clear, concise, and properly formatted.
|
137 |
"""
|
138 |
+
return self._execute_prompt(prompt)
|
139 |
+
|
140 |
+
class FigureDrafterAgent(BaseAgent):
|
141 |
+
def describe_figure(self, invention_disclosure: str, strategic_mandate: str) -> str:
|
142 |
+
prompt = f"""
|
143 |
+
You are a patent illustrator's assistant. You need to describe a key technical figure for a patent application.
|
144 |
|
145 |
+
Invention Disclosure: "{invention_disclosure}"
|
|
|
|
|
146 |
|
147 |
+
**CRITICAL INSTRUCTION:** The figure must visually represent the core idea from the mandate:
|
148 |
+
**Strategic Mandate: "{strategic_mandate}"**
|
149 |
+
|
150 |
+
1. Decide on the best type of figure to illustrate the mandate (e.g., flowchart, system diagram, cross-section).
|
151 |
+
2. Write a brief description of this figure.
|
152 |
+
3. Generate the LaTeX/TikZ code to create this figure.
|
153 |
+
|
154 |
+
Return a single response containing both the description and the LaTeX code block.
|
155 |
"""
|
156 |
+
return self._execute_prompt(prompt)
|
157 |
+
|
158 |
+
class SegmindIdeogramAgent:
|
159 |
+
def __init__(self):
|
160 |
+
self.api_key = os.getenv("SEGMIND_API_KEY", "SG_f5de4e5bf40aa615") # Use user's key as default
|
161 |
+
self.url = "https://api.segmind.com/v1/ideogram-3"
|
162 |
+
|
163 |
+
def generate_image(self, technical_summary: str, strategic_mandate: str) -> Optional[str]:
|
164 |
+
if not self.api_key:
|
165 |
+
return None
|
166 |
+
|
167 |
+
# Create a more cinematic prompt for image generation
|
168 |
+
image_prompt = f"""
|
169 |
+
Create a photorealistic, cinematic photograph representing the following invention.
|
170 |
+
The image should focus on the core concept defined by the strategic mandate.
|
171 |
+
|
172 |
+
Invention Summary: "{technical_summary}"
|
173 |
+
Core Concept (Strategic Mandate): "{strategic_mandate}"
|
174 |
+
|
175 |
+
Translate this technical concept into a visually stunning and professional marketing image.
|
176 |
+
Emphasize the most innovative aspect. For example, if it's an algorithm, show a sleek user interface or an abstract representation of data flow, not just the hardware.
|
177 |
"""
|
|
|
|
|
|
|
|
|
178 |
|
179 |
+
data = {
|
180 |
+
"prompt": image_prompt,
|
181 |
+
"resolution": "1024x1024",
|
182 |
+
"style_type": "REALISTIC"
|
|
|
|
|
|
|
183 |
}
|
184 |
+
headers = {'x-api-key': self.api_key}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
+
try:
|
187 |
+
response = requests.post(self.url, json=data, headers=headers)
|
188 |
+
if response.status_code == 200:
|
189 |
+
return base64.b64encode(response.content).decode('utf-8')
|
190 |
+
else:
|
191 |
+
print(f"Segmind API Error: {response.status_code} - {response.text}")
|
192 |
+
return None
|
193 |
+
except Exception as e:
|
194 |
+
print(f"Error calling Segmind API: {e}")
|
195 |
+
return None
|
196 |
|
197 |
+
|
198 |
+
# --- The Orchestrator ---
|
199 |
+
class AgenticNegotiator:
|
200 |
+
def __init__(self, invention_disclosure: str):
|
201 |
+
self.state = NegotiationState(invention_disclosure=invention_disclosure)
|
|
|
202 |
self.agents = {
|
203 |
+
"Prior Art Detective": PriorArtDetective(),
|
204 |
+
"Chief Strategist": ChiefStrategistAgent(),
|
205 |
+
"Technical Writer": TechnicalWriterAgent(),
|
206 |
+
"Claims Drafter": ClaimsDrafterAgent(),
|
207 |
+
"Figure Drafter": FigureDrafterAgent(),
|
208 |
+
"Conceptual Artist": SegmindIdeogramAgent(),
|
209 |
}
|
210 |
+
|
211 |
+
def _update_transcript(self, agent_name: str, message: str, data: Optional[Dict] = None):
|
212 |
+
entry = {"agent": agent_name, "message": message, "data": data or {}}
|
213 |
+
self.state.negotiation_transcript.append(entry)
|
214 |
+
|
215 |
+
def run_negotiation(self) -> Generator[NegotiationState, None, None]:
|
216 |
+
# Step 0: Check for Gemini API Key
|
217 |
+
if not GEMINI_AVAILABLE:
|
218 |
+
self._update_transcript("System", "CRITICAL ERROR: `GEMINI_API_KEY` is not set. The agentic workflow cannot proceed. Please configure the environment variable.")
|
219 |
+
yield self.state
|
220 |
+
return
|
221 |
+
|
222 |
+
# Step 1: Prior Art Detective
|
223 |
+
agent_name = "Prior Art Detective"
|
224 |
+
self._update_transcript(agent_name, "Analyzing the invention to understand the technical landscape...")
|
225 |
+
yield self.state
|
226 |
+
|
227 |
+
prior_art_result = self.agents[agent_name].analyze(self.state.invention_disclosure)
|
228 |
+
self.state.prior_art_analysis = prior_art_result
|
229 |
+
self.state.key_concepts = prior_art_result.get("key_concepts", [])
|
230 |
+
self._update_transcript(agent_name, f"Analysis complete. The landscape appears to be: {prior_art_result.get('landscape_summary', 'N/A')}", prior_art_result)
|
231 |
+
yield self.state
|
232 |
+
|
233 |
+
# Step 2: Chief Strategist
|
234 |
+
agent_name = "Chief Strategist"
|
235 |
+
self._update_transcript(agent_name, "Reviewing prior art to determine the most defensible patenting strategy...")
|
236 |
+
yield self.state
|
237 |
+
|
238 |
+
mandate = self.agents[agent_name].formulate_strategy(self.state.invention_disclosure, self.state.prior_art_analysis)
|
239 |
+
self.state.strategic_mandate = mandate
|
240 |
+
self._update_transcript(agent_name, f"Strategy formulated. All agents will now adhere to the following mandate: **{mandate}**")
|
241 |
+
yield self.state
|
242 |
+
|
243 |
+
# Step 3: Guided Content Generation
|
244 |
+
# Technical Summary
|
245 |
+
agent_name = "Technical Writer"
|
246 |
+
self._update_transcript(agent_name, "Acknowledged. Drafting the technical summary to align with the strategic mandate.")
|
247 |
+
yield self.state
|
248 |
+
summary = self.agents[agent_name].write_summary(self.state.invention_disclosure, self.state.strategic_mandate)
|
249 |
+
self.state.technical_summary = summary
|
250 |
+
self._update_transcript(agent_name, "Technical summary drafted.")
|
251 |
+
yield self.state
|
252 |
+
|
253 |
+
# Patent Claims
|
254 |
+
agent_name = "Claims Drafter"
|
255 |
+
self._update_transcript(agent_name, "Understood. Drafting patent claims focused on the mandated novel aspect.")
|
256 |
+
yield self.state
|
257 |
+
claims = self.agents[agent_name].draft_claims(self.state.invention_disclosure, self.state.strategic_mandate)
|
258 |
+
self.state.patent_claims = claims
|
259 |
+
self._update_transcript(agent_name, "Patent claims drafted.")
|
260 |
+
yield self.state
|
261 |
+
|
262 |
+
# Figure Description (LaTeX)
|
263 |
+
agent_name = "Figure Drafter"
|
264 |
+
self._update_transcript(agent_name, "Affirmative. Designing a technical figure that visually represents the core strategic mandate.")
|
265 |
+
yield self.state
|
266 |
+
figure_desc = self.agents[agent_name].describe_figure(self.state.invention_disclosure, self.state.strategic_mandate)
|
267 |
+
self.state.figure_description = figure_desc
|
268 |
+
self._update_transcript(agent_name, "Technical figure description and LaTeX code generated.")
|
269 |
+
yield self.state
|
270 |
+
|
271 |
+
# Conceptual Image (Ideogram)
|
272 |
+
agent_name = "Conceptual Artist"
|
273 |
+
self._update_transcript(agent_name, "Now generating a high-fidelity conceptual image based on the strategy...")
|
274 |
+
yield self.state
|
275 |
+
image_b64 = self.agents[agent_name].generate_image(self.state.technical_summary, self.state.strategic_mandate)
|
276 |
+
if image_b64:
|
277 |
+
self.state.ideogram_image_b64 = image_b64
|
278 |
+
self._update_transcript(agent_name, "Conceptual image generated successfully.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
else:
|
280 |
+
self._update_transcript(agent_name, "Failed to generate conceptual image. The API may be unavailable or the key may be invalid.")
|
281 |
+
yield self.state
|
282 |
|
|
|
|
|
|
|
283 |
|
284 |
+
self._update_transcript("AgenticNegotiator", "All tasks complete. The patent application is ready for assembly.")
|
285 |
+
yield self.state
|
286 |
+
|
287 |
+
def test_agentic_negotiation():
|
288 |
+
"""Test the new agentic negotiation workflow."""
|
289 |
+
print("🤖 Testing True Agentic Workflow")
|
290 |
print("=" * 60)
|
291 |
|
292 |
+
if not GEMINI_AVAILABLE:
|
293 |
+
print("\n❌ Cannot run test: GEMINI_API_KEY is not configured.")
|
294 |
+
return
|
295 |
+
|
296 |
test_invention = """
|
297 |
+
My invention is a smart coffee mug that uses a novel phase-change material to keep coffee at a perfect temperature. It also has a mobile app that connects via Bluetooth to let the user set their preferred temperature. The key innovation is a machine learning algorithm that learns the user's drinking habits to pre-warm or cool the mug, optimizing energy use.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
"""
|
299 |
|
300 |
+
negotiator = AgenticNegotiator(invention_disclosure=test_invention)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
|
302 |
+
final_state = None
|
303 |
+
for i, state in enumerate(negotiator.run_negotiation()):
|
304 |
+
print(f"\n--- Turn {i+1} ---")
|
305 |
+
last_message = state.negotiation_transcript[-1]
|
306 |
+
print(f"**{last_message['agent']}:** {last_message['message']}")
|
307 |
+
final_state = state
|
308 |
+
|
309 |
+
print("\n\n✅ Negotiation Complete!")
|
310 |
+
print("=" * 60)
|
311 |
+
print(f"\n**Final Strategic Mandate:**\n{final_state.strategic_mandate}")
|
312 |
+
print(f"\n**Generated Claims Preview:**\n{final_state.patent_claims[:300]}...")
|
313 |
+
print(f"\n**Generated Figure Description Preview:**\n{final_state.figure_description[:300]}...")
|
314 |
+
if final_state.ideogram_image_b64:
|
315 |
+
print(f"\n**Ideogram Image:** Generated successfully (Base64 data)")
|
316 |
+
else:
|
317 |
+
print(f"\n**Ideogram Image:** Failed to generate.")
|
|
|
|
|
|
|
|
|
318 |
|
319 |
if __name__ == "__main__":
|
320 |
+
test_agentic_negotiation()
|
requirements.txt
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
-
gradio
|
2 |
-
requests
|
3 |
-
openai
|
4 |
-
pillow
|
5 |
-
python-dotenv
|
6 |
-
google-generativeai
|
|
|
|
1 |
+
gradio>=4.44.0
|
2 |
+
requests>=2.31.0
|
3 |
+
openai>=1.51.0
|
4 |
+
pillow>=10.0.0
|
5 |
+
python-dotenv>=1.0.0
|
6 |
+
google-generativeai>=0.8.3
|
7 |
+
segmind>=0.2.2
|