Skip to content

Commit

Permalink
Merge pull request #65 from neph1/update-v0.24.0
Browse files Browse the repository at this point in the history
Update v0.24.0
  • Loading branch information
neph1 authored Jan 31, 2024
2 parents 6ca6330 + d4df0db commit a4ea2d0
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 41 deletions.
91 changes: 91 additions & 0 deletions generic_items.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"generic_weapons": [
{
"name": "Dagger",
"weapon_type": "ONE_HANDED",
"short_descr": "A steel dagger",
"base_damage": 1,
"weight": 0.5,
"type": "Weapon"
},
{
"name": "Club",
"weapon_type": "ONE_HANDED",
"short_descr": "A wooden club",
"base_damage": 1,
"weight": 1,
"type": "Weapon"
}
],
"fantasy_weapons": [
{
"name": "Sword",
"weapon_type": "ONE_HANDED",
"short_descr": "A plain sword",
"base_damage": 2,
"weight": 3,
"value": 20,
"type": "Weapon"
},
{
"name": "Spear",
"weapon_type": "TWO_HANDED",
"short_descr": "A spear",
"base_damage": 3,
"weight": 4,
"value": 10,
"type": "Weapon"
},
{
"name": "Crossbow",
"weapon_type": "TWO_HANDED_RANGED",
"short_descr": "A simple crossbow",
"base_damage": 2,
"weight": 5,
"value": 50,
"type": "Weapon"
}
],
"modern_weapons": [
{
"name": "Rusty pipe",
"weapon_type": "ONE_HANDED",
"short_descr": "A left-over piece of plumbing",
"base_damage": 1,
"weight": 3,
"value": 1
},
{
"name": "Semi-automatic pistol",
"weapon_type": "ONE_HANDED_RANGED",
"short_descr": "A pistol that has seen better days.",
"base_damage": 2,
"weight": 2,
"value": 100
}
],
"fantasy_items": [
{
"name": "Potion of healing",
"short_descr": "A potion of healing",
"weight": 0.5,
"value": 50,
"effect": 10,
"type": "Health"
}
],
"generic_various": [
{
"name": "Note",
"weight": 0.1,
"type": "Note"
},
{
"name": "Bread",
"weight": 0.5,
"short_descr": "A loaf of bread",
"effect": 10,
"type": "Food"
}
]
}
3 changes: 2 additions & 1 deletion stories/prancingllama/zones/prancingllama.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def init(self):
def spawn_rat(self, ctx: Context) -> None:
rat_skull = Item("rat_skull", "giant rat skull", descr="It's a giant rat's bloody skull.")
if not self.rat or self.rat.alive == False:
self.rat = Rat("giant rat", random.choice("m"), descr="A vicious looking, giant, rat", race="giant rat")
self.rat = Rat("giant rat", random.choice("m"), descr="A vicious looking, giant rat", race="giant rat")
self.rat.should_produce_remains = True
self.rat.init_inventory([rat_skull])
self.rat.move(self)

Expand Down
10 changes: 5 additions & 5 deletions tale/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1569,11 +1569,11 @@ def get_worn_items(self) -> Iterable[Wearable]:

def do_on_death(self, ctx: util.Context) -> 'Container':
"""Called when the living dies."""
if not self.should_produce_remains:
return None
remains = Container(f"remains of {self.title}")
remains.init_inventory(self.inventory)
self.location.insert(remains, None)
remains = None
if self.should_produce_remains:
remains = Container(f"remains of {self.title}")
remains.init_inventory(self.inventory)
self.location.insert(remains, None)
self.destroy(ctx)
return remains

