|
import gradio as gr
|
|
import modules.shared as shared
|
|
from pathlib import Path
|
|
import re
|
|
import json
|
|
from functools import partial
|
|
from modules.text_generation import stop_everything_event
|
|
from modules import chat
|
|
from modules import ui as main_ui
|
|
from modules.utils import gradio
|
|
from modules.extensions import apply_extensions
|
|
import random
|
|
|
|
right_symbol = '\U000027A1'
|
|
left_symbol = '\U00002B05'
|
|
refresh_symbol = '\U0001f504'
|
|
|
|
def atoi(text):
|
|
return int(text) if text.isdigit() else text.lower()
|
|
|
|
def natural_keys(text):
|
|
return [atoi(c) for c in re.split(r'(\d+)', text)]
|
|
|
|
def get_file_path(filename):
|
|
return "extensions/StoryCrafter/"+filename
|
|
|
|
last_save = get_file_path("last.json")
|
|
save_proj_path = get_file_path("Projects")
|
|
save_proj_path_txt = get_file_path("Text")
|
|
state_save = get_file_path("state.json")
|
|
|
|
params = {
|
|
"display_name": "StoryCrafter",
|
|
"is_tab": True,
|
|
"selectA": [0,0],
|
|
'projectname':"temp_project",
|
|
'auto_clear': True,
|
|
'include_history': True,
|
|
'include_history_nr':5,
|
|
'lorebook':'',
|
|
'system':'You are experienced fiction writer. Develop the plot slowly. Describe all actions in full, elaborate and vivid detail.',
|
|
'world':''
|
|
|
|
}
|
|
|
|
|
|
|
|
help_str = """
|
|
**Help**
|
|
|
|
This is for writing and generating stories beat by beat (short passages of scenes, paragraphs). At each generation all the previously written/edited beats will be dynamically inserted into LLM as a memory. You can edit the beats any time you wish as both final text and the text LLM see is dynamically generated from the beats each time.
|
|
|
|
Versions
|
|
|
|
Each beat can also have multiple versions and you can then choose which version to include in the final text.
|
|
|
|
Cross variation to prompt. In the Instruct mode you can specify [V1], [V2] or [V3] in the prompt and it will insert the text from that version. This way you can instruct to rewrite the text without copying the text to prompt.
|
|
For example: Rewrite the following text using first person POV [V1] or Summarrize the following text: [V2]
|
|
|
|
Future Cues
|
|
|
|
Each beat can also have Future Cues - unlike Prompt, which are directions for the currently generated text, Future Cues are for the text that will be generated after the current one, down the page. Here you can specify changes and twists that are valid AFTER this test.
|
|
For example if in this block of text the character is changing their hairstyle, in the Future Cues you might specify: from this point refer to Anna as having short pink hair
|
|
"""
|
|
|
|
|
|
|
|
|
|
selected_item = "Beat 1"
|
|
selected_item_title = "Beat 1"
|
|
selected_item_prompt = "Write a paragraph where ..."
|
|
selected_item_scenetext = ""
|
|
selected_scene_version = "v1"
|
|
selected_item_notes = ""
|
|
full_text_until = ""
|
|
full_text = ""
|
|
|
|
|
|
dynamic_lore = []
|
|
dynamic_lore_changed = False
|
|
|
|
data_structure = [{"outline": selected_item, "outline_title": selected_item_title, "prompt": selected_item_prompt, "scenetext_v1": selected_item_scenetext,"scenetext_v2": "","scenetext_v3": "", "version": selected_scene_version,"notes":selected_item_notes, "is_summary": False}]
|
|
|
|
def does_outline_exist(outline_name):
|
|
global data_structure
|
|
return any(item["outline"] == outline_name for item in data_structure)
|
|
|
|
def get_first_outline_name():
|
|
global data_structure
|
|
if data_structure:
|
|
return data_structure[0]["outline"]
|
|
else:
|
|
return ""
|
|
|
|
def get_first_outline_name_title(default_title):
|
|
global data_structure
|
|
if data_structure and len(data_structure) > 0:
|
|
return data_structure[0].get("outline_title", default_title)
|
|
else:
|
|
return default_title
|
|
|
|
|
|
def get_data_by_outline(outline_title):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
key = "scenetext_"+item["version"]
|
|
return item["prompt"], item[key], item["version"], item["notes"]
|
|
return None, None
|
|
|
|
def get_title_by_outline(outline_title):
|
|
global data_structure
|
|
def_out = outline_title
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
return item.get("outline_title", def_out)
|
|
return None, None
|
|
|
|
|
|
|
|
def delete_item_by_outline(outline_title):
|
|
global data_structure
|
|
global selected_item
|
|
next_selected_item = ""
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
data_structure.remove(item)
|
|
selected_item = next_selected_item
|
|
if selected_item=="" and len(data_structure)>0:
|
|
selected_item = data_structure[0]["outline"]
|
|
|
|
return True
|
|
next_selected_item = item["outline"]
|
|
return False
|
|
|
|
def generate_unique_outline_name_old(scene_string):
|
|
global data_structure
|
|
|
|
counter = 1
|
|
while True:
|
|
outline_title = f"{scene_string} {counter}"
|
|
|
|
if not any(item["outline"] == outline_title for item in data_structure):
|
|
return outline_title
|
|
counter += 1
|
|
|
|
|
|
def generate_unique_outline_name(base_name):
|
|
global data_structure
|
|
|
|
|
|
max_number = 0
|
|
|
|
|
|
for item in data_structure:
|
|
try:
|
|
|
|
number = int(item["outline"].split()[-1])
|
|
max_number = max(max_number, number)
|
|
except ValueError:
|
|
|
|
continue
|
|
|
|
|
|
new_outline_name = f"{base_name} {max_number + 1}"
|
|
return new_outline_name
|
|
|
|
def add_item(outline_title, prompt_string, scene_string):
|
|
global data_structure
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
outline_name2 = outline_title
|
|
|
|
|
|
new_item = {"outline": outline_title, "outline_title": outline_name2, "prompt": prompt_string, "scenetext_v1": scene_string,"scenetext_v2": "","scenetext_v3": "", "version": "v1", "notes": "", "is_summary": False}
|
|
|
|
selected_item = outline_title
|
|
selected_item_title = outline_name2
|
|
selected_item_prompt = prompt_string
|
|
selected_item_scenetext = scene_string
|
|
selected_scene_version = new_item["version"]
|
|
selected_item_notes = ""
|
|
|
|
data_structure.append(new_item)
|
|
|
|
|
|
def add_item_auto(scene_prefix, prompt_string, scene_text):
|
|
global data_structure
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
|
|
if len(data_structure)>0:
|
|
|
|
last_item = data_structure[-1]
|
|
|
|
|
|
if last_item["prompt"] == '' and last_item["scenetext_v1"] == '':
|
|
|
|
last_item["prompt"] = prompt_string
|
|
last_item["scenetext_v1"] = scene_text
|
|
last_item["scenetext_v2"] = ""
|
|
last_item["scenetext_v3"] = ""
|
|
last_item["is_summary"] = False
|
|
last_item["version"] = "v1"
|
|
last_item["notes"] = ""
|
|
|
|
|
|
selected_item = last_item["outline"]
|
|
selected_item_title = last_item["outline_title"]
|
|
selected_item_prompt = last_item["prompt"]
|
|
selected_item_scenetext = last_item["scenetext_v1"]
|
|
selected_scene_version = last_item["version"]
|
|
selected_item_notes = last_item["notes"]
|
|
|
|
data_structure[-1] = last_item
|
|
return
|
|
|
|
|
|
outline_title = generate_unique_outline_name(scene_prefix)
|
|
outline_name2 = outline_title
|
|
|
|
new_item = {"outline": outline_title, "outline_title": outline_name2, "prompt": prompt_string, "scenetext_v1": scene_text,"scenetext_v2": "","scenetext_v3": "", "version": "v1", "notes":"", "is_summary": False}
|
|
|
|
selected_item = outline_title
|
|
selected_item_title = outline_name2
|
|
selected_item_prompt = prompt_string
|
|
selected_item_scenetext = scene_text
|
|
selected_scene_version = new_item["version"]
|
|
selected_item_notes = ""
|
|
|
|
|
|
data_structure.append(new_item)
|
|
|
|
|
|
def set_version_by_outline(outline_title, scene_version):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
item["version"] = scene_version
|
|
return True
|
|
return False
|
|
|
|
def update_item_by_outline(outline_title, scene_version, new_prompt, new_scene_text):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
item["prompt"] = new_prompt
|
|
item["version"] = scene_version
|
|
key = "scenetext_"+item["version"]
|
|
item[key] = new_scene_text
|
|
return True
|
|
return False
|
|
|
|
def update_item_title_by_outline(outline_name, new_outline_title):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_name:
|
|
item["outline_title"] = new_outline_title
|
|
return True
|
|
return False
|
|
|
|
def update_prompt_by_outline(outline_title, new_prompt):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
item["prompt"] = new_prompt
|
|
return True
|
|
return False
|
|
|
|
def update_scenetext_by_outline(outline_title, new_scene_text):
|
|
global data_structure
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
key = "scenetext_"+item["version"]
|
|
item[key] = new_scene_text
|
|
return True
|
|
return False
|
|
|
|
def update_notes_by_outline(outline_title, new_notes_text):
|
|
global data_structure
|
|
for item in data_structure:
|
|
item['notes'] = new_notes_text
|
|
return True
|
|
return False
|
|
|
|
|
|
def generate_combined_text():
|
|
global data_structure
|
|
global full_text
|
|
full_text = ""
|
|
for item in data_structure:
|
|
key = "scenetext_"+item["version"]
|
|
full_text += item[key]+'\n\n'
|
|
|
|
|
|
full_text = full_text.strip()
|
|
return full_text
|
|
|
|
|
|
def generate_combined_text_until_current_with_history(max_last):
|
|
global data_structure
|
|
global selected_item
|
|
outline_title = selected_item
|
|
count_before_outline = 0
|
|
temp_hist = []
|
|
|
|
if max_last > 0:
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
break
|
|
|
|
|
|
if count_before_outline < max_last:
|
|
key = "scenetext_"+item["version"]
|
|
temp_hist.append(item[key])
|
|
else:
|
|
|
|
temp_hist.pop(0)
|
|
key = "scenetext_"+item["version"]
|
|
temp_hist.append(item[key])
|
|
|
|
if item["notes"]!='':
|
|
note_txt = "Note: "+item["notes"]
|
|
temp_hist.append(note_txt)
|
|
|
|
count_before_outline += 1
|
|
|
|
|
|
combined_text = ""
|
|
for item_txt in temp_hist:
|
|
combined_text += item_txt + '\n\n'
|
|
text_until = combined_text.rstrip('\n\n')
|
|
|
|
return text_until
|
|
|
|
|
|
def generate_combined_text_until_current():
|
|
global data_structure
|
|
global selected_item
|
|
global full_text_until
|
|
combined_text = ""
|
|
outline_title = selected_item
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
break
|
|
key = "scenetext_"+item["version"]
|
|
combined_text += item[key] + '\n\n'
|
|
full_text_until = combined_text.rstrip('\n\n')
|
|
|
|
if full_text_until =='':
|
|
full_text_until = '[Beginning]'
|
|
return full_text_until
|
|
|
|
|
|
def move_item_up(outline_title):
|
|
global data_structure
|
|
for i in range(len(data_structure)):
|
|
if data_structure[i]["outline"] == outline_title and i > 0:
|
|
|
|
data_structure[i], data_structure[i - 1] = data_structure[i - 1], data_structure[i]
|
|
return True
|
|
return False
|
|
|
|
def move_item_down(outline_title):
|
|
global data_structure
|
|
for i in range(len(data_structure) - 1):
|
|
if data_structure[i]["outline"] == outline_title and i < len(data_structure) - 1:
|
|
|
|
data_structure[i], data_structure[i + 1] = data_structure[i + 1], data_structure[i]
|
|
return True
|
|
return False
|
|
|
|
|
|
class ToolButton(gr.Button, gr.components.FormComponent):
|
|
"""Small button with single emoji as text, fits inside gradio forms"""
|
|
|
|
def __init__(self, **kwargs):
|
|
super().__init__(variant="tool", **kwargs)
|
|
|
|
def get_block_name(self):
|
|
return "button"
|
|
|
|
|
|
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_class):
|
|
def refresh():
|
|
refresh_method()
|
|
args = refreshed_args() if callable(refreshed_args) else refreshed_args
|
|
|
|
for k, v in args.items():
|
|
setattr(refresh_component, k, v)
|
|
|
|
return gr.update(**(args or {}))
|
|
|
|
refresh_button = ToolButton(value=refresh_symbol, elem_classes=elem_class)
|
|
refresh_button.click(
|
|
fn=refresh,
|
|
inputs=[],
|
|
outputs=[refresh_component]
|
|
)
|
|
return refresh_button
|
|
|
|
|
|
def read_file_to_string(file_path):
|
|
data = ''
|
|
try:
|
|
with open(file_path, 'r') as file:
|
|
data = file.read()
|
|
except FileNotFoundError:
|
|
data = ''
|
|
|
|
return data
|
|
|
|
|
|
|
|
def parse_dynamic_lore(lore_string):
|
|
memories = []
|
|
entries = lore_string.strip().split('\n\n')
|
|
|
|
print("Parsing lore")
|
|
|
|
for entry in entries:
|
|
lines = entry.strip().split('\n')
|
|
if len(lines) < 2:
|
|
continue
|
|
|
|
keywords_part = lines[0].strip()
|
|
memory_text = '\n'.join(lines[1:]).strip()
|
|
|
|
|
|
keywords = [kw.replace(':', '').strip().lower() for kw in keywords_part.split(',')]
|
|
|
|
|
|
memories.append({
|
|
'keywords': ','.join(keywords),
|
|
'memory': memory_text
|
|
})
|
|
|
|
return memories
|
|
|
|
|
|
def atoi(text):
|
|
return int(text) if text.isdigit() else text.lower()
|
|
|
|
def save_string_to_file(file_path, string):
|
|
try:
|
|
with open(file_path, 'w') as file:
|
|
file.write(string)
|
|
print("String saved to file successfully.")
|
|
except Exception as e:
|
|
print("Error occurred while saving string to file:", str(e))
|
|
|
|
|
|
def save_to_json(path_to_file):
|
|
global data_structure
|
|
try:
|
|
with open(Path(path_to_file), 'w') as json_file:
|
|
json.dump(data_structure, json_file, indent=2)
|
|
return True
|
|
except:
|
|
print(f"Saving to {path_to_file} failed")
|
|
return False
|
|
|
|
def load_from_json(path_to_file):
|
|
global data_structure
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
global full_text_until
|
|
global full_text
|
|
|
|
print(f"Loading project: {path_to_file}")
|
|
try:
|
|
with open(Path(path_to_file), 'r') as json_file:
|
|
data_structure.clear()
|
|
data_structure.extend(json.load(json_file))
|
|
|
|
|
|
default_values = {
|
|
"outline": "Beat 1",
|
|
"outline_title": "Untitled",
|
|
"prompt": "",
|
|
"scenetext_v1": "",
|
|
"scenetext_v2": "",
|
|
"scenetext_v3": "",
|
|
"version":"v1",
|
|
"notes": "",
|
|
"is_summary": False
|
|
}
|
|
for entry in data_structure:
|
|
for key, default in default_values.items():
|
|
if key not in entry:
|
|
entry[key] = default
|
|
|
|
|
|
|
|
generate_combined_text()
|
|
selected_item = get_first_outline_name()
|
|
selected_item_title = get_first_outline_name_title(selected_item)
|
|
generate_combined_text_until_current()
|
|
selected_item_prompt,selected_item_scenetext, selected_scene_version, selected_item_notes = get_data_by_outline(selected_item)
|
|
|
|
|
|
return True
|
|
except (FileNotFoundError, json.JSONDecodeError):
|
|
return False
|
|
|
|
def save_state():
|
|
global params
|
|
global state_save
|
|
|
|
try:
|
|
with open(Path(state_save), 'w') as json_file:
|
|
json.dump(params, json_file, indent=4)
|
|
except:
|
|
print("Can't save last state..")
|
|
|
|
def load_state():
|
|
global params
|
|
global state_save
|
|
global dynamic_lore_changed
|
|
|
|
try:
|
|
with open(Path(state_save), 'r') as json_file:
|
|
new_params = json.load(json_file)
|
|
dynamic_lore_changed = True
|
|
for item in new_params:
|
|
params[item] = new_params[item]
|
|
except:
|
|
pass
|
|
|
|
|
|
def save_proj_state(path_to_file):
|
|
global params
|
|
|
|
try:
|
|
with open(Path(path_to_file), 'w') as json_file:
|
|
json.dump(params, json_file, indent=4)
|
|
except:
|
|
print("Can't save last state..")
|
|
|
|
def load_proj_state(path_to_file):
|
|
global params
|
|
global dynamic_lore_changed
|
|
try:
|
|
with open(Path(path_to_file), 'r') as json_file:
|
|
new_params = json.load(json_file)
|
|
dynamic_lore_changed = True
|
|
for item in new_params:
|
|
params[item] = new_params[item]
|
|
except:
|
|
pass
|
|
|
|
|
|
|
|
last_history_visible = []
|
|
last_history_internal = []
|
|
last_undo = ""
|
|
|
|
|
|
|
|
def get_scene_list():
|
|
global data_structure
|
|
return [item["outline"] for item in data_structure]
|
|
|
|
|
|
|
|
|
|
def replace_placeholder(text, placeholder, replacement):
|
|
return text.replace(placeholder, replacement)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_reply_wrapperMY(text_prompt, existing_text_in_output, state, _continue=False):
|
|
|
|
global params
|
|
global last_history_visible
|
|
global last_history_internal
|
|
global last_undo
|
|
global last_save
|
|
global selected_item
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global full_text_until
|
|
global full_text
|
|
global data_structure
|
|
global dynamic_lore_changed
|
|
global dynamic_lore
|
|
|
|
selF = params['selectA'][0]
|
|
selT = params['selectA'][1]
|
|
|
|
params['selectA'] = [0,0]
|
|
|
|
new_version = True
|
|
if 'turn_template' in state:
|
|
new_version = False
|
|
|
|
visible_text = None
|
|
|
|
if "[V1]" in text_prompt or "[V2]" in text_prompt or "[V3]" in text_prompt:
|
|
for item in data_structure:
|
|
if item["outline"] == selected_item:
|
|
if "[V1]" in text_prompt:
|
|
text_prompt = replace_placeholder(text_prompt, "[V1]", item['scenetext_v1'])
|
|
if "[V2]" in text_prompt:
|
|
text_prompt = replace_placeholder(text_prompt, "[V2]", item['scenetext_v2'])
|
|
if "[V3]" in text_prompt:
|
|
text_prompt = replace_placeholder(text_prompt, "[V3]", item['scenetext_v3'])
|
|
break
|
|
|
|
|
|
|
|
user_prompt = text_prompt
|
|
|
|
text_to_keep = ""
|
|
|
|
if params['lorebook']!='' and not dynamic_lore:
|
|
dynamic_lore_changed=True
|
|
|
|
if dynamic_lore_changed==True:
|
|
dynamic_lore = parse_dynamic_lore(params['lorebook'])
|
|
dynamic_lore_changed = False
|
|
|
|
generate_combined_text()
|
|
|
|
if new_version:
|
|
if state['instruction_template_str']=='':
|
|
print("Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction Template]")
|
|
text_to_keep = existing_text_in_output + "\n Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction template]"
|
|
yield text_to_keep, full_text
|
|
return
|
|
else:
|
|
if state['turn_template']=='':
|
|
print("Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction Template]")
|
|
text_to_keep = existing_text_in_output + "\n Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction template]"
|
|
yield text_to_keep, full_text
|
|
return
|
|
|
|
|
|
|
|
state['mode'] = 'instruct'
|
|
|
|
_iswriting = "..."
|
|
|
|
|
|
|
|
if new_version:
|
|
context_instruct = state['custom_system_message']
|
|
contest_instruct_bk = context_instruct
|
|
|
|
|
|
|
|
else:
|
|
context_instruct = state['context_instruct']
|
|
contest_instruct_bk = context_instruct
|
|
|
|
|
|
|
|
|
|
state = apply_extensions('state', state)
|
|
if shared.model_name == 'None' or shared.model is None:
|
|
print("No model is loaded! Select one in the Model tab.")
|
|
yield text_to_keep, full_text
|
|
return
|
|
|
|
output = {'visible': [], 'internal': []}
|
|
output['internal'].append(['', ''])
|
|
output['visible'].append(['', ''])
|
|
|
|
last_history = {'visible': [], 'internal': []}
|
|
|
|
|
|
outline_title = selected_item
|
|
count_before_outline = 0
|
|
|
|
if params['include_history_nr'] > 0 and params['include_history']:
|
|
for item in data_structure:
|
|
if item["outline"] == outline_title:
|
|
break
|
|
|
|
hist_prompt = item["prompt"]
|
|
key = "scenetext_"+item["version"]
|
|
hist_response = item[key]
|
|
|
|
hist_notes = item["notes"]
|
|
|
|
if count_before_outline < params['include_history_nr']:
|
|
last_history['internal'].append([hist_prompt, hist_response])
|
|
last_history['visible'].append([hist_prompt, hist_response])
|
|
else:
|
|
|
|
last_history['internal'].pop(0)
|
|
last_history['visible'].pop(0)
|
|
last_history['internal'].append([hist_prompt, hist_response])
|
|
last_history['visible'].append([hist_prompt, hist_response])
|
|
|
|
if hist_notes!='':
|
|
note_text = 'Note: '+hist_notes
|
|
note_response = "(Understood. I’ll keep this note in mind as I write further.)"
|
|
last_history['internal'].append([note_text, note_response])
|
|
last_history['visible'].append([note_text, note_response])
|
|
|
|
|
|
count_before_outline += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stopping_strings = chat.get_stopping_strings(state)
|
|
|
|
is_stream = state['stream']
|
|
|
|
|
|
if not _continue:
|
|
visible_text = user_prompt
|
|
|
|
|
|
user_prompt, visible_text = apply_extensions('chat_input', user_prompt, visible_text, state)
|
|
user_prompt = apply_extensions('input', user_prompt, state, is_chat=True)
|
|
|
|
outtext = _iswriting
|
|
yield outtext, full_text
|
|
|
|
else:
|
|
visible_text = user_prompt
|
|
|
|
if _continue:
|
|
text_to_keep = existing_text_in_output
|
|
|
|
|
|
|
|
|
|
last_history['internal'].append([user_prompt, existing_text_in_output])
|
|
last_history['visible'].append([user_prompt, existing_text_in_output])
|
|
|
|
outtext = text_to_keep + _iswriting
|
|
yield outtext, full_text
|
|
|
|
|
|
|
|
kwargs = {
|
|
'_continue': _continue,
|
|
'history': last_history,
|
|
}
|
|
|
|
|
|
system_message = contest_instruct_bk
|
|
world_msg = ''
|
|
lore_msg = ''
|
|
|
|
if params['system']!='':
|
|
system_message = params['system']
|
|
system_message = system_message.rstrip('\n')
|
|
|
|
if params['world']!='':
|
|
world_msg = "\n\n"+params['world']
|
|
|
|
|
|
if dynamic_lore:
|
|
user_input_lower = text_prompt.lower()
|
|
for dyn_mem_item in dynamic_lore:
|
|
|
|
keywords = dyn_mem_item["keywords"].lower().split(",")
|
|
for keyword in keywords:
|
|
keywordsimp = keyword.strip()
|
|
if keywordsimp!='' and keywordsimp in user_input_lower:
|
|
print(f"Found Lore keyword: {keywordsimp}")
|
|
|
|
lore_msg += "\n\n"+ dyn_mem_item["memory"]
|
|
|
|
|
|
|
|
if new_version:
|
|
state['custom_system_message'] = system_message+world_msg+lore_msg
|
|
else:
|
|
state['context_instruct'] = system_message+world_msg+lore_msg
|
|
|
|
|
|
|
|
|
|
|
|
prompt = chat.generate_chat_prompt(user_prompt, state, **kwargs)
|
|
|
|
|
|
if new_version:
|
|
state['custom_system_message'] = contest_instruct_bk
|
|
else:
|
|
state['context_instruct'] = contest_instruct_bk
|
|
|
|
|
|
reply = None
|
|
for j, reply in enumerate(chat.generate_reply(prompt, state, stopping_strings=stopping_strings, is_chat=True)):
|
|
|
|
visible_reply = reply
|
|
|
|
if shared.stop_everything:
|
|
output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True)
|
|
|
|
output_text = output['visible'][-1][1]
|
|
print("--Interrupted--")
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
generate_combined_text()
|
|
save_to_json(last_save)
|
|
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
return
|
|
|
|
if _continue:
|
|
output['internal'][-1] = [user_prompt, reply]
|
|
output['visible'][-1] = [visible_text, visible_reply]
|
|
if is_stream:
|
|
output_text = output['visible'][-1][1]
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
yield text_to_keep + output_text, full_text
|
|
elif not (j == 0 and visible_reply.strip() == ''):
|
|
output['internal'][-1] = [user_prompt, reply.lstrip(' ')]
|
|
output['visible'][-1] = [visible_text, visible_reply.lstrip(' ')]
|
|
|
|
if is_stream:
|
|
output_text = output['visible'][-1][1]
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True)
|
|
|
|
output_text = output['visible'][-1][1]
|
|
|
|
|
|
last_history_visible = output['visible'][-1]
|
|
last_history_internal = output['internal'][-1]
|
|
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
generate_combined_text()
|
|
save_to_json(last_save)
|
|
save_state()
|
|
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_reply_wrapperMY_NP(text_prompt, existing_text_in_output, state, _continue=False):
|
|
|
|
global params
|
|
global last_history_visible
|
|
global last_history_internal
|
|
global last_undo
|
|
global last_save
|
|
global selected_item
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global full_text_until
|
|
global full_text
|
|
global data_structure
|
|
global dynamic_lore_changed
|
|
global dynamic_lore
|
|
|
|
|
|
selF = params['selectA'][0]
|
|
selT = params['selectA'][1]
|
|
|
|
params['selectA'] = [0,0]
|
|
|
|
new_version = True
|
|
if 'turn_template' in state:
|
|
new_version = False
|
|
|
|
visible_text = None
|
|
|
|
user_prompt = text_prompt
|
|
|
|
text_to_keep = ""
|
|
|
|
if params['lorebook']!='' and not dynamic_lore:
|
|
dynamic_lore_changed=True
|
|
|
|
if dynamic_lore_changed==True:
|
|
dynamic_lore = parse_dynamic_lore(params['lorebook'])
|
|
dynamic_lore_changed = False
|
|
|
|
|
|
generate_combined_text()
|
|
|
|
if new_version:
|
|
if state['instruction_template_str']=='':
|
|
print("Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction Template]")
|
|
text_to_keep = existing_text_in_output + "\n Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction template]"
|
|
yield text_to_keep, full_text
|
|
return
|
|
else:
|
|
if state['turn_template']=='':
|
|
print("Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction Template]")
|
|
text_to_keep = existing_text_in_output + "\n Instruction template is empty! Select Instruct template in tab [Parameters] - [Instruction template]"
|
|
yield text_to_keep, full_text
|
|
return
|
|
|
|
|
|
|
|
state['mode'] = 'instruct'
|
|
|
|
_iswriting = "..."
|
|
|
|
|
|
|
|
if new_version:
|
|
context_instruct = state['custom_system_message']
|
|
contest_instruct_bk = context_instruct
|
|
|
|
|
|
|
|
else:
|
|
context_instruct = state['context_instruct']
|
|
contest_instruct_bk = context_instruct
|
|
|
|
|
|
|
|
|
|
state = apply_extensions('state', state)
|
|
if shared.model_name == 'None' or shared.model is None:
|
|
print("No model is loaded! Select one in the Model tab.")
|
|
yield text_to_keep, full_text
|
|
return
|
|
|
|
output = {'visible': [], 'internal': []}
|
|
output['internal'].append(['', ''])
|
|
output['visible'].append(['', ''])
|
|
|
|
last_history = {'visible': [], 'internal': []}
|
|
|
|
|
|
if params['include_history_nr']>0 and params['include_history']:
|
|
story_so_far = generate_combined_text_until_current_with_history(params['include_history_nr'])
|
|
else:
|
|
story_so_far = ''
|
|
|
|
stopping_strings = chat.get_stopping_strings(state)
|
|
|
|
is_stream = state['stream']
|
|
|
|
|
|
if not _continue:
|
|
visible_text = user_prompt
|
|
|
|
outtext = _iswriting
|
|
yield outtext, full_text
|
|
|
|
else:
|
|
visible_text = user_prompt
|
|
|
|
if _continue:
|
|
text_to_keep = existing_text_in_output+'\n'
|
|
|
|
story_so_far = story_so_far +"\n"+ existing_text_in_output
|
|
outtext = text_to_keep + _iswriting
|
|
yield outtext, full_text
|
|
|
|
|
|
|
|
kwargs = {
|
|
'_continue': _continue,
|
|
'history': last_history,
|
|
}
|
|
|
|
|
|
|
|
system_message = contest_instruct_bk
|
|
world_msg = ''
|
|
lore_msg = ''
|
|
|
|
if params['system']!='':
|
|
system_message = params['system']
|
|
system_message = system_message.rstrip('\n')
|
|
|
|
if params['world']!='':
|
|
world_msg = "\n\n"+params['world']+"\n\n"
|
|
|
|
|
|
if dynamic_lore:
|
|
user_input_lower = text_prompt.lower()
|
|
for dyn_mem_item in dynamic_lore:
|
|
|
|
keywords = dyn_mem_item["keywords"].lower().split(",")
|
|
|
|
for keyword in keywords:
|
|
keywordsimp = keyword.strip()
|
|
if keywordsimp!='' and keywordsimp in user_input_lower:
|
|
|
|
print(f"Found Lore keyword: {keywordsimp}")
|
|
lore_msg += "\n\n"+ dyn_mem_item["memory"]
|
|
|
|
|
|
prompt = system_message + world_msg + lore_msg
|
|
prompt = prompt+ story_so_far+"\n"
|
|
if text_prompt!='':
|
|
prompt = prompt + "(Editor's Note: Continue writing the story using the following direction. "+ text_prompt+")\n"
|
|
|
|
|
|
if new_version:
|
|
state['custom_system_message'] = contest_instruct_bk
|
|
else:
|
|
state['context_instruct'] = contest_instruct_bk
|
|
|
|
|
|
reply = None
|
|
for j, reply in enumerate(chat.generate_reply(prompt, state, stopping_strings=stopping_strings, is_chat=False)):
|
|
|
|
|
|
visible_reply = reply
|
|
|
|
if shared.stop_everything:
|
|
output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=False)
|
|
|
|
output_text = output['visible'][-1][1]
|
|
print("--Interrupted--")
|
|
update_item_by_outline(selected_item, selected_scene_version,text_prompt, text_to_keep + output_text)
|
|
generate_combined_text()
|
|
save_to_json(last_save)
|
|
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
return
|
|
|
|
if _continue:
|
|
output['internal'][-1] = [user_prompt, reply]
|
|
output['visible'][-1] = [visible_text, visible_reply]
|
|
if is_stream:
|
|
output_text = output['visible'][-1][1]
|
|
update_item_by_outline(selected_item, selected_scene_version,text_prompt, text_to_keep + output_text)
|
|
yield text_to_keep + output_text, full_text
|
|
elif not (j == 0 and visible_reply.strip() == ''):
|
|
output['internal'][-1] = [user_prompt, reply.lstrip(' ')]
|
|
output['visible'][-1] = [visible_text, visible_reply.lstrip(' ')]
|
|
|
|
if is_stream:
|
|
output_text = output['visible'][-1][1]
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=False)
|
|
|
|
output_text = output['visible'][-1][1]
|
|
|
|
|
|
last_history_visible = output['visible'][-1]
|
|
last_history_internal = output['internal'][-1]
|
|
|
|
update_item_by_outline(selected_item, selected_scene_version, text_prompt, text_to_keep + output_text)
|
|
generate_combined_text()
|
|
save_to_json(last_save)
|
|
save_state()
|
|
|
|
yield text_to_keep + output_text, full_text
|
|
|
|
def custom_css():
|
|
return """
|
|
.preview-text textarea {
|
|
background-color: #071407 !important;
|
|
--input-text-size: 16px !important;
|
|
color: #4dc66a !important;
|
|
--body-text-color: #4dc66a !important;
|
|
font-family: monospace
|
|
|
|
}
|
|
.scene-text textarea {
|
|
background-color: #301919 !important;
|
|
color: #f19999 !important;
|
|
--body-text-color: #f19999 !important;
|
|
font-family: monospace
|
|
|
|
}
|
|
.scene-text2 textarea {
|
|
background-color: #192930 !important;
|
|
color: #99CCFF !important;
|
|
--body-text-color: #99CCFF !important;
|
|
font-family: monospace
|
|
|
|
}
|
|
"""
|
|
|
|
def custom_js():
|
|
java = '''
|
|
const blockwriterElement = document.querySelector('#textbox-blockwriter textarea');
|
|
let blockwriterScrolled = false;
|
|
|
|
blockwriterElement.addEventListener('scroll', function() {
|
|
let diff = blockwriterElement.scrollHeight - blockwriterElement.clientHeight;
|
|
if(Math.abs(blockwriterElement.scrollTop - diff) <= 1 || diff == 0) {
|
|
blockwriterScrolled = false;
|
|
} else {
|
|
blockwriterScrolled = true;
|
|
}
|
|
});
|
|
|
|
const blockwriterObserver = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
if(!blockwriterScrolled) {
|
|
blockwriterElement.scrollTop = playgroundAElement.scrollHeight;
|
|
}
|
|
});
|
|
});
|
|
|
|
blockwriterObserver.observe(blockwriterElement.parentNode.parentNode.parentNode, config);
|
|
|
|
'''
|
|
return java
|
|
|
|
|
|
def create_action_button(button_label, main_function, update_function, outputs, variant = 'primary'):
|
|
|
|
_ishow = False
|
|
|
|
def show():
|
|
nonlocal _ishow
|
|
if _ishow:
|
|
_ishow = False
|
|
return gr.Button.update(visible=False),gr.Button.update(visible=False)
|
|
else:
|
|
_ishow = True
|
|
return gr.Button.update(visible=True),gr.Button.update(visible=True)
|
|
|
|
def hide():
|
|
nonlocal _ishow
|
|
_ishow = False
|
|
return gr.Button.update(visible=False),gr.Button.update(visible=False)
|
|
|
|
def process():
|
|
nonlocal _ishow
|
|
_ishow = False
|
|
main_function()
|
|
return gr.Button.update(visible=False),gr.Button.update(visible=False)
|
|
|
|
_intMain = gr.Button(button_label, interactive=True, variant = variant)
|
|
with gr.Row():
|
|
_intAction = gr.Button(value= 'Continue?',variant="primary",visible=False,interactive=True)
|
|
_intCancel = gr.Button(value='Cancel',visible=False,interactive=True)
|
|
|
|
|
|
_intMain.click(show,None,[_intAction,_intCancel])
|
|
_intCancel.click(hide,None,[_intAction,_intCancel])
|
|
_intAction.click(process,None,[_intAction,_intCancel]).then(update_function,None,outputs)
|
|
|
|
return _intMain
|
|
|
|
def create_save_button(button_label, save_method, defaultname_variable, default_key, save_method_inputs = None, variant = 'secondary'):
|
|
|
|
def show():
|
|
defname = defaultname_variable[default_key] if defaultname_variable is not None else default_key
|
|
return gr.Textbox.update(value = defname, interactive= True, visible=True),gr.Button.update(visible=True),gr.Button.update(visible=True),gr.Button.update(visible=False)
|
|
|
|
def hide():
|
|
return gr.Textbox.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=True)
|
|
|
|
_intMain = gr.Button(button_label, interactive=True,variant=variant)
|
|
_edit_name = gr.Textbox(value='',lines=1,max_lines=1,visible=False, label='Name',interactive=True)
|
|
with gr.Row():
|
|
_intAction = gr.Button(value=button_label,variant="primary",visible=False,interactive=True)
|
|
_intCancel = gr.Button(value='Cancel',visible=False,interactive=True)
|
|
|
|
_intMain.click(show,None,[_edit_name,_intAction,_intCancel,_intMain])
|
|
_intCancel.click(hide,None,[_edit_name,_intAction,_intCancel,_intMain])
|
|
inputs = [_edit_name] + save_method_inputs if save_method_inputs is not None else _edit_name
|
|
_intAction.click(save_method,inputs,None).then(hide,None,[_edit_name,_intAction,_intCancel,_intMain])
|
|
|
|
return _intMain
|
|
|
|
|
|
def create_load_button(button_label, load_method, file_list_method, update_function, outputs, variant = 'secondary'):
|
|
|
|
def show():
|
|
choices = file_list_method()
|
|
return gr.Dropdown.update(choices=choices, value='None', visible = True),gr.Button.update(visible=True),gr.Button.update(visible=True),gr.Button.update(visible=False)
|
|
|
|
def hide():
|
|
return gr.Textbox.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=True)
|
|
|
|
def process(text):
|
|
load_method(text)
|
|
return gr.Textbox.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=False),gr.Button.update(visible=True)
|
|
|
|
_intMain = gr.Button(button_label, interactive=True,variant=variant)
|
|
_drop = gr.Dropdown(choices=['None'], label= button_label, value='None',visible=False,interactive=True)
|
|
with gr.Row():
|
|
_intAction = gr.Button(value='Load',variant="primary",visible=False,interactive=True)
|
|
_intCancel = gr.Button(value='Cancel',visible=False,interactive=True)
|
|
|
|
|
|
_intMain.click(show,None,[_drop,_intAction,_intCancel,_intMain])
|
|
_intCancel.click(hide,None,[_drop,_intAction,_intCancel,_intMain])
|
|
_intAction.click(process,_drop,[_drop,_intAction,_intCancel,_intMain]).then(update_function,None,outputs)
|
|
|
|
return _intMain
|
|
|
|
|
|
def get_available_projects():
|
|
templpath = save_proj_path
|
|
paths = (x for x in Path(templpath).iterdir() if x.suffix in ('.json'))
|
|
sortedlist = sorted(set((k.stem for k in paths)), key=natural_keys)
|
|
sortedlist.insert(0, "None")
|
|
return sortedlist
|
|
|
|
|
|
def lorebook_save_action(name, text):
|
|
|
|
print(f"Saving file: {name}")
|
|
print(f"Saving file: {text}")
|
|
|
|
def project_save(projname):
|
|
global params
|
|
global last_save
|
|
params['projectname'] = projname
|
|
projpath = save_proj_path +"/"+ projname+".json"
|
|
projpath2 = save_proj_path +"/"+ projname+".jsonw"
|
|
|
|
save_to_json(projpath)
|
|
save_to_json(last_save)
|
|
save_proj_state(projpath2)
|
|
save_state()
|
|
print(f"Project saved to: {projpath}")
|
|
return projname
|
|
|
|
def quick_project_save():
|
|
global params
|
|
global last_save
|
|
projname = params['projectname']
|
|
projpath = save_proj_path +"/"+ projname+".json"
|
|
projpath2 = save_proj_path +"/"+ projname+".jsonw"
|
|
|
|
save_to_json(projpath)
|
|
save_proj_state(projpath2)
|
|
|
|
save_to_json(last_save)
|
|
save_state()
|
|
print(f"Project saved to: {projpath}")
|
|
|
|
|
|
def load_project(projname):
|
|
global params
|
|
params['projectname'] = projname
|
|
projpath = save_proj_path +"/"+ projname+".json"
|
|
projpath2 = save_proj_path +"/"+ projname+".jsonw"
|
|
load_from_json(projpath)
|
|
load_proj_state(projpath2)
|
|
print(f"Project loaded: {projpath}")
|
|
|
|
def rename_scene(scene_name):
|
|
global params
|
|
print(f"Saving file: {scene_name}")
|
|
|
|
def full_update_ui():
|
|
global selected_item
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global full_text_until
|
|
global full_text
|
|
global selected_item_notes
|
|
global params
|
|
|
|
return gr.Radio.update(choices=get_scene_list(), value=selected_item), selected_item, selected_item_prompt, selected_item_scenetext, selected_scene_version, full_text_until, full_text, selected_item_notes, params['projectname'], params['projectname'], params['system'],params['world'],params['lorebook']
|
|
|
|
def create_new_project():
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global full_text_until
|
|
global full_text
|
|
global data_structure
|
|
global last_save
|
|
global params
|
|
|
|
selected_item = "Beat 1"
|
|
selected_item_title = "Beat 1"
|
|
|
|
selected_item_prompt = "Write a paragraph where ..."
|
|
selected_item_scenetext = ""
|
|
full_text_until = ""
|
|
full_text = ""
|
|
params['projectname'] = 'new_project'
|
|
data_structure = [{"outline": selected_item,"outline_title": selected_item_title, "prompt": selected_item_prompt, "scenetext_v1": selected_item_scenetext, "scenetext_v2": "", "scenetext_v3": "","version":"v1","notes":"","is_summary": False}]
|
|
|
|
params['world']=''
|
|
params['lorebook']=''
|
|
save_to_json(last_save)
|
|
save_state()
|
|
|
|
def delete_beat_funct():
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global full_text_until
|
|
global full_text
|
|
global data_structure
|
|
global last_save
|
|
|
|
delete_item_by_outline(selected_item)
|
|
|
|
|
|
def ui():
|
|
global params
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global full_text
|
|
global full_text_until
|
|
|
|
|
|
params['selectA'] = [0,0]
|
|
|
|
load_state()
|
|
load_from_json(last_save)
|
|
|
|
with gr.Row():
|
|
with gr.Column():
|
|
|
|
with gr.Tab('Scenes'):
|
|
with gr.Row():
|
|
with gr.Column(scale = 1):
|
|
with gr.Row():
|
|
gr_btn_addnew_scene = gr.Button(value='+ New Beat',visible=True,variant="primary")
|
|
with gr.Row():
|
|
gr_scenes_radio = gr.Radio(choices=get_scene_list(), value=selected_item, label='Beats', interactive=True, elem_classes='checkboxgroup-table')
|
|
with gr.Column(scale = 3):
|
|
with gr.Row():
|
|
gr_itemname = gr.Textbox(value=selected_item_title, lines = 1, visible = True, label = 'Beat Title', interactive=True, elem_classes=['scene-text'])
|
|
with gr.Row():
|
|
gr_prompt = gr.Textbox(value=selected_item_prompt ,lines=4,visible=True, label='Prompt')
|
|
with gr.Row():
|
|
with gr.Tab('Instruct Mode'):
|
|
with gr.Row():
|
|
gr_btn_generate = gr.Button(value='Generate',visible=True,variant="primary")
|
|
gr_btn_generate_continue = gr.Button(value='Continue',visible=True)
|
|
gr_btn_stop = gr.Button(value='Stop',visible=True)
|
|
with gr.Row():
|
|
gr.Markdown('The text will be generated from the prompt using model instruction template.')
|
|
with gr.Tab('Narrative Mode'):
|
|
with gr.Row():
|
|
gr_btn_generate_np = gr.Button(value='Generate (Narrative)',variant="primary", visible=True)
|
|
gr_btn_generate_continue_np = gr.Button(value='Continue (Narrative)',visible=True)
|
|
gr_btn_stop_np = gr.Button(value='Stop',visible=True)
|
|
with gr.Row():
|
|
gr.Markdown('The text will be generated as a Narrative completion of the scenes before. Prompt can be used to steer the generation but is used without adding instruction template.')
|
|
with gr.Tab('Future Cues'):
|
|
with gr.Row():
|
|
gr_notes = gr.Textbox(value=selected_item_notes ,lines=4,visible=True,interactive=True, label='Future Cues will be visible to the text model and will shape further text generation', elem_classes=['scene-text2'])
|
|
with gr.Tab('Settings'):
|
|
with gr.Row():
|
|
|
|
gr_include_history = gr.Checkbox(label = "Include Previous Scenes and Notes in the prompt", value = params['include_history'])
|
|
include_last_history = gr.Slider(value = params['include_history_nr'],step = 1, minimum=0, maximum=50, label='Max Number of newset Scenes to Include')
|
|
with gr.Tab('Tools'):
|
|
with gr.Row():
|
|
gr_tools_swap = gr.Button(value='<> Swap',visible=True, elem_classes="small-button")
|
|
|
|
with gr.Row():
|
|
gr_generated_text_version = gr.Radio(choices = ['v1','v2','v3'], value= selected_scene_version , visible=True, label='Version')
|
|
with gr.Row():
|
|
gr_generated_text = gr.Textbox(value=selected_item_scenetext ,lines=10,visible=True, label='Text',elem_classes=['textbox', 'add_scrollbar'],elem_id='textbox-blockwriter')
|
|
|
|
with gr.Row():
|
|
gr_btn_save_Quick = gr.Button(value='Quick Save',visible=True,variant="primary")
|
|
gr_itemUp = gr.Button("Move Up")
|
|
gr_itemDown = gr.Button("Move Down")
|
|
delete_beat = gr.Button('Delete Current Beat', interactive=True)
|
|
delete_confirm = gr.Button('Are you Sure?', variant='stop', visible=False)
|
|
delete_cancel = gr.Button('Cancel', visible=False)
|
|
with gr.Column(scale = 3):
|
|
with gr.Row():
|
|
gr_prevtext = gr.Textbox(value=full_text_until, lines = 35, visible = True, label = 'Story to this point', interactive=False,elem_classes=['preview-text', 'add_scrollbar'])
|
|
|
|
with gr.Tab('Full Text'):
|
|
with gr.Row():
|
|
with gr.Column(scale = 1):
|
|
gr_project_name_txt = gr.Textbox(value = params['projectname'], lines=1, label='Text Name')
|
|
gr_btn_save_Text = gr.Button(value='Save Text',visible=True,variant="primary")
|
|
with gr.Column(scale = 4):
|
|
gr_fulltext = gr.Textbox(value=full_text,lines=25,visible=True, label='Full Text', elem_classes=['preview-text', 'add_scrollbar'])
|
|
with gr.Column(scale = 1):
|
|
gr.Markdown('')
|
|
with gr.Tab('Lore book'):
|
|
with gr.Row():
|
|
with gr.Column(scale=4):
|
|
gr_text_SYSTEM = gr.Textbox(value = params['system'], lines=2, label='System Prompt')
|
|
with gr.Column(scale=1):
|
|
gr.Markdown('Set System message. This will be always send as the first thing to the text model')
|
|
with gr.Row():
|
|
with gr.Column(scale=4):
|
|
gr_text_WOORLD = gr.Textbox(value = params['world'], lines=10, label='Story Description and World (always present in prompt)')
|
|
with gr.Column(scale=1):
|
|
gr.Markdown('Description of the story, world, characters. This will be alwayspresent on the top of the prompt below the system prompt')
|
|
with gr.Row():
|
|
with gr.Column(scale=4):
|
|
gr_text_DYNAMEMORY = gr.Textbox(value = params['lorebook'], lines=10, label='Dynamic Lore')
|
|
with gr.Column(scale=1):
|
|
gr.Markdown('Lore triggered by a keywords in the prompt. The Lore will be only used if a keyword in the prompt triggers it.')
|
|
gr_lore_example = gr.Button(value='Load Example', visible=True)
|
|
|
|
with gr.Tab('Project'):
|
|
with gr.Row():
|
|
with gr.Column(scale=1):
|
|
|
|
gr_project_name = gr.Textbox(value = params['projectname'], lines=1, label='Current Project')
|
|
gr_project_save = gr.Button('Save Project', interactive=True)
|
|
gr_project_saveA = gr.Button('Save?', visible=False)
|
|
gr_project_saveC = gr.Button('Cancel', variant='stop', visible=False)
|
|
|
|
create_load_button( 'Load project', load_project, get_available_projects, full_update_ui, [gr_scenes_radio,gr_itemname,gr_prompt,gr_generated_text,gr_generated_text_version, gr_prevtext,gr_fulltext,gr_notes, gr_project_name,gr_project_name_txt,gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY] )
|
|
gr.Markdown('---')
|
|
create_action_button('New Project',create_new_project,full_update_ui,[gr_scenes_radio,gr_itemname,gr_prompt,gr_generated_text,gr_generated_text_version,gr_prevtext,gr_fulltext,gr_notes,gr_project_name,gr_project_name_txt,gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY])
|
|
with gr.Column(scale=4):
|
|
|
|
gr.Markdown(help_str)
|
|
|
|
def update_state_param(sysmsg, world, lore):
|
|
global params
|
|
global dynamic_lore_changed
|
|
params['system'] = sysmsg
|
|
params['world'] = world
|
|
lore_before = params['lorebook']
|
|
params['lorebook'] = lore
|
|
|
|
if lore_before!=lore:
|
|
dynamic_lore_changed = True
|
|
|
|
|
|
gr_text_SYSTEM.input(update_state_param,[gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY],None)
|
|
gr_text_WOORLD.input(update_state_param,[gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY],None)
|
|
gr_text_DYNAMEMORY.input(update_state_param,[gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY],None)
|
|
|
|
def write_lore():
|
|
global params
|
|
global dynamic_lore_changed
|
|
|
|
lore = """rimmer,arnold:
|
|
Arnold Judas Rimmer - A hologram of a deceased crew member, painfully neurotic, insufferably pompous, and obsessed with climbing the ranks of the Space Corps despite being utterly incompetent. Known for his pedantic obsession with Space Corps directives and his strained relationship with Lister.
|
|
|
|
cat:
|
|
The Cat - A highly evolved humanoid descendant of the ship's original pet cat. Vain, flamboyant, and obsessed with fashion, he moves with feline grace but is utterly self-centered. Lives for his looks and has a hilariously tenuous grasp of the crew's perilous reality.
|
|
|
|
lister,dave:
|
|
Dave Lister - The last human alive, a slobby, curry-loving everyman with a big heart and a dream of returning to Earth. Despite his laziness and crude manners, he's the emotional core of the crew, often finding himself at odds with Rimmer's uptight personality but deeply loyal to his companions."""
|
|
|
|
|
|
params['lorebook'] = lore
|
|
dynamic_lore_changed = True
|
|
|
|
return lore
|
|
|
|
gr_lore_example.click(write_lore,None,gr_text_DYNAMEMORY)
|
|
|
|
def update_item_ui():
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
global full_text_until
|
|
return selected_item_title, selected_item_prompt, selected_item_scenetext, selected_scene_version, full_text_until, selected_item_notes
|
|
|
|
|
|
def update_scenes_ui():
|
|
global selected_item
|
|
return gr.Radio.update(choices=get_scene_list(), value=selected_item)
|
|
|
|
def select_scene(scene_name):
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
|
|
if does_outline_exist(scene_name):
|
|
selected_item = scene_name
|
|
selected_item_prompt, selected_item_scenetext, selected_scene_version, selected_item_notes = get_data_by_outline(scene_name)
|
|
selected_item_title = get_title_by_outline(scene_name)
|
|
generate_combined_text_until_current()
|
|
|
|
|
|
gr_scenes_radio.change(select_scene,gr_scenes_radio,None).then(update_item_ui,None,[gr_itemname,gr_prompt,gr_generated_text,gr_generated_text_version, gr_prevtext,gr_notes],show_progress=False)
|
|
|
|
def change_version(version):
|
|
global selected_item
|
|
global selected_item_title
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
|
|
selected_scene_version = version
|
|
|
|
set_version_by_outline(selected_item,version)
|
|
selected_item_prompt, selected_item_scenetext, selected_scene_version, selected_item_notes = get_data_by_outline(selected_item)
|
|
generate_combined_text_until_current()
|
|
generate_combined_text()
|
|
|
|
|
|
|
|
|
|
def update_text_version_change():
|
|
global selected_item_scenetext
|
|
global full_text_until
|
|
global full_text
|
|
return selected_item_scenetext,full_text_until,full_text
|
|
|
|
|
|
gr_generated_text_version.change(change_version,gr_generated_text_version,None).then(update_text_version_change, None, [gr_generated_text,gr_prevtext,gr_fulltext],show_progress=False)
|
|
|
|
|
|
clear_arr = [delete_confirm, delete_beat, delete_cancel]
|
|
delete_beat.click(lambda: [gr.update(visible=True), gr.update(visible=False), gr.update(visible=True)], None, clear_arr)
|
|
delete_cancel.click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, clear_arr)
|
|
delete_confirm.click(delete_beat_funct,None,None).then(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, clear_arr).then(
|
|
full_update_ui, None,[gr_scenes_radio,gr_itemname,gr_prompt,gr_generated_text,gr_generated_text_version, gr_prevtext,gr_fulltext,gr_notes,gr_project_name,gr_project_name_txt,gr_text_SYSTEM,gr_text_WOORLD,gr_text_DYNAMEMORY])
|
|
|
|
|
|
save_arr = [gr_project_saveA, gr_project_save, gr_project_saveC]
|
|
gr_project_save.click(lambda: [gr.update(visible=True), gr.update(visible=False), gr.update(visible=True)], None, save_arr)
|
|
gr_project_saveC.click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, save_arr)
|
|
gr_project_saveA.click(project_save,gr_project_name,gr_project_name_txt).then(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, save_arr)
|
|
|
|
gr_btn_save_Quick.click(quick_project_save,None,None)
|
|
|
|
def full_text_save(savename):
|
|
text = generate_combined_text()
|
|
projpath = save_proj_path_txt +"/"+ savename+".txt"
|
|
try:
|
|
|
|
|
|
with open(projpath, 'w', encoding='utf-8') as file:
|
|
file.write(text)
|
|
|
|
print(f"Text successfully saved to: {projpath}")
|
|
except Exception as e:
|
|
print(f"Failed to save text to file. Error: {e}")
|
|
|
|
|
|
gr_btn_save_Text.click(full_text_save,gr_project_name_txt,None)
|
|
|
|
def add_new_item():
|
|
add_item_auto("Beat","","")
|
|
generate_combined_text_until_current()
|
|
|
|
gr_btn_addnew_scene.click(add_new_item,None,None).then(update_scenes_ui, None, gr_scenes_radio,show_progress=False).then(update_item_ui, None,[gr_itemname,gr_prompt,gr_generated_text,gr_generated_text_version, gr_prevtext, gr_notes],show_progress=False)
|
|
|
|
def change_prompt(text):
|
|
global selected_item
|
|
global selected_item_prompt
|
|
selected_item_prompt = text
|
|
update_prompt_by_outline(selected_item,selected_item_prompt)
|
|
|
|
|
|
gr_prompt.input(change_prompt,gr_prompt,None)
|
|
|
|
def change_scenetext(text):
|
|
global selected_item
|
|
global selected_item_scenetext
|
|
selected_item_scenetext = text
|
|
update_scenetext_by_outline(selected_item,selected_item_scenetext)
|
|
return generate_combined_text()
|
|
|
|
gr_generated_text.input(change_scenetext,gr_generated_text,gr_fulltext,show_progress=False)
|
|
|
|
def change_notes(text):
|
|
global selected_item_notes
|
|
global selected_item
|
|
selected_item_notes = text
|
|
update_notes_by_outline(selected_item,selected_item_notes)
|
|
|
|
gr_notes.input(change_notes,gr_notes,None,show_progress=False)
|
|
|
|
def change_title(text):
|
|
global selected_item
|
|
global selected_item_title
|
|
update_item_title_by_outline(selected_item,text)
|
|
selected_item_title = text
|
|
|
|
|
|
gr_itemname.input(change_title,gr_itemname,None)
|
|
|
|
def moveitemup():
|
|
global selected_item
|
|
move_item_up(selected_item)
|
|
|
|
return gr.Radio.update(choices=get_scene_list(), value=selected_item), generate_combined_text(), generate_combined_text_until_current()
|
|
|
|
gr_itemUp.click(moveitemup,None,[gr_scenes_radio,gr_fulltext,gr_prevtext])
|
|
|
|
|
|
def moveitemdown():
|
|
global selected_item
|
|
move_item_down(selected_item)
|
|
|
|
return gr.Radio.update(choices=get_scene_list(), value=selected_item), generate_combined_text(), generate_combined_text_until_current()
|
|
|
|
gr_itemDown.click(moveitemdown,None,[gr_scenes_radio,gr_fulltext,gr_prevtext])
|
|
|
|
|
|
input_paramsA = [gr_prompt, gr_generated_text, shared.gradio['interface_state']]
|
|
output_paramsA =[gr_generated_text,gr_fulltext]
|
|
|
|
|
|
disable_struct = [gr_scenes_radio,gr_btn_addnew_scene,gr_itemUp,gr_itemDown,gr_btn_generate,gr_btn_generate_continue,gr_btn_generate_np,gr_btn_generate_continue_np]
|
|
|
|
def update_full_text_ui():
|
|
global full_text_until
|
|
return full_text_until
|
|
|
|
def disable_radio():
|
|
return gr.Radio.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False)
|
|
|
|
def enable_radio():
|
|
return gr.Radio.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True)
|
|
|
|
gr_btn_generate.click(main_ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(disable_radio,None,disable_struct).then(
|
|
generate_reply_wrapperMY, inputs=input_paramsA, outputs= output_paramsA, show_progress=False).then(enable_radio,None,disable_struct)
|
|
|
|
gr_btn_generate_np.click(main_ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(disable_radio,None,disable_struct).then(
|
|
generate_reply_wrapperMY_NP, inputs=input_paramsA, outputs= output_paramsA, show_progress=False).then(enable_radio,None,disable_struct)
|
|
|
|
gr_btn_generate_continue_np.click(main_ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(disable_radio,None,disable_struct).then(
|
|
partial(generate_reply_wrapperMY_NP, _continue=True), inputs=input_paramsA, outputs= output_paramsA, show_progress=False).then(enable_radio,None,disable_struct)
|
|
|
|
gr_btn_generate_continue.click(main_ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(disable_radio,None,disable_struct).then(
|
|
partial(generate_reply_wrapperMY, _continue=True), inputs=input_paramsA, outputs= output_paramsA, show_progress=False).then(enable_radio,None,disable_struct)
|
|
|
|
def stop_everything_eventMy():
|
|
shared.stop_everything = True
|
|
|
|
gr_btn_stop.click(stop_everything_eventMy, None, None, queue=False)
|
|
gr_btn_stop_np.click(stop_everything_eventMy, None, None, queue=False)
|
|
|
|
include_last_history.change(lambda x: params.update({"include_history_nr": x}), include_last_history,None)
|
|
|
|
gr_include_history.change(lambda x: params.update({"include_history": x}), gr_include_history, None)
|
|
|
|
def swap_current():
|
|
global selected_item
|
|
global data_structure
|
|
global selected_item_prompt
|
|
global selected_item_scenetext
|
|
global selected_scene_version
|
|
global selected_item_notes
|
|
global full_text
|
|
for item in data_structure:
|
|
if item["outline"] == selected_item:
|
|
key = "scenetext_"+item["version"]
|
|
prompt = item["prompt"]
|
|
item["prompt"] = item[key]
|
|
item[key] = prompt
|
|
break
|
|
|
|
generate_combined_text()
|
|
selected_item_prompt, selected_item_scenetext, selected_scene_version, selected_item_notes = get_data_by_outline(selected_item)
|
|
return selected_item_prompt, selected_item_scenetext, full_text
|
|
|
|
|
|
gr_tools_swap.click(swap_current,None,[gr_prompt,gr_generated_text,gr_fulltext]) |