Skip to content

Commit

Permalink
ref: Story generation offloaded to KAI horde
Browse files Browse the repository at this point in the history
  • Loading branch information
db0 committed Sep 2, 2022
1 parent 7c243fa commit c33d287
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 222 deletions.
23 changes: 8 additions & 15 deletions src/dreamscape/AI/AIRatings.gd
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,21 @@ func _init(_encounter: EncounterStory = null):


func story_rated(classification :int) -> void:
# If the player didn't like it, we don't bother sending it at all
if classification == HConst.AIGenres.DISLIKE:
return
var thread: Thread = Thread.new()
threads.append(thread)
# warning-ignore:return_value_discarded
thread.start(self, "submit", classification)
thread.start(self, "submit_rating", classification)


func submit(classification: int):
func submit_rating(classification: int):
var data := {
"uuid": encounter.story_uuid,
"generation": encounter.story,
"title": encounter.title,
"name": encounter.name,
"type": encounter.type,
"classification": classification,
"client_id": cfc.game_settings['Client UUID'],
"model": globals.ai_stories.current_model,
"soft_prompt": globals.ai_stories.current_soft_prompt,
"kai_instance": "%s:%s" % [cfc.game_settings.get("kai_url",'http://127.0.0.1'),cfc.game_settings.get("kai_port", 5000)],
}
var _ret = _initiate_rest(HTTPClient.METHOD_POST, "/generation/", data)
var _ret = _initiate_rest(HTTPClient.METHOD_POST, "/rate", data)


func retrieve_evaluating_gens() -> void:
Expand All @@ -58,15 +51,15 @@ func retrieve_finalized_gens() -> void:


func retrieve_gens(evaluating:= true) -> void:
var endpoint = "/generations/evaluating/"
var endpoint = "/generations/evaluating"
if not evaluating:
endpoint = "/generations/finalized/"
endpoint = "/generations/finalized"
var ret = _initiate_rest(HTTPClient.METHOD_GET, endpoint)
if typeof(ret) == TYPE_DICTIONARY:
emit_signal("ratings_retrieved", ret, evaluating)
else:
var blah = endpoint.replace("/generations/",'').replace("/",'')
CFUtils.dprint("AIRatings:Could not retrieve %s stories from %s:%s" % [blah,TELEMETRY_URI,TELEMETRY_PORT])
var blah = endpoint.replace("/generations",'').replace("/",'')
CFUtils.dprint("AIRatings:Could not retrieve %s stories from %s:%s" % [blah,TELEMETRY_URI])


func _initiate_rest(method, endpoint: String, data: Dictionary = {}):
Expand Down
113 changes: 0 additions & 113 deletions src/dreamscape/AI/AIStories.gd
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@ var stories := {}
var threads: Array
var evaluating_generations: Dictionary
var finalized_generations: Dictionary
var current_model: String
var current_soft_prompt: String

onready var ai_ratings: AIRatings = AIRatings.new()

func _init():
load_stories()

func _ready():
if cfc.is_testing:
Expand All @@ -34,14 +30,6 @@ func _ready():
ai_ratings.connect("ratings_retrieved", self, "_on_ratings_received")
ai_ratings.retrieve_evaluating_gens()
ai_ratings.retrieve_finalized_gens()
# warning-ignore:return_value_discarded
EventBus.connect("kobodoldai_server_changed", self, "_on_koboldai_server_changed")
if cfc.game_settings.get("generate_ai", false):
var thread: Thread = Thread.new()
# warning-ignore:return_value_discarded
thread.start(self, "_init_koboldai_story")
threads.append(thread)



func retrieve_story(encounter_story) -> Dictionary:
Expand Down Expand Up @@ -73,64 +61,8 @@ func retrieve_story(encounter_story) -> Dictionary:
CFUtils.dprint("AIStories:Using finalized story for " + encounter_story.name)
else:
CFUtils.dprint("AIStories:Could not find generated story for " + encounter_story.name)
# We don't want to generate a story if there's an unused one already
if cfc.game_settings.generate_ai and not stories.has(encounter_story.name):
var thread: Thread = Thread.new()
# warning-ignore:return_value_discarded
thread.start(self, "regenerate_torment_story", encounter_story)
threads.append(thread)
return(story)

