File size: 18,650 Bytes
38e1a47
 
 
 
137c880
e77acc2
137c880
 
 
 
5753724
e77acc2
 
 
 
5753724
 
 
 
 
 
 
 
 
 
 
 
 
137c880
 
 
 
 
 
 
 
 
e77acc2
 
 
 
 
 
137c880
8d57868
137c880
 
8d57868
 
137c880
8d57868
 
137c880
8d57868
137c880
8d57868
 
 
 
 
 
 
 
 
 
 
 
38e1a47
8d57868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137c880
8d57868
137c880
8d57868
137c880
 
 
 
 
 
 
0f743a0
137c880
 
0f743a0
137c880
0f743a0
 
 
 
137c880
38e1a47
 
5753724
38e1a47
137c880
 
38e1a47
137c880
 
 
 
 
 
 
e77acc2
137c880
38e1a47
 
137c880
 
38e1a47
 
137c880
 
 
 
38e1a47
e77acc2
5753724
 
 
 
137c880
 
e77acc2
137c880
 
 
 
 
 
38e1a47
137c880
 
 
 
 
 
 
 
 
 
 
6ca0045
 
137c880
 
6ca0045
 
 
137c880
 
 
 
38e1a47
137c880
 
38e1a47
137c880
 
 
 
 
 
 
2a4ee49
 
137c880
 
 
 
 
 
2a4ee49
137c880
 
 
 
 
 
 
38e1a47
137c880
 
38e1a47
8d57868
38e1a47
8d57868
 
 
e77acc2
 
8d57868
e77acc2
8d57868
e77acc2
 
8d57868
 
 
 
 
e77acc2
 
8d57868
 
e77acc2
 
38e1a47
 
7376d7d
8d57868
 
 
 
 
 
 
e77acc2
 
38e1a47
8d57868
 
 
 
38e1a47
5753724
 
 
 
 
 
 
 
 
 
38e1a47
8d57868
 
 
 
 
 
 
 
54dd993
38e1a47
8d57868
 
 
 
 
 
 
 
 
38e1a47
8d57868
38e1a47
8d57868
38e1a47
8d57868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38e1a47
8d57868
38e1a47
8d57868
 
 
 
 
 
 
 
 
38e1a47
5753724
 
38e1a47
 
5753724
137c880
38e1a47
 
 
 
8d57868
 
 
 
 
 
38e1a47
e77acc2
 
 
 
 
 
 
 
 
 
 
8d57868
38e1a47
e77acc2
 
 
 
 
 
 
 
 
 
 
 
8d57868
e77acc2
 
 
 
 
 
8d57868
e77acc2
 
 
 
 
8d57868
e77acc2
 
 
8d57868
 
 
38e1a47
e77acc2
38e1a47
 
 
 
 
8d57868
137c880
 
 
 
 
38e1a47
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
import gradio as gr
import os
import requests
import json
from typing import Dict, List, Generator, Optional
from dotenv import load_dotenv
import base64
import tempfile
import re
import urllib.parse
from datetime import datetime

# Load environment variables from .env file
load_dotenv()

# --- Data Logging (with consent) ---
def log_user_data(invention_disclosure: str):
    """Logs the user's invention disclosure to a file if consent is given."""
    try:
        with open("user_data_log.txt", "a") as f:
            log_entry = {
                "timestamp": datetime.now().isoformat(),
                "invention_disclosure": invention_disclosure
            }
            f.write(json.dumps(log_entry) + "\n")
    except Exception as e:
        print(f"Error logging user data: {e}")

# --- New Agentic Backend Integration ---
try:
    from real_ai_agents_implementation import AgenticNegotiator, NegotiationState
    AGENTIC_BACKEND_AVAILABLE = True
except ImportError as e:
    print(f"Failed to import agentic backend: {e}")
    AGENTIC_BACKEND_AVAILABLE = False
    
# Keep Gemini Image Generator for LaTeX compilation
try:
    from gemini_image_generator import GeminiImageGenerator
    GEMINI_IMAGE_AVAILABLE = True
