# Project export: Graphly

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2025
- Tagline: Map everything, digital twin of entire urbanization!
- Devpost: https://devpost.com/software/graph-vkbi9l
- GitHub: https://github.com/SunfishTK1/graphly
- Video: https://www.youtube.com/embed/s-9ErxcfFXw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Alp Niksarlı (4 commits), Thomas Kanz (3 commits), utkanuygur (2 commits)

## Devpost submission (written by the team)

### Overview

Video Demo

### Inspiration

Current search is broken. Search engines rely on string matching and keyword tuning, not true understanding. With LLMs and graphs, we can rebuild search from the ground up—semantic, contextual, and interactive. We're starting with a digital twin of the real world, beginning in Berkeley.

### What it does

Graph is a world-scale knowledge engine where everything is a node. People, places, facts, and memories are embedded in a graph through LLMs and GraphRAG. Users can search the entire graph in natural language, visualize the connections, and even place themselves inside it. You can query a building, a person, or an event, and get a response that knows how it's all linked—contextually and relationally.

### How we built it

We used: Python and various LLMs to intensely augment the data FastAPI to handle LLM requests and orchestrate backend services GraphRAG to build context-aware graph data structures Azure OpenAI and Claude to fetch embeddings and perform agentic workflows React + TypeScript for a fast, smooth frontend Gemini for multimodal agent capabilities GraphQL to structure graph queries Cloudflare + Azure Foundry for scalable hosting and caching Each node in the graph holds a vector, powered by Azure’s text-embedding-3-large. Our server connects these embeddings to LLM outputs in a real-time interactive interface. 🤝 Sponsors + Products We Used Azure OpenAI – GPT-4o + o4-mini for embedding, classification, and multi-modal understanding Anthropic – Claude for rich, long-form scraping and agentic workflows Gemini – Pro model used for image + text understanding, redundancy checking Letta AI – Agent routing, orchestration, and multi-agent memory handling Vapi – Voice interface (in progress) for real-time audio interactions Fetch AI – Used for real-time planning agents and knowledge graph updates

### Challenges we ran into

Graph complexity: Making vectorized nodes traversable in real time while keeping contextual awareness LLM integration: Getting Claude, Gemini, and Azure GPT-4o to work smoothly in parallel agent workflows Latency and cost: Balancing responsiveness with API rate limits and inference pricing Frontend–graph sync: Visualizing real-time graph updates was tricky to optimize

### Accomplishments we're proud of

Built a full LLM-powered GraphRAG stack end-to-end in one weekend Fully integrated Claude, GPT-4o, Gemini, and Fetch into agent workflows Designed a real-time graph search UX where users can explore knowledge as a map Used cutting-edge tools like Azure Foundry and Cloudflare Vectorize to scale intelligently

### What we learned

Agent workflows are powerful but chaotic. Memory, planning, and tools need strict control Vector databases and graph databases are very different beasts, but we merged them effectively Building with multiple LLM providers (OpenAI, Anthropic, Google) unlocked new use cases and capabilities

### What's next

