File size: 10,962 Bytes
0fc768b
3c74d99
 
10cff5d
3c74d99
 
780c827
c6219ec
55020f5
 
8f7fdc3
3c74d99
910154a
 
 
 
 
55020f5
 
910154a
 
 
 
 
 
def4b9d
 
 
 
 
 
910154a
 
 
 
def4b9d
 
910154a
 
 
 
55020f5
910154a
def4b9d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55020f5
910154a
55020f5
910154a
 
55020f5
 
 
910154a
55020f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
910154a
55020f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
def4b9d
 
55020f5
 
 
 
910154a
55020f5
910154a
 
f2019db
910154a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55020f5
 
 
 
 
910154a
 
 
 
 
 
 
 
def4b9d
55020f5
910154a
def4b9d
910154a
 
 
 
 
 
 
 
 
 
 
10cff5d
47f3b7c
910154a
 
 
55020f5
910154a
 
def4b9d
 
910154a
 
 
 
 
 
def4b9d
910154a
 
 
 
 
 
 
 
 
 
 
 
 
def4b9d
910154a
 
 
 
 
 
55020f5
 
 
910154a
 
 
def4b9d
 
 
 
 
 
910154a
def4b9d
910154a
 
 
10cff5d
 
910154a
55020f5
910154a
 
 
 
 
 
 
55020f5
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
import os
import json
import gradio as gr
from datetime import datetime
from dotenv import load_dotenv
from openai import OpenAI
from prompts import SYSTEM_PROMPT, format_exploration_prompt

# Load environment variables
load_dotenv()

class ExplorationPathGenerator:
    def __init__(self, api_key: str):
        self.client = OpenAI(
            api_key=api_key,
            base_url="https://api.groq.com/openai/v1"
        )

    def generate_exploration_path(self, query: str, selected_path=None, exploration_parameters=None):
        try:
            if selected_path is None:
                selected_path = []
            if exploration_parameters is None:
                exploration_parameters = {}

            # Use the prompt from prompt.py
            formatted_prompt = format_exploration_prompt(
                user_query=query,
                selected_path=selected_path,
                exploration_parameters=exploration_parameters
            )

            response = self.client.chat.completions.create(
                model="mixtral-8x7b-32768",
                messages=[
                    {"role": "system", "content": SYSTEM_PROMPT},
                    {"role": "user", "content": formatted_prompt}
                ],
                temperature=0.7,
                max_tokens=4000
            )

            result = json.loads(response.choices[0].message.content)
            
            # Convert exploration response to graph format
            nodes = []
            node_id_counter = 0

            # Add meta insights as central node
            node_id_counter += 1
            meta_node = {
                "id": f"meta_{node_id_counter}",
                "title": "Exploration Summary",
                "description": result["exploration_summary"]["current_context"],
                "depth": 0,
                "connections": []
            }
            nodes.append(meta_node)

            # Create nodes from standard axes
            for axis in result["knowledge_axes"]["standard_axes"]:
                node_id_counter += 1
                axis_node = {
                    "id": f"std_{node_id_counter}",
                    "title": axis["name"],
                    "description": f"Current values: {', '.join(axis['current_values'])}",
                    "depth": 1,
                    "connections": []
                }
                
                # Connect to meta node
                meta_node["connections"].append({
                    "target_id": axis_node["id"],
                    "relevance_score": 0.8
                })

                # Add potential values as nodes
                for value in axis["potential_values"]:
                    node_id_counter += 1
                    value_node = {
                        "id": f"val_{node_id_counter}",
                        "title": value["value"],
                        "description": value["contextual_rationale"],
                        "depth": 2,
                        "connections": []
                    }
                    nodes.append(value_node)
                    axis_node["connections"].append({
                        "target_id": value_node["id"],
                        "relevance_score": value["relevance_score"] / 100
                    })
                
                nodes.append(axis_node)

            # Create nodes from emergent axes
            for axis in result["knowledge_axes"]["emergent_axes"]:
                node_id_counter += 1
                emergent_node = {
                    "id": f"emg_{node_id_counter}",
                    "title": f"{axis['name']} (Emergent)",
                    "description": f"Parent axis: {axis['parent_axis']}",
                    "depth": 2,
                    "connections": []
                }
                
                # Connect to meta node
                meta_node["connections"].append({
                    "target_id": emergent_node["id"],
                    "relevance_score": 0.6
                })

                # Add innovative values
                for value in axis["innovative_values"]:
                    node_id_counter += 1
                    value_node = {
                        "id": f"inv_{node_id_counter}",
                        "title": value["value"],
                        "description": value["discovery_potential"],
                        "depth": 3,
                        "connections": []
                    }
                    nodes.append(value_node)
                    emergent_node["connections"].append({
                        "target_id": value_node["id"],
                        "relevance_score": value["innovation_score"] / 100
                    })
                
                nodes.append(emergent_node)

            return {"nodes": nodes}

        except Exception as e:
            print(f"Error generating exploration path: {e}")
            return {"error": str(e)}

    def create_visualization_html(self, nodes):
        """Create a simple HTML visualization"""
        html_content = "<div style='padding: 20px; font-family: Arial, sans-serif;'>"
        
        # Create a style for the nodes
        html_content += """
        <style>
        .node-card {
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            background-color: #f9f9f9;
        }
        .node-title {
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 8px;
        }
        .node-description {
            color: #34495e;
            margin-bottom: 8px;
        }
        .node-connections {
            font-size: 0.9em;
            color: #7f8c8d;
        }
        .depth-indicator {
            display: inline-block;
            padding: 3px 8px;
            border-radius: 12px;
            font-size: 0.8em;
            margin-bottom: 5px;
        }
        </style>
        """

        # Create nodes visualization
        for node in nodes:
            depth_color = ['#FF9999', '#99FF99', '#9999FF'][node['depth'] % 3]
            
            html_content += f"""
            <div class='node-card'>
                <div class='depth-indicator' style='background-color: {depth_color}'>
                    Depth: {node['depth']}
                </div>
                <div class='node-title'>{node['title']}</div>
                <div class='node-description'>{node['description']}</div>
                <div class='node-connections'>
            """
            
            # Add connections
            if node.get('connections'):
                html_content += "<strong>Connections:</strong><ul>"
                for conn in node['connections']:
                    html_content += f"<li>Connected to: {conn['target_id']}"
                    if 'relevance_score' in conn:
                        html_content += f" (Relevance: {conn['relevance_score']:.2f})"
                    html_content += "</li>"
                html_content += "</ul>"
            
            html_content += "</div></div>"

        html_content += "</div>"
        return html_content