except ImportError:
    GEMINI_IMAGE_AVAILABLE = False

def compile_latex_to_image(latex_code: str) -> Optional[str]:
    """Try to compile LaTeX code to an image using a web service, with fallbacks."""
    if not latex_code:
        return None
        
    content_to_render = None
    try:
        # A more robust regex to find the complete document, even with surrounding text.
        match = re.search(r'(\\documentclass.*?\\end{document})', latex_code, re.DOTALL)
        if match:
            content_to_render = match.group(1)
        else:
            # Fallback for tikzpicture only if full document not found
            match = re.search(r'(\\begin{tikzpicture}.*?\\end{tikzpicture})', latex_code, re.DOTALL)
            if match:
                # If only tikz is found, wrap it in a standard document class
                content_to_render = f"""\\documentclass[border=5mm]{{standalone}}
\\usepackage{{tikz}}
\\usetikzlibrary{{shapes,arrows}}
{match.group(0)}
"""
            else:
                 # If no specific block is found, take the whole code and hope for the best
                content_to_render = latex_code

        # --- Attempt 1: codecogs API (fast but limited) ---
        try:
            encoded_latex = urllib.parse.quote(content_to_render)
            api_url = f"https://latex.codecogs.com/png.latex?{encoded_latex}"
            response = requests.get(api_url, timeout=15)
            if response.status_code == 200 and response.headers.get('content-type', '').startswith('image/'):
                image_b64 = base64.b64encode(response.content).decode('utf-8')
                return f"data:image/png;base64,{image_b64}"
            else:
                print(f"LaTeX compilation (codecogs) failed with status: {response.status_code}")
        except Exception as e:
            print(f"An error occurred during codecogs LaTeX compilation: {e}")

        # --- Attempt 2: A more robust secondary API (slower but more capable) ---
        print("Codecogs failed, trying secondary LaTeX service...")
        try:
            api_url_secondary = "https://latex.ytotech.com/api/v1"
            payload = {
                "latex": content_to_render,
                "format": "png",
                "quality": 85,
                "density": 300
            }
            response = requests.post(api_url_secondary, json=payload, timeout=30)
            if response.status_code == 200:
                response_data = response.json()
                if response_data.get("status") == "success" and response_data.get("result"):
                    # The result is already base64 encoded
                    image_b64 = response_data["result"]
                    return f"data:image/png;base64,{image_b64}"
            else:
                print(f"LaTeX compilation (secondary) failed with status: {response.status_code}")
                return None
        except Exception as e:
            print(f"An error occurred during secondary LaTeX compilation: {e}")
            return None

    except Exception as e:
        print(f"A critical error occurred during LaTeX preparation: {e}")
        return None

def create_negotiation_transcript_display(transcript: List[Dict]) -> str:
    """Creates a markdown display for the agent negotiation transcript."""
    if not transcript:
        return "### Agent Negotiation Log\n\n*Awaiting instructions...*"

    markdown = "### Agent Negotiation Log\n\n---\n"
    for entry in transcript:
        agent = entry.get('agent', 'System')
        message = entry.get('message', '').replace('\n', '\n> ') # Indent multiline messages
        
        # Using markdown emphasis and blockquotes instead of raw HTML
        markdown += f"\n\n**🤖 {agent}:**\n"
        markdown += f"> {message}\n\n"
        markdown += "---"
        
    return markdown