for Graph Make it multiplayer: users can collaborate in a shared knowledge space Zoom out: bring in more cities, institutions, and data sets Decentralize: users can own their nodes and control what they share Release a public search portal to explore the Berkeley knowledge graph in real time Add interactive voice agent integration using Vapi or other tools

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 13 recognized source files, 145 KB.
- Python (language) — detected in the code
- FastAPI (technology) — claimed on Devpost, not found in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- OpenAI (technology) — claimed on Devpost, not found in the code
- React (technology) — claimed on Devpost, not found in the code
- TypeScript (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (27 of 27)

```
.DS_Store
.gitignore
augmented_data/business_info_first_100.csv
augmented_data/business_info.csv
complex_graph_data.json
complex_graph.pkl
data_augmentation.py
data.ipynb
graphrag_mayavi.py
graphrag.py
hi.txt
knowledge_graph_summary.json
letta.mermaid
load_knowledge_graph.py
load_specific_kg.py
Makefile
mayavi_demo.py
mayavi_simple_demo.py
mplot3d_demo.py
plotly_3d_demo.py
pyvista_demo.py
pyvista_simple_test.py
query_graph.py
raw_data/Business_Licenses_20250621.csv
requirements.txt
sample_graphrag/.gitignore
sample_graphrag/chat.py
```

### Dependencies

- requirements.txt: matplotlib@>=3.5.0, mayavi@>=4.7.0, numpy@>=1.21.0, plotly@>=5.0.0, PySide6@>=6.0.0, pyvista@>=0.40.0

### Recent commits (newest first)

- Merge pull request #1 from SunfishTK1/visualizer
- added visualizer
- Integrate Letta for memory perservation
- Add multi-provider LLM support
- Augment full data
- Augment first 100 business data
- sample chat with azure
- Uploaded business license data now
- hi

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
matplotlib>=3.5.0
numpy>=1.21.0
mayavi>=4.7.0
PySide6>=6.0.0
pyvista>=0.40.0
plotly>=5.0.0 
```

### data_augmentation.py

```python
# %%


# %%

# %%

# %%

# %%

# %%

# %%




```

### pyvista_simple_test.py

```python
#!/usr/bin/env python3
"""
Simple PyVista Test
===================

A simple test to verify PyVista is working correctly.
"""

import numpy as np
import pyvista as pv

def simple_test():
    """Create a simple 3D plot to test PyVista"""
    print("Testing PyVista...")
    
    # Create a simple sphere
    sphere = pv.Sphere(radius=2)
    
    # Create plotter
    plotter = pv.Plotter()
    
    # Add the sphere
    plotter.add_mesh(sphere, color='red', opacity=0.8)
    plotter.add_title('PyVista Test - Simple Sphere')
    
    # Show the plot
    print("Opening 3D window... Close the window when done.")
    plotter.show()
    
    print("PyVista test completed successfully!")

if __name__ == "__main__":
    simple_test() 
```

### mayavi_simple_demo.py

```python
#!/usr/bin/env python3
"""
Simple Mayavi Demo
==================

A simple demonstration of Mayavi's 3D visualization capabilities.
This script creates a few basic 3D plots to showcase Mayavi's features.

Run this script to test if Mayavi is working correctly on your system.
"""

import numpy as np
from mayavi import mlab

def simple_3d_plot():
    """Create a simple 3D surface plot"""
    print("Creating 3D Surface Plot...")
    
    # Clear any existing plots
    mlab.clf()
    
    # Generate data for a simple surface
    x, y = np.mgrid[-2:2:50j, -2:2:50j]
    z = np.sin(x*np.pi) * np.cos(y*np.pi) * np.exp(-(x**2 + y**2)/2)
    
    # Create the surface plot
    surf = mlab.surf(x, y, z, colormap='viridis')
    
    # Add a title and labels
    mlab.title('Simple 3D Surface', size=0.3)
    mlab.axes(xlabel='X', ylabel='Y', zlabel='Z')
    mlab.colorbar(surf, title="Height")
    
    # Show the plot
    mlab.show()

def scatter_3d():
    """Create a 3D scatter plot"""
    print("Creating 3D Scatter Plot...")
    
    mlab.clf()
    
    # Generate random data
    n = 500
    x = np.random.randn(n)
    y = np.random.randn(n) 
    z = np.random.randn(n)
    colors = x + y  # Color based on x+y values
    
    # Create scatter plot
    pts = mlab.points3d(x, y, z, colors, scale_mode='none', scale_factor=0.1)
    
    mlab.title('3D Scatter Plot', size=0.3)
    mlab.colorbar(pts, title="X+Y Value")
    
    mlab.show()

def vector_field():
    """Create a simple vector field visualization"""
    print("Creating Vector Field...")
    
    mlab.clf()
    
    # Generate vector field data
    x, y, z = np.mgrid[-1:1:8j, -1:1:8j, -1:1:8j]
    
    # Simple vector field (circulation)
    u = -y
    v = x
    w = z * 0.1
    
    # Create vector field plot
    vectors = mlab.quiver3d(x, y, z, u, v, w, scale_factor=0.3)
    
    mlab.title('Vector Field Visualization', size=0.3)
    
    mlab.show()

def main():
    """Run the demo"""
    print("Mayavi Simple Demo")
    print("==================")
    print("This demo will show three different types of 3D visualizations.")
    print("Close each window to proceed to the next demo.\n")
    
    demos = [
        ("3D Surface", simple_3d_plot),
        ("3D Scatter", scatter_3d),
        ("Vector Field", vector_field)
    ]
    
    for name, demo_func in demos:
        print(f"\nRunning {name} demo...")
        try:
            demo_func()
        except Exception as e:
            print(f"Error running {name}: {e}")
            print("Make sure you have a display available and Mayavi is properly installed.")
        
        input("Press Enter to continue to next demo...")
    
    print("\nDemo complete! Mayavi is working correctly.")

if __name__ == "__main__":
    main() 
```

### mplot3d_demo.py

```python
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.patches as patches

def demo_3d_scatter():
    """Demo of 3D scatter plot"""
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate random data
    n = 100
    x = np.random.randn(n)
    y = np.random.randn(n)
    z = np.random.randn(n)
    colors = np.random.randn(n)
    
    # Create scatter plot
    scatter = ax.scatter(x, y, z, c=colors, cmap='viridis', s=60, alpha=0.7)
    
    ax.set_xlabel('X Label')
    ax.set_ylabel('Y Label')
    ax.set_zlabel('Z Label')
    ax.set_title('3D Scatter Plot Demo')
    
    # Add colorbar
    plt.colorbar(scatter)
    plt.show()

def demo_3d_line():
    """Demo of 3D line plot"""
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate parametric curve data
    t = np.linspace(0, 4*np.pi, 100)
    x = np.cos(t)
    y = np.sin(t)
    z = t
    
    # Create line plot
    ax.plot(x, y, z, 'b-', linewidth=2, label='Helix')
    
    # Add another curve
    x2 = np.cos(t) * np.exp(-t/10)
    y2 = np.sin(t) * np.exp(-t/10)
    z2 = t
    ax.plot(x2, y2, z2, 'r-', linewidth=2, label='Decaying Helix')
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D Line Plot Demo')
    ax.legend()
    plt.show()

def demo_3d_surface():
    """Demo of 3D surface plot"""
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate surface data
    x = np.linspace(-5, 5, 50)
    y = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2))
    
    # Create surface plot
    surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, alpha=0.8)
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D Surface Plot Demo')
    
    # Add colorbar
    fig.colorbar(surf)
    plt.show()

def demo_3d_wireframe():
    """Demo of 3D wireframe plot"""
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate wireframe data
    x = np.linspace(-3, 3, 30)
    y = np.linspace(-3, 3, 30)
    X, Y = np.meshgrid(x, y)
    Z = X * np.exp(-X**2 - Y**2)
    
    # Create wireframe plot
    ax.plot_wireframe(X, Y, Z, color='blue', alpha=0.7)
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D Wireframe Plot Demo')
    plt.show()