func regenerate_torment_story(encounter_story) -> void:
var ai_prompt : String = encounter_story.get_random_prompt()
var fmt := {
"prompt": ai_prompt,
"title": encounter_story.title,
"genre": HConst.get_aigenre_description(cfc.game_settings.ai_genre)
}
var prompt: String
if cfc.game_settings.ai_genre != HConst.AIGenres.RANDOM:
prompt = "[ Title: {title} ]\n"\
+ "[ Genre: {genre} ]\n"\
+ "{prompt}"
# We don't have to tell the AI to generate a random Genre.
else:
prompt = "[ Title: {title} ]\n"\
+ "{prompt}"
prompt = prompt.format(fmt)
# print("regenerate_torment_story():" + prompt)
var new_story = KoboldAI.generate(prompt, encounter_story.max_length)
if not new_story:
return
var regex = RegEx.new()
regex.compile(" \\[ [\\w ]+ \\]([ .,;])")
var full_story : String = regex.sub(ai_prompt, '$1') + new_story
stories[encounter_story.name] = {
"uuid": UUID.v4(),
"story": full_story
}
save_stories()

# Saves previously generated stories that have not yet been used
func save_stories() -> void:
stories_file.open(STORIES_FILENAME, File.WRITE)
stories_file.store_var(stories)
# file.store_string(JSON.print(state, '\t'))
stories_file.close()


# Loads previously generated stories that have not yet been used
func load_stories() -> void:
if not stories_file_exists():
return
stories_file.open(STORIES_FILENAME, File.READ)
var data = stories_file.get_var()
stories_file.close()
if typeof(data) != TYPE_DICTIONARY:
return
# warning-ignore:return_value_discarded
stories = data


# Retrieves a generation under evaluation which has not yet been rated by this client
func get_fresh_evaluating_gen(encounter_story):
Expand Down Expand Up @@ -163,10 +95,6 @@ func get_generations(encounter_story, evaluating: bool) -> Dictionary:
return(collected_generations)


func stories_file_exists() -> bool:
return(stories_file.file_exists(STORIES_FILENAME))


# Stores the downloaded ratings to the internal variables
func _on_ratings_received(ratings_dict: Dictionary, evaluating: bool) -> void:
if evaluating:
Expand All @@ -177,47 +105,6 @@ func _on_ratings_received(ratings_dict: Dictionary, evaluating: bool) -> void:
CFUtils.dprint("AIStories:Loaded finalized stories.")


func _init_koboldai_story() -> void:
var wi = KoboldAI.get_world_info()
if not wi:
push_warning("KoboldAI instance not found")
return
if wi.has("entries"):
if wi.entries.empty():
var _ret = KoboldAI.put_story()
CFUtils.dprint("AIStories:Hypnagonia world info loaded.")
else:
CFUtils.dprint("AIStories:Hypnagonia world info already loaded.")
var sp = KoboldAI.get_soft_prompt()
if not sp:
push_warning("KoboldAI instance not found")
return
var model_to_sp := {
"KoboldAI/fairseq-dense-2.7B-Nerys": "surrealism_and_dreams_2.7B.zip",
"KoboldAI/fairseq-dense-13B-Nerys": "surrealism_and_dreams_13B.zip",
"KoboldAI/fairseq-dense-13B-Nerys-v2": "surrealism_and_dreams_13B.zip",
}
var model = KoboldAI.get_model()
if not model:
push_warning("KoboldAI instance not found")
return
if not model_to_sp.values().has(sp):
var _ret = KoboldAI.put_soft_prompt(model_to_sp[model])
CFUtils.dprint("AIStories:Hypnagonia soft prompt %s loaded." % [model_to_sp[model]])
current_model = model
current_soft_prompt = model_to_sp[model]
else:
CFUtils.dprint("AIStories:Hypnagonia soft prompt %s already loaded." % [sp])
current_soft_prompt = sp
current_model = model



func _on_koboldai_server_changed() -> void:
var thread: Thread = Thread.new()
thread.start(self, "_init_koboldai_story")
threads.append(thread)

