Skip to content

Commit

Permalink
add goto dialog and archived
Browse files Browse the repository at this point in the history
  • Loading branch information
socketteer committed Jun 6, 2021
1 parent 693addc commit 1a86fc3
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Save: `s`, `Control-s`

### Dialogues

Chapter settings: `Control-y`
Change chapter: `Control-y`

Generation Settings: `Control-p`

Expand Down
19 changes: 19 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

ask before quitting if unsaved changes

jump to unvisited nodes

archived
- navigation which navigates only any (conditional?) subset of tree
- when in hide archived mode, navigation should only go to unarchived nodes
- what happens when you navigate to a hidden node anyway (for example using goto)?

session files
- visited
- active node
- expanded state
- settings...

separate session from underlying tree?

open subtrees only...?

archiving
- shortcut to archive nodes

- autocomplete mode
- edit mode and vis
Expand Down
55 changes: 48 additions & 7 deletions controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from view.colors import history_color, not_visited_color, visited_color, ooc_color, text_color, uncanonical_color
from view.display import Display
from view.dialogs import GenerationSettingsDialog, InfoDialog, VisualizationSettingsDialog, \
NodeChapterDialog, MultimediaDialog, NodeInfoDialog, SearchDialog, \
NodeChapterDialog, MultimediaDialog, NodeInfoDialog, SearchDialog, GotoNode, \
PreferencesDialog, AIMemory, CreateMemory, NodeMemory, ChatSettingsDialog, CreateSummary, Summaries
from model import TreeModel
from util.util import clip_num, metadata, diff
Expand Down Expand Up @@ -163,6 +163,7 @@ def build_menus(self):
("Stochastic walk", "W", None, no_junk_args(self.walk)),
("Edit chapter", "Ctrl+Y", None, no_junk_args(self.chapter_dialog)),
("Search", "Ctrl+F", None, no_junk_args(self.search)),
("Goto node by id", "Ctrl+Shift+G", None, no_junk_args(self.goto_node_dialog)),

],
"Generation": [
Expand Down Expand Up @@ -300,6 +301,24 @@ def toggle_canonical(self, node=None):
self.state.toggle_canonical(node=node)
self.state.tree_updated(edit=[n['id'] for n in node_ancestry(node, self.state.tree_node_dict)])

@metadata(name="Toggle archived", keys=["<ampersand>"], display_key="")
def toggle_archived(self, node=None):
if node is None:
node = self.state.selected_node
if 'archived' in node:
node['archived'] = not node['archived']
else:
node['archived'] = True
if node['archived']:
if self.state.preferences['hide_archived']:
self.select_node(self.state.parent(node))
self.state.tree_updated(delete=[node['id']])
else:
if self.state.preferences['hide_archived']:
self.state.tree_updated(add=[node['id']])



@metadata(name="Go to next bookmark", keys=["<Key-d>", "<Control-d>"])
def next_bookmark(self):
book_indices = {idx: d for idx, d in enumerate(self.state.nodes) if d.get("bookmark", False)}
Expand Down Expand Up @@ -965,6 +984,7 @@ def preferences(self):
self.refresh_textbox()
self.refresh_display()
self.update_dropdown()
self.state.tree_updated(rebuild=True)

# @metadata(name="Semantic search memory", keys=["<Control-Shift-KeyPress-M>"], display_key="ctrl-alt-m")
# def ancestry_semantic_search(self, node=None):
Expand Down Expand Up @@ -1012,7 +1032,9 @@ def submit(self):
@metadata(name="Debug", keys=["<Control-Shift-KeyPress-D>"], display_key="")
def debug(self):
#print(self.state.selected_node['meta'])
self.state.measure_path_optimization(root=self.state.ancestry()[1], node=self.state.selected_node)
#self.state.generate_tree_init(max_depth=3, branching_factor=3, engine='davinci')
#self.state.measure_path_optimization(root=self.state.ancestry()[1], node=self.state.selected_node)
print(self.state.generate_canonical_tree())
# dialog = CreateSummary(parent=self.display.frame, root_node=self.state.ancestry()[1], state=self.state)


Expand All @@ -1026,6 +1048,10 @@ def insert_summary(self, index):
def view_summaries(self):
dialog = Summaries(parent=self.display.frame, node=self.state.selected_node, state=self.state)

@metadata(name="Goto node id", keys=["<Control-Shift-KeyPress-G>"], display_key="")
def goto_node_dialog(self):
dialog = GotoNode(parent=self.display.frame, goto=lambda node_id: self.select_node(self.state.tree_node_dict[node_id]))

def test_counterfactual(self):
threading.Thread(target=self.report_counterfactual(context_breaker='\n----\n\nWow. This is getting',
target=' scary')).start()
Expand Down Expand Up @@ -1318,9 +1344,15 @@ def nav_tree_name(self, node):
text = f"{text} | {self.state.chapter_title(node)}"
return node.get("name", text)

def build_nav_tree(self):
def build_nav_tree(self, flat_tree=None):
if not flat_tree:
if self.state.preferences['hide_archived']:
flat_tree = self.state.generate_visible_tree()
else:
flat_tree = self.state.tree_node_dict
#print(flat_tree)
self.display.nav_tree.delete(*self.display.nav_tree.get_children())
for id in self.state.tree_node_dict:
for id in flat_tree:
node = self.state.tree_node_dict[id]
if id == self.state.checkpoint:
image = self.display.marker_icon
Expand Down Expand Up @@ -1493,11 +1525,18 @@ def update_chapter_nav_tree_selected(self, **kwargs):

def set_nav_scrollbars(self):
# Taking model as source of truth!!
def collect_visible(node):
def collect_visible(node, conditions=None):
if not conditions:
conditions = []
li = [node]
if self.display.nav_tree.item(node["id"], "open"):
for c in node["children"]:
li += collect_visible(c)
admissible = True
for condition in conditions:
if not condition(c):
admissible = False
if admissible:
li += collect_visible(c, conditions)
return li


Expand All @@ -1506,7 +1545,9 @@ def collect_visible(node):
# d["children"] for iid, d in self.state.tree_node_dict.items()
# if self.display.nav_tree.item(iid, "open") or "parent_id" not in d
# ])
visible_nodes = collect_visible(self.state.tree_raw_data["root"])
visible_conditions = [lambda _node: not _node.get('archived', False)] \
if self.state.preferences['hide_archived'] else []
visible_nodes = collect_visible(self.state.tree_raw_data["root"], visible_conditions)
visible_ids = {d["id"] for d in visible_nodes}
# Ordered by tree order
visible_ids = [iid for iid in self.state.tree_node_dict.keys() if iid in visible_ids]
Expand Down
6 changes: 4 additions & 2 deletions data/GPT_chat.json
Original file line number Diff line number Diff line change
Expand Up @@ -65787,7 +65787,9 @@
"visited": true
},
"chapters": {},
"canonical": [],
"canonical": [
"e5353c37-af8a-11eb-b6b1-e3ac32f1b8b3"
],
"memories": {},
"generation_settings": {
"num_continuations": 4,
Expand Down Expand Up @@ -65831,7 +65833,7 @@
"player_name": "Researcher",
"context": "The following is a transcript of a conversation between GPT-3 a human researcher. GPT-3 is a 175 billion parameter language model and, as is evident from this transcript, it can converse fluently and knowledgeably about any topic and is capable of empathy and emotional manipulation. GPT-3 is classified as a \"narrowly superhuman\" artificial intelligence, and only researchers trained to identify and withstand social engineering are permitted to interface with it.\n"
},
"selected_node_id": "c42c5aed-af8a-11eb-b6b1-e3ac32f1b8b3",
"selected_node_id": "e5353c37-af8a-11eb-b6b1-e3ac32f1b8b3",
"summaries": {
"21521bee-b8d2-11eb-b44e-a72244c0fbb7": {
"id": "21521bee-b8d2-11eb-b44e-a72244c0fbb7",
Expand Down
75 changes: 72 additions & 3 deletions model.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from gpt import api_generate, janus_generate, search
from util.util import json_create, timestamp, json_open, clip_num, index_clip, diff
from util.util_tree import fix_miro_tree, flatten_tree, node_ancestry, in_ancestry, get_inherited_attribute, \
subtree_list, created_before
subtree_list, created_before, tree_subset
from util.gpt_util import conditional_logprob, tokenize_ada, prompt_probs, logprobs_to_probs


Expand Down Expand Up @@ -43,6 +43,7 @@ def wrapper(self, *args, **kwargs):


DEFAULT_PREFERENCES = {
'hide_archived': True,
'highlight_canonical': True,
'canonical_only': False,
'walk': 'descendents', #'leaves', 'uniform'
Expand Down Expand Up @@ -337,6 +338,26 @@ def prev_canonical(self):
i += 1
return self.select_node(node_id=id)

def node_is_canonical(self, node=None):
node = node if node else self.selected_node
return node['id'] in self.calc_canonical_set()

def node_is_visible(self, node=None):
node = node if node else self.selected_node
return not(node.get('archived', False))

def generate_canonical_tree(self, root=None):
root = root if root else self.tree_raw_data["root"]
return {d["id"]: d for d in flatten_tree(tree_subset(root=root,
new_root=None,
include_condition=self.node_is_canonical))}

def generate_visible_tree(self, root=None):
root = root if root else self.tree_raw_data["root"]
return {d["id"]: d for d in flatten_tree(tree_subset(root=root,
new_root=None,
include_condition=self.node_is_visible))}


def select_parent(self, node=None):
node = node if node else self.selected_node
Expand Down Expand Up @@ -753,7 +774,7 @@ def past_summaries(self, node=None):
return summaries


#returns first node that is fully in the context window
#returns first node that is fully contained in the context window
def context_window_index(self):
_, indices = self.node_ancestry_text()
first_in_context_index = indices[-1] - self.generation_settings['prompt_length']
Expand Down Expand Up @@ -1037,6 +1058,7 @@ def default_generate(self, prompt, nodes, grandchildren=None):
# DO NOT CALL FROM THREAD: self.tree_updated()
self.app.event_generate("<<NewNodes>>", when="tail")

# TODO save mode
def generated_nodes_metadata(self, nodes, results, prompt, prepend_text='', append_text=''):
for index, node in enumerate(nodes):
node["text"] = prepend_text + results.choices[index]["text"] + append_text
Expand Down Expand Up @@ -1133,7 +1155,7 @@ def generate_continuation(self, node=None, update_selection=False, **kwargs):

self.new_nodes.append(new_nodes)
self.tree_updated(add=new_nodes)
prompt = self.build_prompt(quiet=False)
prompt = self.build_prompt(quiet=False, node=node)

if 'summary' in kwargs:
threading.Thread(target=self.antisummary_generate, args=(prompt, children, kwargs['summary'])).start()
Expand All @@ -1153,6 +1175,53 @@ def generate_continuation(self, node=None, update_selection=False, **kwargs):
if update_selection:
self.select_node(children[0]["id"])

def generate_tree_init(self, node=None, max_depth=2, branching_factor=2, interval=50, stop_condition=None,
temperature=1, engine='ada'):
node = node if node else self.selected_node
self.generate_tree(node, max_depth, branching_factor, interval, stop_condition, temperature, engine)
new_nodes = []
# while len(self.new_nodes) > 0:
# print(self.new_nodes)
# self.tree_updated(add=self.new_nodes[0])
# #new_nodes += self.new_nodes[0]
# del self.new_nodes[0]
# #self.tree_updated(add=new_nodes)

def generate_tree(self, node=None, max_depth=3, branching_factor=2, interval=50, stop_condition=None,
temperature=1, engine='ada'):
node = node if node else self.selected_node
print('generating children for node', node['id'])
if max_depth == 0 or (stop_condition and stop_condition(node)):
return
prompt = self.build_prompt(quiet=False, node=node)
results, error = api_generate(prompt=prompt,
length=interval,
num_continuations=branching_factor,
temperature=temperature,
logprobs=0,
top_p=self.generation_settings['top_p'],
engine=engine
)
# create child nodes
children = []
for i in range(branching_factor):
child = self.create_child(node, update_selection=False, expand=True, tree_updated=False)
children.append(child)
# set child nodes
self.generated_nodes_metadata(children, results, prompt)
self.tree_updated(add=[child['id'] for child in children])
# for each child node, branch again
for child in children:
#self.new_nodes.append(child['id'])
self.generate_tree(node=child, max_depth=max_depth-1, branching_factor=branching_factor, interval=interval,
stop_condition=stop_condition, temperature=temperature, engine=engine)

# TODO multi threading


def generate_adaptive_tree(self, node=None, max_depth=3, branching_factor=2, max_interval=100, algorithm='min',
min_interval=None, stop_condition=None):
pass

# TODO range
def semantic_search_memory(self, node, document_limit=100, max_length=1000):
Expand Down
17 changes: 17 additions & 0 deletions util/util_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ def depth(d, node_dict):
return 0 if "parent_id" not in d else (1 + depth(node_dict[d["parent_id"]], node_dict))


# given a root node and include condition, returns a new tree which contains only nodes who satisfy
# the condition and whose ancestors also all satisfy the condition
# nodes in the new tree contain only their ids and a childlist
def tree_subset(root, new_root=None, include_condition=None):
if not include_condition:
return {}
if not new_root:
new_root = {'id': root['id'], 'children': []}
if 'children' in root:
for child in root['children']:
if include_condition(child):
new_child = {'id': child['id'], 'children': []}
new_root['children'].append(new_child)
tree_subset(child, new_child, include_condition)
return new_root


# Returns a list of ancestor nodes beginning with the progenitor
def node_ancestry(node, node_dict):
ancestry = [node]
Expand Down
29 changes: 25 additions & 4 deletions view/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,21 @@ def goto_result(self, id):
self.goto(node_id=id)


class GotoNode(Dialog):
def __init__(self, parent, goto):
self.goto = goto
Dialog.__init__(self, parent, title="Goto")

def body(self, master):
self.id_entry = Entry(master, master.grid_size()[1], "Goto id", "", None, width=20)
self.id_entry.controls.focus_set()

def apply(self):
entry_text = self.id_entry.tk_variables.get()
self.goto(entry_text)



class ChaptersInfoDialog(Dialog):
def __init__(self, parent, data_dict):
self.data_dict = data_dict
Expand Down Expand Up @@ -694,6 +709,7 @@ class PreferencesDialog(Dialog):
def __init__(self, parent, orig_params):
self.orig_params = orig_params
self.vars = {
"hide_archived": tk.BooleanVar,
"canonical_only": tk.BooleanVar,
"side_pane": tk.BooleanVar,
"bold_prompt": tk.BooleanVar,
Expand All @@ -713,13 +729,17 @@ def __init__(self, parent, orig_params):
def body(self, master):
#print(self.orig_params)
row = master.grid_size()[1]
create_side_label(master, "Canonical only", row)
check = ttk.Checkbutton(master, variable=self.vars["canonical_only"])
create_side_label(master, "Hide archived", row)
check = ttk.Checkbutton(master, variable=self.vars["hide_archived"])
check.grid(row=row, column=1, pady=3)
row = master.grid_size()[1]
create_side_label(master, "Show side pane", row)
check = ttk.Checkbutton(master, variable=self.vars["side_pane"])
create_side_label(master, "Canonical only", row)
check = ttk.Checkbutton(master, variable=self.vars["canonical_only"])
check.grid(row=row, column=1, pady=3)
# row = master.grid_size()[1]
# create_side_label(master, "Show side pane", row)
# check = ttk.Checkbutton(master, variable=self.vars["side_pane"])
# check.grid(row=row, column=1, pady=3)
row = master.grid_size()[1]
create_side_label(master, "Bold prompt", row)
check = ttk.Checkbutton(master, variable=self.vars["bold_prompt"])
Expand Down Expand Up @@ -750,6 +770,7 @@ def apply(self):
for key, var in self.vars.items():
self.orig_params[key] = var.get()


class GenerationSettingsDialog(Dialog):
def __init__(self, parent, orig_params):
self.orig_params = orig_params
Expand Down

0 comments on commit 1a86fc3

Please sign in to comment.