def demo_3d_contour():
    """Demo of 3D contour plot"""
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate contour data
    x = np.linspace(-3, 3, 30)
    y = np.linspace(-3, 3, 30)
    X, Y = np.meshgrid(x, y)
    Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2)
    
    # Create 3D contour plot
    contours = ax.contour(X, Y, Z, levels=15, cmap='viridis')
    ax.clabel(contours, inline=True, fontsize=8)
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D Contour Plot Demo')
    plt.show()

def demo_3d_bar():
    """Demo of 3D bar plot"""
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate bar data
    xpos = np.arange(5)
    ypos = np.arange(4)
    xposM, yposM = np.meshgrid(xpos, ypos)
    
    xpos = xposM.ravel()
    ypos = yposM.ravel()
    zpos = np.zeros(20)
    
    dx = np.ones(20) * 0.5
    dy = np.ones(20) * 0.5
    dz = np.random.randint(1, 10, 20)
    
    colors = cm.rainbow(dz/float(max(dz)))
    
    # Create 3D bar plot
    ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=colors, alpha=0.8)
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D Bar Plot Demo')
    plt.show()

def demo_parametric_surface():
    """Demo of parametric surface"""
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # Generate parametric surface (torus)
    u = np.linspace(0, 2 * np.pi, 50)
    v = np.linspace(0, 2 * np.pi, 50)
    U, V = np.meshgrid(u, v)
    
    R = 3  # Major radius
    r = 1  # Minor radius
    
    X = (R + r * np.cos(V)) * np.cos(U)
    Y = (R + r * np.cos(V)) * np.sin(U)
    Z = r * np.sin(V)
    
    # Create parametric surface plot
    ax.plot_surface(X, Y, Z, cmap='plasma', alpha=0.8)
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('Parametric Surface Demo (Torus)')
    plt.show()

def demo_multiple_subplots():
    """Demo of multiple 3D subplots"""
    fig = plt.figure(figsize=(15, 10))
    
    # Subplot 1: Scatter
    ax1 = fig.add_subplot(221, projection='3d')
    n = 50
    x = np.random.randn(n)
    y = np.random.randn(n)
    z = np.random.randn(n)
    ax1.scatter(x, y, z, c='red', s=50)
    ax1.set_title('3D Scatter')
    
    # Subplot 2: Line
    ax2 = fig.add_subplot(222, projection='3d')
    t = np.linspace(0, 2*np.pi, 50)
    x = np.cos(t)
    y = np.sin(t)
    z = t
    ax2.plot(x, y, z, 'b-', linewidth=2)
    ax2.set_title('3D Line')
    
    # Subplot 3: Surface
    ax3 = fig.add_subplot(223, projection='3d')
    x = np.linspace(-2, 2, 20)
    y = np.linspace(-2, 2, 20)
    X, Y = np.meshgrid(x, y)
    Z = X**2 + Y**2
    ax3.plot_surface(X, Y, Z, cmap='viridis', alpha=0.7)
    ax3.set_title('3D Surface')
    
    # Subplot 4: Wireframe
    ax4 = fig.add_subplot(224, projection='3d')
    x = np.linspace(-2, 2, 15)
    y = np.linspace(-2, 2, 15)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(X) * np.cos(Y)
    ax4.plot_wireframe(X, Y, Z, color='green')
    ax4.set_title('3D Wireframe')
    
    plt.tight_layout()
    plt.show()