# Thread must be disposed (or "joined"), for portability.
func _exit_tree():
for thread in threads:
Expand Down
4 changes: 1 addition & 3 deletions src/dreamscape/AI/KoboldAI.gd
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ static func _initiate_rest(method, endpoint: String, data: Dictionary = {}):
# print([method, endpoint, data])
var http = HTTPClient.new()
# Connect to host/port.
var err = http.connect_to_host(
cfc.game_settings.get("kai_url",'http://127.0.0.1'),
cfc.game_settings.get("kai_port", 5000))
var err = http.connect_to_host("http://dbzer0.com", 5001)
# Make sure connection was OK.
assert(err == OK)
# Wait until resolved and connected.
Expand Down
42 changes: 32 additions & 10 deletions src/dreamscape/MainMenu/MainMenu.gd
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,14 @@ func _input(event):
library_export.open("user://cards_names_without_art.json",File.WRITE)
library_export.store_string(JSON.print(card_names_for_art_export, '\t'))
library_export.close()
var all_t = _export_torments()
var torments_dict = all_t[0]
var torments_prompts = all_t[1]
library_export.open("user://torments_export.json",File.WRITE)
library_export.store_string(JSON.print(_export_torments(), '\t'))
library_export.store_string(JSON.print(torments_dict, '\t'))
library_export.close()
library_export.open("user://torments_aiprompts.json",File.WRITE)
library_export.store_string(JSON.print(torments_prompts, '\t'))
library_export.close()
library_export.open("user://torments_softprompt.txt",File.WRITE)
library_export.store_string(get_torment_softprompt_training())
Expand Down Expand Up @@ -259,12 +265,13 @@ func _switch_bg(bg_image: ImageTexture) -> void:
bg_tween.start()


func _export_torments() -> Dictionary:
func _export_torments() -> Array:
var tdict: Dictionary = {
'Basic Torments': {},
'Elite Torments': {},
'Bosses': {},
}
var sdict = {}
for act in [Act1, Act2, Act3]:
for e in act.ENEMIES:
var enemy = act.ENEMIES[e]
Expand All @@ -274,29 +281,44 @@ func _export_torments() -> Dictionary:
tdict['Basic Torments'][torment.definition.Name]['Journal Description'] = _remove_bburl_from_desc(enemy.journal_description)
if enemy.has("ai_prompts"):
tdict['Basic Torments'][torment.definition.Name]['AI prompts'] = enemy.ai_prompts
sdict[enemy.name] = {'prompts':{}}
sdict[enemy.name]['prompts']["journal_choice"] = enemy.ai_prompts
if enemy.get("title"):
sdict[enemy.name]["title"] = enemy.title
tdict['Basic Torments'][torment.definition.Name]['Type'] = torment.definition.Type
for e in act.ELITES:
var enemy = act.ELITES[e]
if not tdict['Elite Torments'].has(enemy.name):
tdict['Elite Torments'][enemy.name] = {}
tdict['Elite Torments'][enemy.name]['Journal Description'] = enemy.journal_description
sdict[enemy.name] = {'prompts':{}}
if enemy.get("ai_prompts"):
sdict[enemy.name]['prompts']["journal_choice"] = enemy.ai_prompts
if enemy.get("title"):
sdict[enemy.name]["title"] = enemy.title
for s in enemy.scenes:
var scene :AdvancedEnemyEntity = s.instance()
tdict['Elite Torments'][enemy.name]['Type'] = scene.PROPERTIES.Type
scene.queue_free()
for enemy in act.BOSSES:
if not tdict['Bosses'].has(enemy):
tdict['Bosses'][enemy] = {}
tdict['Bosses'][enemy]['Journal Description'] = act.BOSSES[enemy].journal_description
for s in act.BOSSES[enemy].scenes:
for e in act.BOSSES:
var enemy = act.BOSSES[e]
if not tdict['Bosses'].has(enemy.name):
tdict['Bosses'][enemy.name] = {}
tdict['Bosses'][enemy.name]['Journal Description'] = enemy.journal_description
sdict[enemy.name] = {'prompts':{}}
if enemy.get("ai_prompts"):
sdict[enemy.name]['prompts']["journal_choice"] = enemy.ai_prompts
if enemy.get("title"):
sdict[enemy.name]["title"] = enemy.title
for s in enemy.scenes:
var scene :AdvancedEnemyEntity = s.instance()
tdict['Bosses'][enemy]['Type'] = scene.PROPERTIES.Type
tdict['Bosses'][enemy.name]['Type'] = scene.PROPERTIES.Type
scene.queue_free()
return(tdict)
return([tdict,sdict])


