From 89dd7c1f28d665646090fa3880b2e6d417d704275e7d9cb25930ce6851a646b4 Mon Sep 17 00:00:00 2001 From: Moses Rolston Date: Wed, 12 Mar 2025 16:19:16 -0700 Subject: [PATCH] these either --- api/endpoints/person_routes.py | 32 ++++++++++ api/endpoints/show_cache.py | 26 ++++++++ api/templates/graph.html | 29 +++++++++ api/templates/show_cache.html | 33 ++++++++++ render.py | 65 ++++++++++++++++++++ templates/index.html | 109 +++++++++++++++++++++++++++++++++ 6 files changed, 294 insertions(+) create mode 100644 api/endpoints/person_routes.py create mode 100644 api/endpoints/show_cache.py create mode 100644 api/templates/graph.html create mode 100644 api/templates/show_cache.html create mode 100644 render.py create mode 100644 templates/index.html diff --git a/api/endpoints/person_routes.py b/api/endpoints/person_routes.py new file mode 100644 index 0000000..10dd7a0 --- /dev/null +++ b/api/endpoints/person_routes.py @@ -0,0 +1,32 @@ +from flask import Blueprint, render_template, request +import json + +bp = Blueprint('person', __name__) + +# Load person data from JSON file +with open('../person_data.json') as f: + person_data = json.load(f) + +@bp.route('/', methods=['GET', 'POST']) +def index(): + persons = get_persons() + relationships = ['SPONSORED', 'COSPONSORED'] + + if request.method == 'POST': + relationship_type = request.form.get('relationship_type') + + # Fetch related nodes based on selected relationship + with driver.session() as session: + if relationship_type == 'SPONSORED': + result = session.run("MATCH (p:Person)-[:SPONSORED]->(l:Legislation) RETURN p.name AS person") + elif relationship_type == 'COSPONSORED': + result = session.run("MATCH (p:Person)-[:COSPONSORED]->(l:Legislation) RETURN p.name AS person") + else: + # Fetch all unique persons + result_persons = session.run("MATCH (p:Person) RETURN DISTINCT p.name AS name") + persons = [record['name'] for record in result_persons] + + if relationship_type: + persons = list(set(record['person'] for record in result)) + + return render_template('graph.html', persons=persons, relationships=relationships) diff --git a/api/endpoints/show_cache.py b/api/endpoints/show_cache.py new file mode 100644 index 0000000..3f61876 --- /dev/null +++ b/api/endpoints/show_cache.py @@ -0,0 +1,26 @@ +from flask import Blueprint, render_template +import json +from cachetools import cached, TTLCache + +# Create a Blueprint instance +cache_bp = Blueprint('cache', __name__, template_folder='templates') + +# Configure cache with a time-to-live (TTL) of 3600 seconds (1 hour) +cache = TTLCache(maxsize=100, ttl=3600) + +def load_cache(): + """Load cache from cache.json""" + try: + with open('cache.json', 'r') as file: + data = json.load(file) + for key, value in data.items(): + cache[key] = value + except FileNotFoundError: + print("cache.json not found") + +@cache_bp.route('/show_cache') +@cached(cache) +def index(): + """Render the HTML page with cached items""" + load_cache() + return render_template('show_cache.html', bioguideId=cache.get('bioguideId', {}), legislation=cache.get('legislation', {})) diff --git a/api/templates/graph.html b/api/templates/graph.html new file mode 100644 index 0000000..94451dc --- /dev/null +++ b/api/templates/graph.html @@ -0,0 +1,29 @@ + + + + + Dropdown Example + + +

Select a Relationship and Person

+
+ + + + + + + +
+ + diff --git a/api/templates/show_cache.html b/api/templates/show_cache.html new file mode 100644 index 0000000..5a018cf --- /dev/null +++ b/api/templates/show_cache.html @@ -0,0 +1,33 @@ + + + + + Cache Items + + + +

Cached Items

+ + {% macro render_nested_dict(d) -%} + + {%- endmacro %} + +

Bioguide ID Cache

+ {{- render_nested_dict(bioguideId) -}} + +

Legislation Cache

+ {{- render_nested_dict(legislation) -}} + + diff --git a/render.py b/render.py new file mode 100644 index 0000000..fa2c027 --- /dev/null +++ b/render.py @@ -0,0 +1,65 @@ +from flask import Flask, render_template_string +from neo4j import GraphDatabase +from pyvis.network import Network +import os +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() + +app = Flask(__name__) + +# Configure your Neo4j connection using environment variables +uri = os.getenv("NEO4J_URI") +user = os.getenv("NEO4J_USER") +password = os.getenv("NEO4J_PASSWORD") + +driver = GraphDatabase.driver(uri, auth=(user, password)) + +def fetch_data(): + with driver.session() as session: + result = session.run("MATCH (n:Person)-[r]->(m:Legislation) RETURN n.name AS node1, type(r) AS relationship, m.number AS node2") + nodes = [] + edges = [] + + for record in result: + node1 = record["node1"] + node2 = record["node2"] + + # Debugging: Check the types of node IDs + print(f"Node 1 Type: {type(node1)}, Value: {node1}") + print(f"Node 2 Type: {type(node2)}, Value: {node2}") + + assert isinstance(node1, (str, int)), f"Unexpected type for node ID: {type(node1)}" + assert isinstance(node2, (str, int)), f"Unexpected type for node ID: {type(node2)}" + + nodes.append(node1) + nodes.append(node2) + edges.append((node1, node2, {"title": record["relationship"]})) + + return list(set(nodes)), edges + +@app.route('/') +def index(): + try: + nodes, edges = fetch_data() + + # Create a Network object + net = Network(notebook=False, height='600px', width='100%', directed=True) + + # Add nodes and edges to the graph + for node in nodes: + net.add_node(node) + + for edge in edges: + net.add_edge(edge[0], edge[1], title=edge[2]['title']) + + # Generate HTML for embedding in Flask app + html = net.generate_html("3d-force-directed-graph.html") + return render_template_string(html) + except AssertionError as e: + return f"Assertion Error: {e}", 500 + +if __name__ == '__main__': + port = os.getenv("FLASK_PORT", 5000) # Default to 5000 if not specified in .env + app.run(debug=True, port=port) diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..79ff864 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,109 @@ + + + + + 3D Force-Directed Graph + + + + +
+ + + +