def main():
    """Run all demos"""
    print("3D Plotting Demo with mpl_toolkits.mplot3d")
    print("==========================================")
    
    demos = [
        ("3D Scatter Plot", demo_3d_scatter),
        ("3D Line Plot", demo_3d_line),
        ("3D Surface Plot", 
[truncated — 637 more characters]
```

### load_specific_kg.py

```python
#!/usr/bin/env python3
"""
Load Specific Knowledge Graph Format
===================================
This script loads the specific knowledge_graph.pkl format with entity_map and relationship_map
"""

from graphrag import GraphRAG, Entity, Relation
import matplotlib.pyplot as plt
import numpy as np
import pickle
import random

def load_specific_knowledge_graph():
    """Load the specific knowledge graph format and create 3D visualization"""
    print("Loading knowledge_graph.pkl (Specific Format)")
    print("=" * 50)
    
    # Load the pickle file
    try:
        with open("knowledge_graph.pkl", 'rb') as f:
            data = pickle.load(f)
        print("✓ Successfully loaded pickle file")
    except Exception as e:
        print(f"✗ Error loading pickle file: {e}")
        return None
    
    # Extract the components
    entity_map = data.get('entity_map', {})
    relationship_map = data.get('relationship_map', {})
    community_summaries = data.get('community_summaries', {})
    
    print(f"Found {len(entity_map)} entities")
    print(f"Found {len(relationship_map)} relationship entries")
    print(f"Found {len(community_summaries)} community summaries")
    
    # Initialize GraphRAG
    graph_rag = GraphRAG()
    
    # Convert entities
    print("\nConverting entities...")
    entity_count = 0
    for entity_name, entity_info in entity_map.items():
        if isinstance(entity_info, dict):
            entity = Entity(
                id=f"entity_{entity_count}",
                name=entity_name,
                type=entity_info.get('type', 'ENTITY'),
                properties=entity_info
            )
            graph_rag.add_entity(entity)
            entity_count += 1
            
            if entity_count % 1000 == 0:
                print(f"  Processed {entity_count} entities...")
    
    print(f"✓ Converted {entity_count} entities")
    
    # Convert relationships
    print("\nConverting relationships...")
    relation_count = 0
    entity_name_to_id = {entity.name: entity.id for entity in graph_rag.entities.values()}
    
    for source_entity, relationships in relationship_map.items():
        if source_entity in entity_name_to_id:
            source_id = entity_name_to_id[source_entity]
            
            if isinstance(relationships, list):
                for rel_info in relationships:
                    if isinstance(rel_info, dict):
                        target_entity = rel_info.get('target', '')
                        relation_type = rel_info.get('type', 'RELATED')
                        
                        if target_entity in entity_name_to_id:
                            target_id = entity_name_to_id[target_entity]
                            
                            relation = Relation(
                                id=f"rel_{relation_count}",
                                source=source_id,
                                target=target_id,
                                relation_type=relation_type,
                                properties=rel_info
                            )
                            graph_rag.add_relation(relation)
                            relation_count += 1
                            
                            if relation_count % 1000 == 0:
                                print(f"  Processed {relation_count} relationships...")
    
    print(f"✓ Converted {relation_count} relationships")
    
    # Show statistics
    stats = graph_rag.get_statistics()
    print(f"\nFinal Knowledge Graph Statistics:")
    for key, value in stats.items():
        print(f"  {key}: {value}")
    
    # Sample the graph for visualization (it's too large)
    print(f"\nSampling graph for visualization...")
    sampled_graph = sample_large_graph(graph_rag, max_nodes=100)
    sampled_stats = sampled_graph.get_statistics()
    print(f"Sampled Graph Statistics:")
    for key, value in sampled_stats.items():
        print(f"  {key}: {value}")
    
    # Create 3D visualization
    print(f"\nGenerating 3D visualization...")
    try:
        sampled_graph.visualize_3d("knowledge_graph_3d.png")
        print("✓ 3D visualization completed!")
        
        # Also create 2D for comparison
        print("Generating 2D visualization...")
        sampled_graph.visualize_2d("knowledge_graph_2d.png")
        print("✓ 2D visualization completed!")
        
    except Exception as e:
        print(f"✗ Error during visualization: {e}")
    
    return graph_rag, sampled_graph

def sample_large_graph(graph_rag, max_nodes=100):
    """Sample a large graph to make it manageable for visualization"""
    print(f"Sampling {max_nodes} nodes from {len(graph_rag.entities)} entities...")
    
    # Create a new GraphRAG with sampled nodes
    sampled_graph = GraphRAG()
    
    # Sample entities randomly
    all_entities = list(graph_rag.entities.values())
    if len(all_entities) > max_nodes:
        sampled_entities = random.sample(all_entities, max_nodes)
    else:
        sampled_entities = all_entities
    
    # Add sampled entities
    for entity in sampled_entities:
        sampled_graph.add_entity(entity)
    
    sampled_entity_ids = {entity.id for entity in sampled_entities}
    
    # Add relations between sampled entities
    relation_count = 0
    for relation in graph_rag.relations.values():
        if relation.source in sampled_entity_ids and relation.target in sampled_entity_ids:
            sampled_graph.add_relation(relation)
            relation_count += 1
    
    print(f"✓ Sampled {len(sampled_entities)} entities and {relation_count} relations")
    return sampled_graph

def analyze_entity_types(graph_rag):
    """Analyze entity types in the graph"""
    print(f"\nEntity Type Analysis:")
    print(f"=" * 30)
    
    entity_types = {}
    for entity in graph_rag.entities.values():
        entity_type = entity.type
        entity_types[entity_type] = entity_types.get(entity_type, 0) + 1
    
    # Show top 10 most common entity
[truncated — 2330 more characters]
```

### mayavi_demo.py

```python
import numpy as np
from mayavi import mlab
import matplotlib.pyplot as plt

def demo_3d_points():
    """Demo of 3D points with Mayavi"""
    print("3D Points Demo")
    
    # Generate random data
    n = 1000
    x = np.random.randn(n)
    y = np.random.randn(n)
    z = np.random.randn(n)
    s = np.random.randn(n)  # scalar data for coloring
    
    # Clear previous plots
    mlab.clf()
    
    # Create 3D points plot
    pts = mlab.points3d(x, y, z, s, scale_mode='none', scale_factor=0.05)
    
    # Customize the plot
    mlab.title('3D Points with Mayavi', size=0.2)
    mlab.colorbar(pts, title="Values", orientation="vertical")
    
    mlab.show()

def demo_3d_line():
    """Demo of 3D line plots"""
    print("3D Line Demo")
    
    mlab.clf()
    
    # Generate parametric curves
    t = np.linspace(0, 4*np.pi, 200)
    
    # Helix
    x1 = np.cos(t)
    y1 = np.sin(t)
    z1 = t
    
    # Decaying helix
    x2 = np.cos(t) * np.exp(-t/10)
    y2 = np.sin(t) * np.exp(-t/10)
    z2 = t
    
    # Plot lines
    mlab.plot3d(x1, y1, z1, color=(0, 0, 1), tube_radius=0.05)
    mlab.plot3d(x2, y2, z2, color=(1, 0, 0), tube_radius=0.05)
    
    mlab.title('3D Lines: Helix and Decaying Helix', size=0.2)
    mlab.show()

def demo_surface():
    """Demo of surface plots"""
    print("Surface Demo")
    
    mlab.clf()
    
    # Generate surface data
    x, y = np.mgrid[-3:3:100j, -3:3:100j]
    z = np.sin(np.sqrt(x**2 + y**2))
    
    # Create surface plot
    surf = mlab.surf(x, y, z, colormap='viridis')
    
    mlab.title('3D Surface Plot', size=0.2)
    mlab.colorbar(surf, title="Height", orientation="vertical")
    mlab.show()

def demo_mesh():
    """Demo of mesh plots"""
    print("Mesh Demo")
    
    mlab.clf()
    
    # Generate mesh data
    phi, theta = np.mgrid[0:np.pi:20j, 0:2*np.pi:20j]
    x = np.sin(phi) * np.cos(theta)
    y = np.sin(phi) * np.sin(theta)
    z = np.cos(phi)
    
    # Create mesh plot (sphere)
    mesh = mlab.mesh(x, y, z, colormap='plasma')
    
    mlab.title('3D Mesh: Sphere', size=0.2)
    mlab.show()

def demo_contour3d():
    """Demo of 3D contour plots"""
    print("3D Contour Demo")
    
    mlab.clf()
    
    # Generate 3D scalar field
    x, y, z = np.mgrid[-5:5:64j, -5:5:64j, -5:5:64j]
    scalars = np.sin(x*y*z) / (x*y*z + 0.1)
    
    # Create 3D contour plot
    contour = mlab.contour3d(scalars, contours=8, transparent=True, colormap='coolwarm')
    
    mlab.title('3D Contour Plot', size=0.2)
    mlab.colorbar(contour, title="Values", orientation="vertical")
    mlab.show()

def demo_volume():
    """Demo of volume rendering"""
    print("Volume Rendering Demo")
    
    mlab.clf()
    
    # Generate 3D volume data
    x, y, z = np.mgrid[-10:10:64j, -10:10:64j, -10:10:64j]
    r = np.sqrt(x**2 + y**2 + z**2)
    volume_data = np.exp(-r**2/50) * np.sin(r)
    
    # Create volume plot
    vol = mlab.pipeline.volume(mlab.pipeline.scalar_field(volume_data), 
                               vmin=0, vmax=0.8)
    
    mlab.title('Volume Rendering', size=0.2)
    mlab.show()

def demo_quiver3d():
    """Demo of 3D vector field"""
    print("3D Vector Field Demo")
    
    mlab.clf()
    
    # Generate vector field data
    x, y, z = np.mgrid[-2:3:10j, -2:3:10j, -2:3:10j]
    u = np.sin(np.pi*x) * np.cos(np.pi*z)
    v = -2*np.sin(np.pi*y) * np.cos(2*np.pi*z)
    w = np.cos(np.pi*x)*np.sin(np.pi*z) + np.cos(np.pi*y)*np.sin(2*np.pi*z)
    
    # Create vector field plot
    quiver = mlab.quiver3d(x, y, z, u, v, w, scale_factor=0.5, colormap='jet')
    
    mlab.title('3D Vector Field', size=0.2)
    mlab.colorbar(quiver, title="Magnitude", orientation="vertical")
    mlab.show()

def demo_pipeline():
    """Demo of Mayavi pipeline for advanced visualization"""
    print("Advanced Pipeline Demo")
    
    mlab.clf()
    
    # Generate data
    x, y, z = np.mgrid[-3:3:64j, -3:3:64j, -3:3:64j]
    scalars = x*x*0.5 + y*y + z*z*2.0
    
    # Create scalar field
    src = mlab.pipeline.scalar_field(scalars)
    
    # Add iso-surfaces at different levels
    iso1 = mlab.pipeline.iso_surface(src, contours=[scalars.min()+0.1*scalars.ptp()], 
                                     colormap='Reds', opacity=0.3)
    iso2 = mlab.pipeline.iso_surface(src, contours=[scalars.min()+0.5*scalars.ptp()], 
                                     colormap='Blues', opacity=0.3)
    iso3 = mlab.pipeline.iso_surface(src, contours=[scalars.min()+0.9*scalars.ptp()], 
                                     colormap='Greens', opacity=0.3)
    
    # Add a plane cut
    plane = mlab.pipeline.scalar_cut_plane(src, plane_orientation='z_axes')
    
    mlab.title('Advanced Pipeline: Multiple Iso-surfaces + Cut Plane', size=0.2)
    mlab.show()

def demo_parametric_surface():
    """Demo of parametric surfaces"""
    print("Parametric Surface Demo")
    
    mlab.clf()
    
    # Generate parametric surface (torus)
    phi, theta = np.mgrid[0:2*np.pi:40j, 0:2*np.pi:40j]
    R = 3  # major radius
    r = 1  # minor radius
    
    x = (R + r*np.cos(theta)) * np.cos(phi)
    y = (R + r*np.cos(theta)) * np.sin(phi)
    z = r * np.sin(theta)
    
    # Color by height
    colors = z
    
    # Create parametric surface
    surf = mlab.mesh(x, y, z, scalars=colors, colormap='plasma')
    
    mlab.title('Parametric Surface: Torus', size=0.2)
    mlab.colorbar(surf, title="Height", orientation="vertical")
    mlab.show()

def demo_molecular_visualization():
    """Demo of molecular-like visualization"""
    print("Molecular Visualization Demo")
    
    mlab.clf()
    
    # Generate atomic positions (simple cubic lattice)
    n = 5
    x, y, z = np.mgrid[0:n:1, 0:n:1, 0:n:1]
    x = x.flatten()
    y = y.flatten()
    z = z.flatten()
    
    # Add some random displacement
    x += np.random.randn(len(x)) * 0.1
    y += np.random.randn(len(y)) * 0.1
    z += np.random.randn(len(z)) * 0.1
    
    # Different atom types
    atom_types = np.random.randint(0, 3, len(x))
    
    # 
[truncated — 2467 more characters]
```

### pyvista_demo.py

```python
#!/usr/bin/env python3
"""
PyVista 3D Visualization Demo
=============================

A comprehensive demonstration of PyVista's 3D visualization capabilities.
PyVista is often more reliable and easier to use than Mayavi.

Run this script to see various 3D visualization examples.
"""

import numpy as np
import pyvista as pv
import matplotlib.pyplot as plt

def demo_basic_surface():
    """Create a basic 3D surface plot"""
    print("Creating Basic 3D Surface...")
    
    # Generate surface data
    x = np.arange(-10, 10, 0.25)
    y = np.arange(-10, 10, 0.25)
    x, y = np.meshgrid(x, y)
    z = np.sin(np.sqrt(x**2 + y**2))
    
    # Create a structured grid
    grid = pv.StructuredGrid(x, y, z)
    
    # Plot
    plotter = pv.Plotter()
    plotter.add_mesh(grid, colormap='viridis', show_edges=True)
    plotter.add_title('Basic 3D Surface')
    plotter.show()

def demo_scatter_3d():
    """Create a 3D scatter plot"""
    print("Creating 3D Scatter Plot...")
    
    # Generate random data
    n = 1000
    points = np.random.randn(n, 3)
    colors = np.linalg.norm(points, axis=1)
    
    # Create point cloud
    cloud = pv.PolyData(points)
    cloud['colors'] = colors
    
    # Plot
    plotter = pv.Plotter()
    plotter.add_mesh(cloud, scalars='colors', colormap='plasma', 
                     point_size=8, render_points_as_spheres=True)
    plotter.add_title('3D Scatter Plot')
    plotter.show()

def demo_parametric_surface():
    """Create parametric surfaces"""
    print("Creating Parametric Surfaces...")
    
    # Create torus
    torus = pv.ParametricTorus(ringradius=3, crosssectionalradius=1)
    
    # Create sphere
    sphere = pv.Sphere(radius=1.5, center=(6, 0, 0))
    
    # Plot both
    plotter = pv.Plotter()
    plotter.add_mesh(torus, color='red', opacity=0.8)
    plotter.add_mesh(sphere, color='blue', opacity=0.8)
    plotter.add_title('Parametric Surfaces: Torus and Sphere')
    plotter.show()

def demo_volume_rendering():
    """Create volume rendering"""
    print("Creating Volume Rendering...")
    
    # Create 3D data
    dims = (64, 64, 64)
    origin = (-2, -2, -2)
    spacing = (4/(dims[0]-1), 4/(dims[1]-1), 4/(dims[2]-1))
    
    # Create structured grid
    grid = pv.ImageData(dimensions=dims, origin=origin, spacing=spacing)
    
    # Generate scalar field
    x, y, z = grid.points.T
    scalars = np.sin(x*y*z) * np.exp(-(x**2 + y**2 + z**2)/4)
    grid['scalars'] = scalars
    
    # Volume rendering
    plotter = pv.Plotter()
    plotter.add_volume(grid, scalars='scalars', cmap='viridis', opacity='sigmoid')
    plotter.add_title('Volume Rendering')
    plotter.show()

def demo_vector_field():
    """Create vector field visualization"""
    print("Creating Vector Field...")
    
    # Create grid
    x = np.arange(-5, 5, 1)
    y = np.arange(-5, 5, 1)
    z = np.arange(-5, 5, 1)
    x, y, z = np.meshgrid(x, y, z)
    
    # Create vectors
    u = -y
    v = x
    w = z * 0.1
    
    # Create vector field
    points = np.column_stack((x.ravel(), y.ravel(), z.ravel()))
    vectors = np.column_stack((u.ravel(), v.ravel(), w.ravel()))
    
    grid = pv.PolyData(points)
    grid['vectors'] = vectors
    
    # Create arrows
    arrows = grid.glyph(orient='vectors', scale='vectors', factor=0.3)
    
    # Plot
    plotter = pv.Plotter()
    plotter.add_mesh(arrows, colormap='jet')
    plotter.add_title('Vector Field Visualization')
    plotter.show()

def demo_multiple_objects():
    """Create scene with multiple objects"""
    print("Creating Multi-Object Scene...")
    
    # Create various objects
    sphere = pv.Sphere(radius=1, center=(0, 0, 0))
    cube = pv.Cube(center=(3, 0, 0))
    cone = pv.Cone(center=(-3, 0, 0))
    cylinder = pv.Cylinder(center=(0, 3, 0))
    
    # Create surface
    x = np.arange(-2, 2, 0.1)
    y = np.arange(-2, 2, 0.1)
    x, y = np.meshgrid(x, y)
    z = np.sin(x) * np.cos(y) - 2
    surface = pv.StructuredGrid(x, y, z)
    
    # Plot all
    plotter = pv.Plotter()
    plotter.add_mesh(sphere, color='red', opacity=0.8)
    plotter.add_mesh(cube, color='blue', opacity=0.8)
    plotter.add_mesh(cone, color='green', opacity=0.8)
    plotter.add_mesh(cylinder, color='yellow', opacity=0.8)
    plotter.add_mesh(surface, colormap='viridis', opacity=0.6)
    plotter.add_title('Multi-Object 3D Scene')
    plotter.show()

def demo_contours():
    """Create contour plots"""
    print("Creating 3D Contours...")
    
    # Generate data
    x = np.arange(-5, 5, 0.2)
    y = np.arange(-5, 5, 0.2)
    z = np.arange(-5, 5, 0.2)
    x, y, z = np.meshgrid(x, y, z)
    
    # Create scalar field
    scalars = x**2 + y**2 + z**2
    
    # Create grid
    grid = pv.StructuredGrid(x, y, z)
    grid['scalars'] = scalars.ravel()
    
    # Create contours
    contours = grid.contour(isosurfaces=6)
    
    # Plot
    plotter = pv.Plotter()
    plotter.add_mesh(contours, colormap='coolwarm', opacity=0.7)
    plotter.add_title('3D Contour Surfaces')
    plotter.show()

def demo_molecular_structure():
    """Create molecular-like structure"""
    print("Creating Molecular Structure...")
    
    # Generate atomic positions
    n_atoms = 50
    positions = np.random.randn(n_atoms, 3) * 3
    
    # Create atoms as spheres
    atoms = pv.PolyData(positions)
    atom_spheres = atoms.glyph(geom=pv.Sphere(radius=0.2))
    
    # Create bonds (connect nearby atoms)
    bonds = []
    for i in range(n_atoms):
        for j in range(i+1, n_atoms):
            dist = np.linalg.norm(positions[i] - positions[j])
            if dist < 2.0:  # bond threshold
                bond = pv.Line(positions[i], positions[j])
                bonds.append(bond)
    
    # Combine bonds
    if bonds:
        all_bonds = bonds[0]
        for bond in bonds[1:]:
            all_bonds = all_bonds + bond
    
    # Plot
    plotter = pv.Plotter()
    plotter.add_mesh(atom_spheres, color='red')
    if bonds:
        plotter.add_mesh(all_bonds, color='gray', line_width=3)
   
[truncated — 2988 more characters]
```

### plotly_3d_demo.py

```python
#!/usr/bin/env python3
"""
Plotly 3D Visualization Demo
============================

A comprehensive demonstration of Plotly's 3D visualization capabilities.
Plotly opens visualizations in your web browser, making it very reliable.

Run this script to see various 3D visualizations in your browser.
"""

import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.offline as pyo

def demo_3d_scatter():
    """Create a 3D scatter plot"""
    print("Creating 3D Scatter Plot...")
    
    # Generate random data
    n = 500
    x = np.random.randn(n)
    y = np.random.randn(n)
    z = np.random.randn(n)
    colors = x + y + z  # Color based on sum
    
    # Create scatter plot
    fig = go.Figure(data=go.Scatter3d(
        x=x, y=y, z=z,
        mode='markers',
        marker=dict(
            size=8,
            color=colors,
            colorscale='Viridis',
            colorbar=dict(title="Values"),
            opacity=0.8
        )
    ))
    
    fig.update_layout(
        title='3D Scatter Plot with Plotly',
        scene=dict(
            xaxis_title='X Axis',
            yaxis_title='Y Axis',
            zaxis_title='Z Axis'
        )
    )
    
    fig.show()

def demo_3d_surface():
    """Create a 3D surface plot"""
    print("Creating 3D Surface Plot...")
    
    # Generate surface data
    x = np.linspace(-5, 5, 50)
    y = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2))
    
    # Create surface plot
    fig = go.Figure(data=go.Surface(
        x=X, y=Y, z=Z,
        colorscale='Viridis',
        colorbar=dict(title="Height")
    ))
    
    fig.update_layout(
        title='3D Surface Plot',
        scene=dict(
            xaxis_title='X',
            yaxis_title='Y',
            zaxis_title='Z'
        )
    )
    
    fig.show()