func get_torment_softprompt_training() -> String:
var torments_dict = _export_torments()
var torments_dict = _export_torments()[0]
var softprompt_export := ''
var torment_template := "[ Keywords: {name},{type} ]\n{description}<|endoftext|>"
for d in torments_dict:
Expand Down
35 changes: 0 additions & 35 deletions src/dreamscape/MainMenu/SettingsMenu.gd
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
extends CenterContainer

var koboldai_server_changed := false
var koboldai_changed_timer : float = 0

onready var back_button = $"%Back"
onready var focus_style = $"%FocusStyle"
onready var expand_linked_terms = $"%ExpandLinkedTerms"
Expand All @@ -17,9 +14,6 @@ onready var music_vol_slider = $"%MusicVolSlider"
onready var use_ai = $"%UseAI"
onready var judge_ai = $"%JudgeAI"
onready var generate_ai = $"%GenerateAI"
onready var urlvbc = $"%URLVBC"
onready var kaiurl_input = $"%KAIURLInput"
onready var kai_port_input = $"%KAIPortInput"
onready var ai_label = $"%AILabel"
onready var ai_genre = $"%AIGenre"

Expand All @@ -44,8 +38,6 @@ func _ready() -> void:
cfc.game_settings['use_ai'] = cfc.game_settings.get('use_ai', OS.get_name() != "HTML5")
cfc.game_settings['judge_ai'] = cfc.game_settings.get('judge_ai', true)
cfc.game_settings['generate_ai'] = cfc.game_settings.get('generate_ai', false)
cfc.game_settings['kai_url'] = cfc.game_settings.get('kai_url', "http://127.0.0.1")
cfc.game_settings['kai_port'] = cfc.game_settings.get('kai_port', 5000)
cfc.game_settings['ai_genre'] = cfc.game_settings.get('ai_genre', HConst.AIGenres.RANDOM)

AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), cfc.game_settings.main_volume)
Expand All @@ -70,9 +62,6 @@ func _ready() -> void:
judge_ai.disabled = !use_ai.pressed
generate_ai.pressed = cfc.game_settings.generate_ai
generate_ai.disabled = !use_ai.pressed
urlvbc.visible = generate_ai.pressed
kaiurl_input.text = cfc.game_settings.kai_url
kai_port_input.text = str(cfc.game_settings.kai_port)
for genre_desc in HConst.AIGenres:
if HConst.AIGenres[genre_desc] == HConst.AIGenres.DISLIKE:
continue
Expand All @@ -81,15 +70,6 @@ func _ready() -> void:
# To avoid the slider adjust sound sounding from the initial setting
sound_effect_enabled = true

func _process(delta):
if koboldai_server_changed:
koboldai_changed_timer += delta
if koboldai_changed_timer >= 10:
EventBus.emit_signal("kobodoldai_server_changed")
koboldai_server_changed = false
koboldai_changed_timer = 0


func _on_FancAnimations_toggled(button_pressed: bool) -> void:
cfc.set_setting('fancy_movement',button_pressed)
cfc.set_setting('enable_visible_shuffle',button_pressed)
Expand Down Expand Up @@ -204,28 +184,13 @@ func _on_JudgeAI_toggled(button_pressed):

func _on_GenerateAI_toggled(button_pressed):
cfc.set_setting('generate_ai',button_pressed)
urlvbc.visible = generate_ai.pressed
if sound_effect_enabled:
if button_pressed:
SoundManager.play_se('setting_toggle_on')
else:
SoundManager.play_se('setting_toggle_off')


func _on_KAIURLInput_text_changed():
cfc.set_setting('kai_url',kaiurl_input.text.rstrip('\n'))
koboldai_server_changed = true
koboldai_changed_timer = 0



func _on_KAIPortInput_text_changed():
cfc.set_setting('kai_port',int(kai_port_input.text.rstrip('\n')))
koboldai_server_changed = true
koboldai_changed_timer = 0



func _on_UseAI_toggled(button_pressed):
cfc.set_setting('use_ai',button_pressed)
generate_ai.disabled = !button_pressed
Expand Down
Loading

0 comments on commit c33d287

Please sign in to comment.