def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth: int = 5, domain: str = "") -> tuple:
    """Generate exploration path and visualization"""
    try:
        # Initialize generator
        api_key = os.getenv("GROQ_API_KEY")
        if not api_key:
            raise ValueError("GROQ_API_KEY not found in environment variables")
            
        generator = ExplorationPathGenerator(api_key=api_key)

        # Parse inputs
        try:
            selected_path = json.loads(path_history)
            exploration_parameters = json.loads(parameters)
        except json.JSONDecodeError as e:
            raise ValueError(f"Invalid JSON input: {str(e)}")

        # Add parameters
        exploration_parameters.update({
            "domain": domain,
            "depth": depth
        })

        # Generate result
        result = generator.generate_exploration_path(
            query=query,
            selected_path=selected_path,
            exploration_parameters=exploration_parameters
        )

        # Create visualization
        graph_html = generator.create_visualization_html(result.get('nodes', []))
        
        summary = f"Exploration path generated with {len(result.get('nodes', []))} nodes"
        
        return json.dumps(result), graph_html, summary

    except Exception as e:
        error_response = {
            "error": str(e),
            "status": "failed",
            "timestamp": datetime.now().isoformat(),
            "query": query
        }
        return json.dumps(error_response), "<div>Error generating visualization</div>", f"Error: {str(e)}"

def create_interface() -> gr.Blocks:
    """Create and configure the Gradio interface"""
    with gr.Blocks(
        title="Art History Exploration Path Generator",
        theme=gr.themes.Soft()
    ) as interface:
        gr.Markdown("""
        # Knowledge Exploration Path Generator
        Generate interactive exploration paths through complex topics.
        """)

        with gr.Row():
            with gr.Column(scale=1):
                query_input = gr.Textbox(
                    label="Exploration Query",
                    placeholder="Enter your exploration query...",
                    lines=2
                )
                
                depth = gr.Slider(
                    label="Exploration Depth",
                    minimum=1,
                    maximum=10,
                    value=5,
                    step=1
                )
                
                domain = gr.Textbox(
                    label="Domain Context",
                    placeholder="Optional: Specify domain context",
                    lines=1
                )
                
                generate_btn = gr.Button("Generate Exploration Path", variant="primary")

            with gr.Column(scale=2):
                text_output = gr.JSON(label="Raw Result")
                graph_output = gr.HTML(label="Visualization")
                summary_output = gr.Textbox(label="Summary", lines=2)

        generate_btn.click(
            fn=explore,
            inputs=[
                query_input,
                gr.Textbox(value="[]", visible=False),
                gr.Textbox(value="{}", visible=False),
                depth,
                domain
            ],
            outputs=[text_output, graph_output, summary_output]
        )

        return interface

if __name__ == "__main__":
    try:
        print(f"===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====")
        demo = create_interface()
        demo.launch(
            server_name="0.0.0.0",
            server_port=7860,
            share=True
        )
    except Exception as e:
        print(f"Failed to launch interface: {e}")