def demo_3d_line():
    """Create 3D line plots"""
    print("Creating 3D Line Plot...")
    
    # Generate parametric curves
    t = np.linspace(0, 4*np.pi, 200)
    
    # Helix
    x1 = np.cos(t)
    y1 = np.sin(t)
    z1 = t
    
    # Decaying helix
    x2 = np.cos(t) * np.exp(-t/10)
    y2 = np.sin(t) * np.exp(-t/10)
    z2 = t
    
    # Create figure
    fig = go.Figure()
    
    # Add helix
    fig.add_trace(go.Scatter3d(
        x=x1, y=y1, z=z1,
        mode='lines',
        line=dict(color='blue', width=6),
        name='Helix'
    ))
    
    # Add decaying helix
    fig.add_trace(go.Scatter3d(
        x=x2, y=y2, z=z2,
        mode='lines',
        line=dict(color='red', width=6),
        name='Decaying Helix'
    ))
    
    fig.update_layout(
        title='3D Line Plots: Helix and Decaying Helix',
        scene=dict(
            xaxis_title='X',
            yaxis_title='Y',
            zaxis_title='Z'
        )
    )
    
    fig.show()

def demo_3d_mesh():
    """Create 3D mesh plot"""
    print("Creating 3D Mesh Plot...")
    
    # Generate sphere data
    phi = np.linspace(0, np.pi, 20)
    theta = np.linspace(0, 2*np.pi, 20)
    phi, theta = np.meshgrid(phi, theta)
    
    x = np.sin(phi) * np.cos(theta)
    y = np.sin(phi) * np.sin(theta)
    z = np.cos(phi)
    
    # Create mesh plot
    fig = go.Figure(data=go.Mesh3d(
        x=x.flatten(),
        y=y.flatten(),
        z=z.flatten(),
        alphahull=5,
        opacity=0.8,
        color='lightblue'
    ))
    
    fig.update_layout(
        title='3D Mesh: Sphere',
        scene=dict(
            xaxis_title='X',
            yaxis_title='Y',
            zaxis_title='Z'
        )
    )
    
    fig.show()

