mirror of
https://github.com/varunshenoy/GraphGPT.git
synced 2023-05-24 23:39:42 +03:00
fix typo
This commit is contained in:
@@ -9,8 +9,12 @@ Successive queries can update the existing state of the graph or create an entir
|
||||
|
||||
The current few-shot prompt guides GPT-3 in accurately understanding the JSON formatting GraphGPT requires for proper rendering. You can see the entire prompt in `public/prompts/main.prompt`. A major issue at the moment is latency. Due to the nature of OpenAI API calls, it takes up to 20 seconds to receive a response.
|
||||
|
||||
## Prompting Magic
|
||||
|
||||
|
||||
|
||||
## Setup
|
||||
|
||||
1. Run `npm install` to download required dependencies (currently just [react-graph-vis](https://github.com/crubier/react-graph-vis)).
|
||||
2. Enter your OPENAI_API_KEY in `src/App.js`.
|
||||
2. Make sure you have an [OpenAI API key](https://openai.com/api/). You will enter this into the web app when running queries.
|
||||
3. Run `npm run start`. GraphGPT should open up in a new browser tab.
|
||||
@@ -2,12 +2,12 @@ Given the current state of a graph and a prompt, extrapolate as many relationshi
|
||||
|
||||
Examples:
|
||||
current state:
|
||||
{ "counter": 1, "graph": { "nodes": [ { "id": 1, "label": "Bob", "color": "#ffffff" } ], "edges": [] } }
|
||||
{ "nodes": [ { "id": 1, "label": "Bob", "color": "#ffffff" } ], "edges": [] }
|
||||
|
||||
prompt: Alice is Bob's roommate. Make her node green.
|
||||
|
||||
new state:
|
||||
{ "counter": 2, "graph": { "nodes": [ { "id": 1, "label": "Bob", "color": "#ffffff" }, { "id": 2, "label": "Alice", "color": "#ff7675" } ], "edges": [ { "from": 1, "to": 2, "label": "roommate" }, ] } }
|
||||
{ "nodes": [ { "id": 1, "label": "Bob", "color": "#ffffff" }, { "id": 2, "label": "Alice", "color": "#ff7675" } ], "edges": [ { "from": 1, "to": 2, "label": "roommate" } ] }
|
||||
|
||||
current state:
|
||||
$state
|
||||
190
src/App.js
190
src/App.js
@@ -11,6 +11,8 @@ const DEFAULT_PARAMS = {
|
||||
"presence_penalty": 0
|
||||
}
|
||||
|
||||
const SELECTED_PROMPT = "STATELESS"
|
||||
|
||||
const options = {
|
||||
layout: {
|
||||
hierarchical: false
|
||||
@@ -21,31 +23,157 @@ const options = {
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [state, setState] = useState(
|
||||
|
||||
const [graphState, setGraphState] = useState(
|
||||
{
|
||||
counter: 0,
|
||||
graph: {
|
||||
nodes: [],
|
||||
edges: []
|
||||
}
|
||||
})
|
||||
const { graph } = state;
|
||||
nodes: [],
|
||||
edges: []
|
||||
}
|
||||
);
|
||||
|
||||
const clearState = () => {
|
||||
setState({
|
||||
counter: 0,
|
||||
graph: {
|
||||
nodes: [],
|
||||
edges: []
|
||||
}
|
||||
setGraphState({
|
||||
nodes: [],
|
||||
edges: []
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const queryPrompt = (prompt, apiKey) => {
|
||||
fetch('prompts/main.prompt')
|
||||
const updateGraph = (updates) => {
|
||||
// updates will be provided as a list of lists
|
||||
// each list will be of the form [ENTITY1, RELATION, ENTITY2] or [ENTITY1, COLOR]
|
||||
|
||||
var current_graph = JSON.parse(JSON.stringify(graphState));
|
||||
|
||||
if (updates.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check type of first element in updates
|
||||
if (typeof updates[0] === "string") {
|
||||
// updates is a list of strings
|
||||
updates = [updates]
|
||||
}
|
||||
|
||||
updates.forEach(update => {
|
||||
if (update.length === 3) {
|
||||
// update the current graph with a new relation
|
||||
const [entity1, relation, entity2] = update;
|
||||
|
||||
// check if the nodes already exist
|
||||
var node1 = current_graph.nodes.find(node => node.id === entity1);
|
||||
var node2 = current_graph.nodes.find(node => node.id === entity2);
|
||||
|
||||
if (node1 === undefined) {
|
||||
current_graph.nodes.push({ id: entity1, label: entity1, color: "#ffffff" });
|
||||
}
|
||||
|
||||
if (node2 === undefined) {
|
||||
current_graph.nodes.push({ id: entity2, label: entity2, color: "#ffffff" });
|
||||
}
|
||||
|
||||
// check if an edge between the two nodes already exists and if so, update the label
|
||||
var edge = current_graph.edges.find(edge => edge.from === entity1 && edge.to === entity2);
|
||||
if (edge !== undefined) {
|
||||
edge.label = relation;
|
||||
return;
|
||||
}
|
||||
|
||||
current_graph.edges.push({ from: entity1, to: entity2, label: relation });
|
||||
|
||||
} else if (update.length === 2 && update[1].startsWith("#")) {
|
||||
// update the current graph with a new color
|
||||
const [entity, color] = update;
|
||||
|
||||
// check if the node already exists
|
||||
var node = current_graph.nodes.find(node => node.id === entity);
|
||||
|
||||
if (node === undefined) {
|
||||
current_graph.nodes.push({ id: entity, label: entity, color: color });
|
||||
return;
|
||||
}
|
||||
|
||||
// update the color of the node
|
||||
node.color = color;
|
||||
|
||||
} else if (update.length === 2 && update[0] == "DELETE") {
|
||||
// delete the node at the given index
|
||||
const [_, index] = update;
|
||||
|
||||
// check if the node already exists
|
||||
var node = current_graph.nodes.find(node => node.id === index);
|
||||
|
||||
console.log("HIII");
|
||||
|
||||
if (node === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the node
|
||||
current_graph.nodes = current_graph.nodes.filter(node => node.id !== index);
|
||||
|
||||
// delete all edges that contain the node
|
||||
current_graph.edges = current_graph.edges.filter(edge => edge.from !== index && edge.to !== index);
|
||||
}
|
||||
});
|
||||
setGraphState(current_graph);
|
||||
};
|
||||
|
||||
const queryStatelessPrompt = (prompt, apiKey) => {
|
||||
fetch('prompts/stateless.prompt')
|
||||
.then(response => response.text())
|
||||
.then(text => text.replace("$prompt", prompt))
|
||||
.then(text => text.replace("$state", JSON.stringify(state)))
|
||||
.then(prompt => {
|
||||
console.log(prompt)
|
||||
|
||||
const params = { ...DEFAULT_PARAMS, prompt: prompt, stop: "\n" };
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + String(apiKey)
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
};
|
||||
fetch('https://api.openai.com/v1/completions', requestOptions)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
switch (response.status) {
|
||||
case 401: // 401: Unauthorized: API key is wrong
|
||||
throw new Error('Please double-check your API key.');
|
||||
case 429: // 429: Too Many Requests: Need to pay
|
||||
throw new Error('You exceeded your current quota, please check your plan and billing details.');
|
||||
default:
|
||||
throw new Error('Something went wrong with the request, please check the Network log');
|
||||
}
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((response) => {
|
||||
const { choices } = response;
|
||||
const text = choices[0].text;
|
||||
console.log(text);
|
||||
|
||||
const updates = JSON.parse(text);
|
||||
console.log(updates);
|
||||
|
||||
updateGraph(updates);
|
||||
|
||||
document.getElementsByClassName("searchBar")[0].value = "";
|
||||
document.body.style.cursor = 'default';
|
||||
document.getElementsByClassName("generateButton")[0].disabled = false;
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
alert(error);
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
const queryStatefulPrompt = (prompt, apiKey) => {
|
||||
fetch('prompts/stateful.prompt')
|
||||
.then(response => response.text())
|
||||
.then(text => text.replace("$prompt", prompt))
|
||||
.then(text => text.replace("$state", JSON.stringify(graphState)))
|
||||
.then(prompt => {
|
||||
console.log(prompt)
|
||||
|
||||
@@ -77,21 +205,31 @@ function App() {
|
||||
const { choices } = response;
|
||||
const text = choices[0].text;
|
||||
console.log(text);
|
||||
|
||||
const new_graph = JSON.parse(text);
|
||||
console.log(new_graph);
|
||||
setState(new_graph, () => {
|
||||
console.log(state);
|
||||
});
|
||||
|
||||
setGraphState(new_graph);
|
||||
|
||||
document.getElementsByClassName("searchBar")[0].value = "";
|
||||
document.body.style.cursor = 'default';
|
||||
document.getElementsByClassName("generateButton")[0].disabled = false;
|
||||
document.getElementsByClassName("searchBar")[0].value = "";
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
alert(error);
|
||||
document.body.style.cursor = 'default';
|
||||
document.getElementsByClassName("generateButton")[0].disabled = false;
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
const queryPrompt = (prompt, apiKey) => {
|
||||
if (SELECTED_PROMPT === "STATELESS") {
|
||||
queryStatelessPrompt(prompt, apiKey);
|
||||
} else if (SELECTED_PROMPT === "STATEFUL") {
|
||||
queryStatefulPrompt(prompt, apiKey);
|
||||
} else {
|
||||
alert("Please select a prompt");
|
||||
document.body.style.cursor = 'default';
|
||||
document.getElementsByClassName("generateButton")[0].disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +257,7 @@ function App() {
|
||||
</div>
|
||||
</center>
|
||||
<div className='graphContainer'>
|
||||
<Graph graph={graph} options={options} style={{ height: "640px" }} />
|
||||
<Graph graph={graphState} options={options} style={{ height: "640px" }} />
|
||||
</div>
|
||||
<p className='footer'>Pro tip: don't take a screenshot! You can right-click and save the graph as a .png 📸</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user