|
import streamlit as st |
|
import pandas as pd |
|
import networkx as nx |
|
from bokeh.models import HoverTool |
|
from bokeh.plotting import figure, from_networkx |
|
import requests |
|
import json |
|
import google.generativeai as genai |
|
|
|
PERPLEXITY_API_KEY = "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" |
|
PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions" |
|
|
|
|
|
def extract_edges(keywords): |
|
keywords = [kw.strip() for kw in keywords.split(",")] |
|
edges = [ |
|
(keywords[i], keywords[j]) |
|
for i in range(len(keywords)) |
|
for j in range(i + 1, len(keywords)) |
|
] |
|
return edges |
|
|
|
|
|
def create_knowledge_graph(data): |
|
G = nx.Graph() |
|
|
|
for _, row in data.iterrows(): |
|
words = [] |
|
for col in data.columns: |
|
if pd.notnull(row[col]): |
|
|
|
cell_value = str(row[col]).strip() |
|
if cell_value: |
|
words.extend(cell_value.split()) |
|
|
|
if words: |
|
edges = extract_edges(",".join(words)) |
|
G.add_edges_from(edges) |
|
|
|
for word in words: |
|
word = word.strip() |
|
if word not in G: |
|
G.add_node(word, title=word, value=len(word)) |
|
|
|
return G |
|
|
|
|
|
def render_graph_bokeh(G): |
|
plot = figure( |
|
title="Interactive Knowledge Graph", |
|
x_range=(-1.5, 1.5), |
|
y_range=(-1.5, 1.5), |
|
tools="pan,wheel_zoom,box_zoom,reset,tap", |
|
active_scroll="wheel_zoom", |
|
) |
|
plot.add_tools(HoverTool(tooltips="@index")) |
|
|
|
graph_renderer = from_networkx(G, nx.spring_layout, scale=1, center=(0, 0)) |
|
|
|
graph_renderer.node_renderer.glyph.size = 10 |
|
graph_renderer.node_renderer.glyph.fill_color = "blue" |
|
graph_renderer.node_renderer.glyph.line_color = "black" |
|
|
|
graph_renderer.edge_renderer.glyph.line_width = 1 |
|
graph_renderer.edge_renderer.glyph.line_color = "gray" |
|
|
|
plot.renderers.append(graph_renderer) |
|
|
|
return plot |
|
|
|
|
|
import re |
|
|
|
|
|
def search_papers(topic: str, num_papers: int) -> list: |
|
headers = { |
|
"Authorization": f"Bearer {PERPLEXITY_API_KEY}", |
|
"Content-Type": "application/json", |
|
} |
|
|
|
prompt = f"""Find {num_papers} recent research papers about {topic}. |
|
Return ONLY a valid JSON array with the following structure for each paper: |
|
[ |
|
{{ |
|
"Title": "paper title", |
|
"Abstract": "abstract text", |
|
"Keywords": "key terms" |
|
}} |
|
]""" |
|
|
|
payload = { |
|
"model": "llama-3.1-sonar-small-128k-chat", |
|
"messages": [ |
|
{ |
|
"role": "system", |
|
"content": "You are a research paper analyzer that returns valid JSON arrays.", |
|
}, |
|
{"role": "user", "content": prompt}, |
|
], |
|
"temperature": 0.1, |
|
} |
|
|
|
try: |
|
response = requests.post(PERPLEXITY_API_URL, headers=headers, json=payload) |
|
response.raise_for_status() |
|
content = response.json()["choices"][0]["message"]["content"] |
|
|
|
|
|
content = content.strip() |
|
if not content.startswith("["): |
|
content = content[content.find("[") :] |
|
if not content.endswith("]"): |
|
content = content[: content.rfind("]") + 1] |
|
|
|
|
|
content = re.sub(r",\s*]", "]", content) |
|
content = re.sub(r",\s*}", "}", content) |
|
|
|
papers = json.loads(content) |
|
if not isinstance(papers, list): |
|
raise ValueError("Response is not a JSON array") |
|
return papers |
|
except requests.exceptions.RequestException as e: |
|
st.error(f"API Request Error: {str(e)}") |
|
return [] |
|
except json.JSONDecodeError as e: |
|
st.error(f"Invalid JSON response: {str(e)}") |
|
st.error(f"Response content: {response.text}") |
|
return [] |
|
except ValueError as e: |
|
st.error(f"Error: {str(e)}") |
|
return [] |
|
|
|
|
|
import os |
|
|
|
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") |
|
GEMINI_API_URL = "https://api.openai.com/v1/engines/davinci-codex/completions" |
|
|
|
|
|
def call_gemini_api(prompt: str) -> str: |
|
headers = { |
|
"Authorization": f"Bearer {GEMINI_API_KEY}", |
|
"Content-Type": "application/json", |
|
} |
|
|
|
payload = { |
|
"prompt": prompt, |
|
"max_tokens": 150, |
|
"temperature": 0.7, |
|
} |
|
|
|
try: |
|
model = genai.GenerativeModel("gemini-pro") |
|
response = model.generate_content(prompt) |
|
return response.text |
|
except Exception as e: |
|
st.error(f"Gemini API Error: {str(e)}") |
|
return "" |
|
|
|
|
|
def generate_gaps_paragraph(gaps): |
|
prompt = f"Generate a brief paragraph about the gaps in the research based on the following gaps: {', '.join(gaps)}" |
|
return call_gemini_api(prompt) |
|
|
|
|
|
def generate_insights(G, topic): |
|
papers = search_papers(topic, 5) |
|
if papers: |
|
st.write("### Research Insights from Perplexity API") |
|
for paper in papers: |
|
st.write(f"**Title:** {paper['Title']}") |
|
st.write(f"**Abstract:** {paper['Abstract']}") |
|
st.write(f"**Keywords:** {paper['Keywords']}") |
|
st.write("---") |
|
|
|
nodes = list(G.nodes(data=True)) |
|
insights = {} |
|
insights["Strong Points"] = [ |
|
n for n, d in nodes if G.degree(n) > len(G.nodes) * 0.1 |
|
] |
|
insights["Weak Points"] = [n for n, d in nodes if G.degree(n) < len(G.nodes) * 0.05] |
|
insights["Gaps"] = [n for n, d in nodes if len(list(nx.neighbors(G, n))) == 0] |
|
|
|
st.write("### Graph-Based Insights") |
|
st.write("**Strong Points:**", insights["Strong Points"]) |
|
st.write("**Weak Points:**", insights["Weak Points"]) |
|
st.write("**Gaps:**", insights["Gaps"]) |
|
|
|
if insights["Gaps"]: |
|
with st.spinner("Generating insights about gaps..."): |
|
gaps_paragraph = generate_gaps_paragraph(insights["Gaps"]) |
|
if gaps_paragraph: |
|
st.write("### Gaps in Research") |
|
st.write(gaps_paragraph) |
|
|
|
|
|
def main(): |
|
st.title("Advanced Interactive Knowledge Graph") |
|
st.write( |
|
"Upload a CSV file to generate a fully interactive and insightful knowledge graph." |
|
) |
|
|
|
uploaded_file = st.file_uploader("Choose a CSV file", type="csv") |
|
|
|
if uploaded_file is not None: |
|
try: |
|
data = pd.read_csv(uploaded_file) |
|
st.write("Preview of the uploaded data:") |
|
st.dataframe(data.head()) |
|
|
|
G = create_knowledge_graph(data) |
|
|
|
st.write("Generated Knowledge Graph:") |
|
plot = render_graph_bokeh(G) |
|
st.bokeh_chart(plot, use_container_width=True) |
|
|
|
topic = st.text_input( |
|
"Enter a topic for additional insights:", "knowledge graphs" |
|
) |
|
if topic: |
|
generate_insights(G, topic) |
|
|
|
except Exception as e: |
|
st.error(f"An error occurred while processing the file: {e}") |
|
else: |
|
st.info("Please upload a CSV file to get started.") |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|