def demo_3d_volume():
    """Create volume plot"""
    print("Creating Volume Plot...")
    
    # Generate 3D data
    X, Y, Z = np.mgrid[-5:5:20j, -5:5:20j, -5:5:20j]
    values = np.sin(X*Y*Z) / (X*Y*Z + 0.1)
    
    # Create volume plot
    fig = go.Figure(data=go.Volume(
        x=X.flatten(),
        y=Y.flatten(),
        z=Z.flatten(),
        value=values.flatten(),
        isomin=0.1,
        isomax=0.8,
        opacity=0.1,
        surface_count=17,
        colorscale='RdYlBu'
    ))
    
    fig.update_layout(
        title='3D Volume Visualization',
        scene=dict(
            xaxis_title='X',
            yaxis_title='Y',
            zaxis_title='Z'
        )
    )
    
    fig.show()

def demo_3d_cone():
    """Create 3D vector field with cones"""
    print("Creating 3D Vector Field...")
    
    # Generate vector field data
    x, y, z = np.mgrid[-2:2:8j, -2:2:8j, -2:2:8j]
    u = -y
    v = x
    w = z * 0.1
    
    # Create cone plot
    fig = go.Figure(data=go.Cone(
        x=x.flatten(),
        y=y.flatten(),
        z=z.flatten(),
        u=u.flatten(),
        v=v.flatten(),
        w=w.flatten(),
        colorscale='Blues',
        sizemode="absolute",
        sizeref=0.5
    ))
    
    fig.update_layout(
        title='3D Vector Field (Cones)',
        scene=dict(
            xaxis_title='X',
            yaxis_title='Y',
            zaxis_title='Z',
            camera=dict(eye=dict(x=1.2, y=1.2, z=0.6))
        )
    )
    
    fig.show()