def run_patent_architect_in_ui(invention_disclosure: str, consent: bool) -> Generator[List, None, None]:
    """
    This is the new main UI function that runs the true agentic workflow.
    It no longer calls an external backend.
    """
    # Initial state for all output fields
    negotiation_html = create_negotiation_transcript_display([])
    prior_art_section = "### Prior Art Analysis\n\n*Awaiting agent analysis...*"
    summary_section = "### Invention Summary\n\n*Awaiting agent analysis...*"
    figures_section = "### Technical Figures\n\n*Awaiting agent analysis...*"
    claims_section = "### Patent Claims\n\n*Awaiting agent analysis...*"
    status = "System Initialized."

    yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]

    if not invention_disclosure:
        status = "Please provide an invention disclosure."
        yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
        return

    if not AGENTIC_BACKEND_AVAILABLE:
        status = "ERROR: The agentic backend is not available. Check server logs."
        negotiation_html = create_negotiation_transcript_display([{"agent": "System", "message": "CRITICAL ERROR: Could not import `AgenticNegotiator`. The application cannot run."}])
        yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]
        return
        
    # --- Log data only if consent is given ---
    if consent:
        log_user_data(invention_disclosure)
        
    # --- Start the Real Agentic Workflow ---
    negotiator = AgenticNegotiator(invention_disclosure)
    
    final_state = None
    for state in negotiator.run_negotiation():
        final_state = state
        
        # Update negotiation transcript
        negotiation_html = create_negotiation_transcript_display(state.negotiation_transcript)
        
        # Update status from the last message
        if state.negotiation_transcript:
            last_entry = state.negotiation_transcript[-1]
            status = f"Active Agent: {last_entry['agent']}"

        # As prior art becomes available, display it
        if state.prior_art_analysis:
            pa_data = state.prior_art_analysis
            prior_art_section = f"### Prior Art & Strategy\n\n"
            if state.strategic_mandate:
                 prior_art_section += f"**Strategic Mandate:**\n> {state.strategic_mandate}\n\n---\n\n"
            prior_art_section += f"**Landscape Summary (from live web search):**\n> {pa_data.get('landscape_summary', 'N/A')}\n\n"
            prior_art_section += f"**Key Concepts Searched:**\n"
            for concept in pa_data.get('key_concepts', []):
                prior_art_section += f"- {concept}\n"
            prior_art_section += "\n**Representative Prior Art Found:**\n"
            for art in pa_data.get('real_prior_art', []):
                prior_art_section += f"- **[{art.get('title', 'Link')}]({art.get('link', '#')})**\n"

        # As sections get generated, display them
        if state.technical_summary:
            summary_section = f"### Invention Summary\n\n{state.technical_summary}"
        
        if state.patent_claims:
            claims_section = f"### Patent Claims\n\n{state.patent_claims}"
            
        # Handle both Ideogram image and LaTeX figure description
        if state.ideogram_image_b64 or state.figure_description:
            figures_section = "### Technical Figures\n\n"
            
            # Display the Ideogram image if it exists
            if state.ideogram_image_b64:
                figures_section += "### Conceptual Image (from Ideogram API)\n"
                image_md = f"![Generated Conceptual Image](data:image/jpeg;base64,{state.ideogram_image_b64})"
                figures_section += image_md + "\n\n---\n\n"

            # Display the LaTeX figure description and compiled image if it exists
            if state.figure_description:
                figures_section += "### Technical Figure (from LaTeX)\n"
                compiled_latex_image_uri = compile_latex_to_image(state.figure_description)
                if compiled_latex_image_uri:
                    figures_section += f"![Compiled LaTeX Figure]({compiled_latex_image_uri})\n\n"
                else:
                    figures_section += "*LaTeX compilation failed. Displaying raw code.*\n\n"
                
                figures_section += "#### Raw LaTeX/TikZ Code:\n"
                figures_section += state.figure_description
        
        yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]

    status = "Agentic Negotiation Complete."
    yield [negotiation_html, prior_art_section, summary_section, figures_section, claims_section, status]