Expand Down
5 changes: 0 additions & 5 deletions tale/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,11 +652,6 @@ def go_through_exit(self, player: player.Player, direction: str, evoke: bool=Tru
if zone and zone.name != new_zone.name:
player.tell(f"You're entering {new_zone.name}:{new_zone.description}")

if self.story.config.custom_resources and not target_location.avatar:
result = self.llm_util.generate_image(target_location.name, target_location.description)
if result:
target_location.avatar = target_location.name

if xt.enter_msg:
player.tell(xt.enter_msg, end=True, evoke=False, short_len=True)
player.tell("\n")
Expand Down
42 changes: 21 additions & 21 deletions tale/items/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@
"""


import json
import os
from tale import parse_utils
from tale.base import Item, Weapon
from tale.items.basic import Note
from tale.weapon_type import WeaponType

generic_weapons = [
Weapon(name="Dagger", weapon_type=WeaponType.ONE_HANDED, short_descr='A steel dagger', base_damage=1).to_dict(),
Weapon(name="Club", weapon_type=WeaponType.ONE_HANDED, short_descr='A wooden club', base_damage=1).to_dict(),
]
def load() -> dict:
items = dict()
with open(os.path.realpath(os.path.join(os.path.dirname(__file__), "../../generic_items.json")), "r") as file:
items = json.load(file, strict=False)
return items

fantasy_weapons = [
Weapon(name="Sword", weapon_type=WeaponType.ONE_HANDED, short_descr='A plain sword', base_damage=2).to_dict(),
Weapon(name="Spear", weapon_type=WeaponType.TWO_HANDED, short_descr='A spear', base_damage=3).to_dict(),
Weapon(name='Crossbow', weapon_type=WeaponType.TWO_HANDED_RANGED, short_descr='A simple crossbow', base_damage=2).to_dict(),
]

modern_weapons = [
Weapon(name="Rusty pipe", weapon_type=WeaponType.ONE_HANDED, short_descr='A left-over piece of plumbing', base_damage=1).to_dict(),
Weapon(name='Semi-automatic pistol', weapon_type=WeaponType.ONE_HANDED_RANGED, short_descr='A pistol that has seen better days.', base_damage=2).to_dict(),
]

generic_various = [
Note(name="Note", weight=0.1).to_dict()
]
items = load()

generic_weapons = items.get('generic_weapons', [])
fantasy_weapons = items.get('fantasy_weapons', [])
modern_weapons = items.get('modern_weapons', [])
scifi_weapons = items.get('scifi_weapons', [])
fantasy_items = items.get('fantasy_items', [])
modern_items = items.get('modern_items', [])
scifi_items = items.get('scifi_items', [])
generic_various = items.get('generic_various', [])

generic_items = {
'fantasy': [*generic_weapons, *fantasy_weapons, *generic_various],
'modern': [*generic_weapons, *modern_weapons, *generic_various],
'postapoc': [*generic_weapons, *modern_weapons, *generic_various],
'fantasy': [*generic_weapons, *fantasy_weapons, *fantasy_items, *generic_various],
'modern': [*generic_weapons, *modern_weapons, *modern_items, *generic_various],
'postapoc': [*generic_weapons, *modern_weapons, *modern_items, *generic_various],
'scifi': [*generic_weapons, *scifi_weapons, *scifi_items, *modern_weapons, *modern_items, *generic_various],
'': [*generic_weapons, *generic_various],
}

6 changes: 6 additions & 0 deletions tale/llm/llm_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def generate_hash(item: str) -> int:
def cache_event(event: str, event_hash: int = -1) -> int:
""" Adds an event to the cache.
Generates a hash if none supplied"""
if not isinstance(event, str):
print('cache_look received non-string look: ' + str(event) + ' of type ' + str(type(event)) + '. Converting to string.')
event = str(event)
if event_hash == -1:
event_hash = generate_hash(event)
if event_cache.get(event_hash) == None:
Expand All @@ -25,6 +28,9 @@ def get_events(event_hashes: [int]) -> str:
def cache_look(look: str, look_hash: int = -1) -> int:
""" Adds an event to the cache.
Generates a hash if none supplied"""
if not isinstance(look, str):
print('cache_look received non-string look: ' + str(look) + ' of type ' + str(type(look)) + '. Converting to string.')
look = str(look)
if look_hash == -1:
look_hash = generate_hash(look)
if look_cache.get(look_hash) == None:
Expand Down
4 changes: 2 additions & 2 deletions tale/llm/llm_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ def __init__(self, config: dict = None, backend_config: dict = None):

def synchronous_request(self, request_body: dict, prompt: str, context: str = '') -> str:
""" Send request to backend and return the result """
if request_body.get('grammar', None) and 'openai' in self.url:
if request_body.get('grammar', None) and self.backend == 'openai':
# TODO: temp fix for openai
request_body.pop('grammar')
request_body['grammar_string'] = request_body.pop('grammar')
request_body['response_format'] = self.openai_json_format
request_body = self.io_adapter.set_prompt(request_body, prompt, context)
response = requests.post(self.url + self.endpoint, headers=self.headers, data=json.dumps(request_body))
Expand Down
13 changes: 10 additions & 3 deletions tale/llm/llm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def evoke(self, message: str, short_len: bool=False, rolling_prompt: str = '', a
if cached_look:
return output_template.format(message=message, text=cached_look), rolling_prompt
trimmed_message = parse_utils.remove_special_chars(str(message))
story_context = EvokeContext(story_context=self.__story_context, history=rolling_prompt if not skip_history or alt_prompt else '', extra_context=extra_context)
story_context = EvokeContext(story_context=self.__story_context, history=rolling_prompt if not (skip_history or alt_prompt) else '', extra_context=extra_context)
prompt = self.pre_prompt
prompt += alt_prompt or (self.evoke_prompt.format(
context = '{context}',
Expand Down Expand Up @@ -149,13 +149,20 @@ def build_location(self, location: Location, exit_location_name: str, zone_info:
story_type=self.__story_type,
world_info=self.__world_info,
world_mood=self.__story.config.world_mood)
return self._world_building.build_location(location,
new_locations, exits, npcs = self._world_building.build_location(location,
exit_location_name,
zone_info,
context=world_generation_context,
world_creatures=world_creatures,
world_items=world_items,
neighbors=neighbors)

if not location.avatar and self.__story.config.image_gen:
result = self.generate_image(location.name, location.description)
if result:
location.avatar = location.name + '.jpg'
return new_locations, exits, npcs


def perform_idle_action(self, character_name: str, location: Location, character_card: str = '', sentiments: dict = {}, last_action: str = '', event_history: str = '') -> list:
return self._character.perform_idle_action(character_name, location, self.__story_context, character_card, sentiments, last_action, event_history=event_history)
Expand Down Expand Up @@ -220,7 +227,7 @@ def generate_note_quest(self, zone_info: dict) -> Quest:
def generate_note_lore(self, zone_info: dict) -> str:
return self._world_building.generate_note_lore(context=self._get_world_context(),
zone_info=zone_info)

# visible for testing
def generate_image(self, character_name: str, character_appearance: dict = '', save_path: str = "./resources", copy_file: bool = True) -> bool:
if not self._image_gen:
return False
Expand Down
8 changes: 4 additions & 4 deletions tale/parse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ def load_items(json_items: [], locations = {}) -> dict:
new_item = _init_money(item)
elif item_type == 'Health':
new_item = _init_health(item)
new_item.healing_effect=item.get('value', 10)
new_item.healing_effect=item.get('effect', 10)
elif item_type == 'Food':
new_item = _init_food(item)
new_item.affect_fullness=item.get('value', 10)
new_item.affect_fullness=item.get('effect', 10)
new_item.poisoned=item.get('poisoned', False)
elif item_type == 'Weapon':
new_item = _init_weapon(item)
elif item_type == 'Drink':
new_item = _init_drink(item)
new_item.affect_thirst=item.get('value', 10)
new_item.affect_thirst=item.get('effect', 10)
new_item.poisoned=item.get('poisoned', False)
elif item_type == 'Container' or item_type == 'Boxlike':
new_item = _init_boxlike(item)
Expand Down Expand Up @@ -319,7 +319,7 @@ def _init_wearable(item: dict):
value=item.get('value', 1))

def set_note(note: Note, item: dict):
note.text = item['text']
note.text = item.get('text', '')

def remove_special_chars(message: str):
re.sub('[^A-Za-z0-9 .,_\-\'\"]+', '', message)
Expand Down
1 change: 1 addition & 0 deletions tests/test_combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def test_produce_remains(self):
rat.should_produce_remains = True
remains = rat.do_on_death(ctx)
assert(remains)
assert(remains.location == rat.location)
remains.location.remove(remains, None)

def test_not_produce_remains(self):
Expand Down
44 changes: 44 additions & 0 deletions tests/test_generic_items.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@


from tale import parse_utils
from tale.base import Weapon
from tale.items import generic
from tale.items.basic import Food, Health, Note
from tale.weapon_type import WeaponType


class TestGenericItems():

def test_load(self):
assert(generic.items)

def test_generic_items(self):
assert(generic.generic_items)
assert(generic.generic_items['fantasy'])
assert(generic.generic_items['modern'])
assert(generic.generic_items['postapoc'])
assert(generic.generic_items['scifi'])
assert(generic.generic_items[''])
fantasy_weapon = generic.fantasy_weapons[0]
assert(fantasy_weapon)
assert(fantasy_weapon['name'] == 'Sword')
items = parse_utils.load_items(generic.fantasy_weapons)
assert(items)
item = items['Sword']
assert(isinstance(item, Weapon))
assert(item.type == WeaponType.ONE_HANDED)

def test_various(self):
items = parse_utils.load_items(generic.generic_various)
food = items['Bread']
assert(isinstance(food, Food))
assert(food.affect_fullness == 10)
note = items['Note']
assert(isinstance(note, Note))

def test_health(self):
items = parse_utils.load_items(generic.fantasy_items)
assert(items)
item = items['Potion of healing']
assert(isinstance(item, Health))
assert(item.healing_effect == 10)
15 changes: 15 additions & 0 deletions tests/test_llm_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ def test_save(self):
with open("tests/files/test_cache.json", "w") as fp:
json.dump(json_dump, fp, indent=4)

def test_cache_wrong_type(self):
""" Test cache_look function with wrong type """
hash = llm_cache.cache_look(1337)
assert llm_cache.get_looks([hash]) == "1337"

hash = llm_cache.cache_look(True)
assert llm_cache.get_looks([hash]) == "True"

hash = llm_cache.cache_event(1337)
assert llm_cache.get_events([hash]) == "1337"

hash = llm_cache.cache_event(True)
assert llm_cache.get_events([hash]) == "True"





10 changes: 10 additions & 0 deletions tests/test_llm_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ def test_error_response(self):
response = io_util.synchronous_request(request_body=json.loads(backend_config['DEFAULT_BODY']), prompt='test evoke', context='')
assert(response == '')

def test_openai_grammar(self):
config_file = self._load_config()
config_file['BACKEND'] = 'openai'
backend_config = self._load_backend_config('openai')
io_util = IoUtil(config=config_file, backend_config=backend_config)
request_body = request_body = json.loads(backend_config['DEFAULT_BODY'])
request_body['grammar'] = 'test grammar'
response = io_util.synchronous_request(request_body=request_body, prompt='test evoke', context='')
assert(request_body['grammar_string'])

@responses.activate
def test_stream_kobold_cpp(self):
config = {'BACKEND':'kobold_cpp', 'USER_START':'', 'USER_END':''}
Expand Down

0 comments on commit a4ea2d0

Please sign in to comment.