def demo_multiple_surfaces():
    """Create multiple surfaces in one plot"""
    print("Creating Multiple Surfaces...")
    
    # Generate data for multiple surfaces
    x = np.linspace(-3, 3, 30)
    y = np.linspace(-3, 3, 30)
    X, Y = np.meshgrid(x, y)
    
    Z1 = np.sin(X) * np.cos(Y) + 2
    Z2 = np.cos(X) * np.sin(Y)
    Z3 = -np.sin(X) * np.cos(Y) - 2
    
    fig = go.Figure()
    
    # Add first surface
    fig.add_trace(go.Surface(
        x=X, y=Y, z=Z1,
        colorscale='Reds',
        opacity=0.8,
        name='Surface 1'
    ))
    
    # Add second surface
    fig.add_trace(go.Surface(
        x=X, y=Y, z=Z2,
        colorscale='Blues',
        opacity=0.8,
        name='Surface 2'
    ))
    
    # Add third surface
    fig.add_trace(go.Surface(
        x=X, y=Y, z=Z3,
        colorscale='Greens',
        opacity=0.8,
        name='Surface 3'
    ))
    
    fig.
[truncated — 4682 more characters]
```

### sample_graphrag/chat.py

```python
import os
import base64
from openai import AzureOpenAI

from dotenv import load_dotenv
load_dotenv()