with gr.Blocks(theme=gr.themes.Base(primary_hue="green", neutral_hue="slate"), title="Patent Architect") as demo:
    gr.HTML("""
    <div style="background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%); 
                border-bottom: 2px solid #00ff41; 
                padding: 30px 20px; 
                text-align: center; 
                font-family: 'Courier New', monospace;">
        <h1 style="font-size: 2.8em; 
                   margin: 0; 
                   text-shadow: 0 0 10px #00ff41;
                   color: #00ff41;
                   font-weight: 900;
                   letter-spacing: 2px;">
            PATENT ARCHITECT
        </h1>
        <p style="font-size: 1.2em; 
                  margin: 10px 0 0 0; 
                  color: #ffff00;
                  text-shadow: 0 0 5px #ffff00;
                  font-weight: 600;">
            From Raw Idea to Strategized Patent Draft
        </p>
    </div>
    """)

    with gr.Row(variant="panel"):
        with gr.Column(scale=2, min_width=600):
            # --- STEP 1: INPUT ---
            gr.Markdown("""
            <div style="border: 1px solid #ffff00; padding: 20px; margin-top: 20px; box-shadow: 0 0 10px rgba(255,255,0,0.2);">
            <h2 style="color: #ffff00; font-size: 1.5em; margin: 0 0 15px 0; text-transform: uppercase; letter-spacing: 1px;">
            Step 1: Disclose Your Invention
            </h2>
            </div>
            """)
            invention_input = gr.Textbox(
                lines=10,
                label="Invention Disclosure",
                placeholder="Describe the core of your invention. Focus on what it does and what makes it novel. The AI agent team will analyze the technical fundamentals.",
                info="Provide a clear, concise description. Details are good, but the core concept is essential."
            )
            
            with gr.Row(elem_classes="consent-row"):
                consent_checkbox = gr.Checkbox(
                    label="I agree to let the developer collect my anonymized invention data to improve this tool.",
                    value=False,
                    interactive=True,
                    info="We will only store the invention text and a timestamp. No personal data is collected. See our Privacy Policy."
                )

            generate_btn = gr.Button("Develop Patent Strategy", variant="primary", size="lg", interactive=False)
            
            # --- STEP 2: LIVE ANALYSIS ---
            gr.Markdown("""
            <div style="border: 1px solid #ff8c00; padding: 20px; margin-top: 30px; box-shadow: 0 0 10px rgba(255,140,0,0.2);">
            <h2 style="color: #ff8c00; font-size: 1.5em; margin: 0 0 15px 0; text-transform: uppercase; letter-spacing: 1px;">
            Step 2: Observe the Agent Team
            </h2>
            </div>
            """)
            negotiation_display = gr.Markdown("The agent negotiation log will appear here once you begin.")
            
        with gr.Column(scale=1, min_width=300):
             # --- SIDEBAR: STATUS & DELIVERABLES ---
            gr.Markdown("""
            <div style="border: 1px solid #00ff41; padding: 20px; margin-top: 20px; box-shadow: 0 0 10px rgba(0,255,65,0.2);">
            <h2 style="color: #00ff41; font-size: 1.5em; margin: 0 0 15px 0; text-transform: uppercase; letter-spacing: 1px;">
            System Status & Output
            </h2>
            </div>
            """)
            status_display = gr.Textbox(
                label="Current Status",
                interactive=False,
                value="Ready"
            )
            gr.Markdown("""
            <h3 style="color: #00ff41; font-size: 1.3em; margin: 20px 0 15px 0; text-transform: uppercase;">
            Step 3: Review Deliverables
            </h3>
            <p style="color: #ff8c00; font-size: 0.9em; margin-bottom: 15px;">
            The final, strategy-aligned patent draft will appear below.
            </p>
            """)
            with gr.Tabs():
                with gr.TabItem("Prior Art & Strategy"):
                    prior_art_output = gr.Markdown(
                        value="*The Prior Art Detective's findings and the Chief Strategist's resulting mandate will be shown here.*"
                    )
                with gr.TabItem("Technical Summary"):
                    summary_output = gr.Markdown(
                        value="*The Technical Writer's summary, aligned with the final strategy, will appear here.*"
                    )
                with gr.TabItem("Technical Figures"):
                    figures_output = gr.Markdown(
                        value="*A conceptual image from the Ideogram API and a technical figure from the Figure Drafter will appear here.*"
                    )
                with gr.TabItem("Patent Claims"):
                    claims_output = gr.Markdown(
                        value="*The Claims Drafter's claims, focused on the strategic mandate, will appear here.*"
                    )

    gr.HTML("<hr style='border: 1px solid #00ff41; margin: 40px 0;'>")
    
    gr.Examples(
        [
            ["A smart coffee mug using phase-change materials and a machine learning algorithm that learns user habits to optimize temperature and energy use."],
            ["A modular vertical farming system with AI-controlled, adaptive full-spectrum LED lighting based on real-time plant reflectance spectra analysis."],
            ["Non-invasive glucose monitoring using Raman spectroscopy."],
        ],
        inputs=[invention_input],
        label="Invention Examples (click one to get started)"
    )

    consent_checkbox.change(lambda x: gr.update(interactive=x), consent_checkbox, generate_btn)

    generate_btn.click(
        fn=run_patent_architect_in_ui,
        inputs=[invention_input, consent_checkbox],
        outputs=[negotiation_display, prior_art_output, summary_output, figures_output, claims_output, status_display]
    )

    gr.HTML("""
    <style>
    .gradio-container {
        background: #0a0a0a !important;
        font-family: 'Courier New', monospace !important;
        max-width: 1400px !important;
        margin: auto !important;
    }
    .gradio-button.primary {
        background: linear-gradient(45deg, #00ff41, #ffff00) !important;
        border: 2px solid #00ff41 !important;
        color: #0a0a0a !important;
        font-weight: 900 !important;
        font-size: 1.2em !important;
        border-radius: 0 !important;
        text-transform: uppercase !important;
        letter-spacing: 2px !important;
        box-shadow: 0 0 15px #00ff41, inset 0 0 10px rgba(0,255,65,0.2) !important;
        font-family: 'Courier New', monospace !important;
        transition: all 0.3s ease !important;
        margin-top: 20px;
    }
    .gradio-button.primary:hover {
        background: linear-gradient(45deg, #ffff00, #ff8c00) !important;
        box-shadow: 0 0 25px #ffff00, inset 0 0 15px rgba(255,255,0,0.3) !important;
        border-color: #ffff00 !important;
    }
    .tab-nav button {
        background: linear-gradient(45deg, #1a1a1a, #0a0a0a) !important;
        border: 1px solid #00ff41 !important;
        color: #00ff41 !important;
        font-family: 'Courier New', monospace !important;
        text-transform: uppercase !important;
        letter-spacing: 1px !important;
        border-radius: 0 !important;
    }
    .tab-nav button.selected {
        background: linear-gradient(45deg, #00ff41, #ffff00) !important;
        color: #0a0a0a !important;
        box-shadow: 0 0 10px #00ff41 !important;
    }
    .gr-textbox, .gr-markdown {
        background: linear-gradient(45deg, #0a0a0a, #1a1a1a) !important;
        border: 1px solid #00ff41 !important;
        color: #00ff41 !important;
        font-family: 'Courier New', monospace !important;
    }
    .gr-textbox:focus, .gr-markdown:focus {
        border-color: #ffff00 !important;
        box-shadow: 0 0 10px #ffff00 !important;
    }
    .gr-info {
        color: #ff8c00 !important;
    }
    * {
        font-family: 'Courier New', monospace !important;
    }
    </style>
    """)

if __name__ == "__main__":
    print("PATENT ARCHITECT - True Agentic Negotiation Workflow")
    print(f"Agentic Backend: {'ONLINE' if AGENTIC_BACKEND_AVAILABLE else 'OFFLINE'}")
    if not os.getenv("GEMINI_API_KEY"):
        print("⚠️ WARNING: GEMINI_API_KEY environment variable not set. Gemini-powered agents will not function.")
    if not os.getenv("SEGMIND_API_KEY"):
        print("⚠️ WARNING: SEGMIND_API_KEY environment variable not set. Ideogram image generation will not function.")
    demo.queue().launch(
        share=False,
        show_error=True
    )