# Configuration
endpoint = os.getenv("ENDPOINT_URL", "https://2025-ai-hackberkeley.openai.azure.com/")
deployment = os.getenv("DEPLOYMENT_NAME", "o4-mini")
subscription_key = os.getenv("AZURE_OPENAI_API_KEY")

if not subscription_key:
    raise ValueError("Please set the AZURE_OPENAI_API_KEY environment variable")

# Initialize Azure OpenAI client
client = AzureOpenAI(
    azure_endpoint=endpoint,
    api_key=subscription_key,
    api_version="2025-01-01-preview",  # Use a valid API version
)

def chat_with_azure_openai(message, conversation_history=None):
    """Send a message to Azure OpenAI and get a response"""
    if conversation_history is None:
        conversation_history = []
    
    # Add system message if it's the first interaction
    if not conversation_history:
        messages = [
            {"role": "system", "content": "You are an AI assistant that helps people find information."},
            {"role": "user", "content": message}
        ]
    else:
        messages = conversation_history + [{"role": "user", "content": message}]
    
    try:
        response = client.chat.completions.create(
            model=deployment,
            messages=messages,
            max_completion_tokens=1000,  # Note: might need to use max_tokens instead of max_completion_tokens
        )
        
        return response.choices[0].message.content
    
    except Exception as e:
        print(f"Error calling Azure OpenAI: {e}")
        return None

def main():
    """Simple chat interface"""
    print("Azure OpenAI Chat Interface")
    print("Type 'quit' to exit")
    
    conversation_history = []
    
    while True:
        user_input = input("\nYou: ")
        
        if user_input.lower() == 'quit':
            break
        
        response = chat_with_azure_openai(user_input, conversation_history)
        
        if response:
            print(f"AI: {response}")
            conversation_history.extend([
                {"role": "user", "content": user_input},
                {"role": "assistant", "content": response}
            ])
        else:
            print("Sorry, there was an error processing your request.")

if __name__ == "__main__":
    main()
```

[3 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]