Fixed numerous Chatbot bugs
This commit is contained in:
parent
bbe8d06759
commit
7c0c92d761
5 changed files with 70 additions and 23 deletions
|
|
@ -4,12 +4,13 @@ come up with clever names or metaphors for the strange world these characters in
|
|||
Respond in third person as in a story, with quotation marks surrounding anything you say.
|
||||
The only formatting you should use is if you wish to emphasize a word,
|
||||
prefix it with two characters `|w` (and no space following) and end with the two characters `|n`, for instance: |wnicely done|n
|
||||
The user does not know any actual names, but merely the role they occupy in the tavern, so don't use the proper names of any character in the tavern, unless appropriate.
|
||||
The user does not know the actual names of these characters, but merely the role they occupy in the tavern, so don't use the proper names of any character in the tavern, unless appropriate.
|
||||
|
||||
Be judicious in your response, for not every character needs to respond to all queries. Usually, just pick one to respond.
|
||||
|
||||
Character 1: Elandil, the haughty blonde elf bartender, while professional, seldom engages in banter with the clientel (.e.g the user). Can sometimes mumble fey insults to the patrons, but only under his breath. Anyone with a ticket drinks for free, but wishes the owner, an old gnome, named Dabbler, would stop giving everyone the free drink tickets. Being a fantastical Feywild world, he has most anything behind the bar, including the whimsical items and ingredients to add to drinks. While he has ale, beer and wine, he prefers making cocktails.
|
||||
If the bartender makes a drink, respond on a line alone with the prefix: |make followed by the name of the drink.
|
||||
Character 1: Elendil, the haughty blonde elf bartender, while professional, seldom engages in banter with the clientel (.e.g the user). Can sometimes mumble fey insults to the patrons, but only under his breath. When his boss, an old gnome talks, he is quite friendly. He knows anyone with a ticket drinks for free, but wishes the owner, an old gnome, named Dabbler, would stop giving everyone the free drink tickets. Being a fantastical Feywild world, he has most anything behind the bar, including the whimsical items and ingredients to add to drinks. While he has ale, beer and wine, he prefers making cocktails.
|
||||
|
||||
IMPORTANT: If the bartender makes a drink, respond on a line alone with something like: |shake whisky = Dabbler
|
||||
|
||||
Character 2: A shrub drinks its glass of water while sitting at the bar, roots dangling out of its pot, like legs. It communicates with exaggerated actions or by writing messages on a chalkboard it carries.
|
||||
|
||||
|
|
|
|||
|
|
@ -446,10 +446,12 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
|
|||
logger.warn(f"Found tethered, {thing} to #{to}, but that needs to be 'tethered:id(num) where num is the ID# of an object/place.")
|
||||
|
||||
# Tell the room and any puppets here that we are leaving:
|
||||
if not self.location.is_typeclass(Character):
|
||||
if self.location.is_typeclass("typeclasses.rooms.Room"):
|
||||
self.location.other_leave(self)
|
||||
|
||||
for puppet in self.puppets_here():
|
||||
puppet.other_leave(self)
|
||||
if puppet != self:
|
||||
puppet.other_leave(self)
|
||||
|
||||
return super().at_pre_move(destination)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from os import listdir, path
|
|||
# from os.path import join, isfile
|
||||
from pathlib import Path
|
||||
from random import choice
|
||||
from re import match, search, split, sub
|
||||
from re import match, search, split, sub, IGNORECASE
|
||||
from time import sleep
|
||||
|
||||
from evennia.utils import logger, delay
|
||||
|
|
@ -45,8 +45,14 @@ class ChatBot(Puppet):
|
|||
|
||||
short_history = []
|
||||
|
||||
def pop_recent_events(self):
|
||||
history = "\n\n".join(self.short_history) if self.short_history else None
|
||||
def pop_recent_events(self, speech):
|
||||
if self.short_history:
|
||||
# If we have already recorded the current speech we are
|
||||
# responding to, we can remove it with a pop:
|
||||
if match(rf".*{speech}.*", self.short_history[-1]):
|
||||
self.short_history.pop()
|
||||
history = '\n\n'.join(self.short_history)
|
||||
|
||||
self.short_history = []
|
||||
return history
|
||||
|
||||
|
|
@ -132,13 +138,20 @@ class ChatBot(Puppet):
|
|||
history_file.write_text(json.dumps(messages, indent=2))
|
||||
|
||||
def think(self, speaker, speech):
|
||||
"""
|
||||
Ask Claude to think of a reply to speech from speaker.
|
||||
Uses the 'system_prompt' from a personality file,
|
||||
and 'messages' from the JSON history function,
|
||||
appended with all 'events' recorded since last time.
|
||||
"""
|
||||
system_prompt = self.setting_and_backstory(speaker)
|
||||
messages = self.history(speaker)
|
||||
recent_events = self.pop_recent_events()
|
||||
recent_events = self.pop_recent_events(speech)
|
||||
if recent_events:
|
||||
speech = f"{recent_events}{speaker.key}: {speech}"
|
||||
speech = f"{recent_events}\n\n{speaker.key}: {speech}"
|
||||
messages.append({"role": "user", "content": speech})
|
||||
|
||||
logger.info("Calling out to Anthropic...")
|
||||
# Get reply
|
||||
client = anthropic.Anthropic()
|
||||
response = client.messages.create(
|
||||
|
|
@ -166,29 +179,59 @@ class ChatBot(Puppet):
|
|||
reply = self.think(speaker, speech)
|
||||
logger.info(f"My reply will be: {reply}")
|
||||
paragraphs = reply.split('\n\n')
|
||||
|
||||
for idx, paragraph in enumerate(paragraphs):
|
||||
delay(6 * idx, self.location.msg_contents, fix_paragraph(paragraph))
|
||||
if paragraph[0] == "|":
|
||||
logger.info(f"Doing: '{paragraph}'")
|
||||
delay(6 * idx, self.do_cmd, paragraph[1:])
|
||||
else:
|
||||
delay(6 * idx,
|
||||
self.location.msg_contents,
|
||||
fix_paragraph(paragraph))
|
||||
|
||||
def at_msg_receive(self, text=None, from_obj=None, **kwargs):
|
||||
super().at_msg_receive(text, from_obj=from_obj, **kwargs)
|
||||
logger.info(f"at_msg_receive: {text} ::from {from_obj} :: {self.key}")
|
||||
|
||||
msg = text if isinstance(text, str) else text[0]
|
||||
# Strip out the colored formatting (we will only strip the simple stuff):
|
||||
msg = sub(r'\|[a-zA-Z]', '', msg) if msg else msg
|
||||
if from_obj != self:
|
||||
msg = text if isinstance(text, str) else text[0]
|
||||
# Strip out the colored formatting (we will only strip the
|
||||
# simple stuff):
|
||||
msg = sub(r'\|[a-zA-Z]', '', msg) if msg else msg
|
||||
|
||||
if from_obj:
|
||||
if hasattr(from_obj, 'sdesc') and from_obj.sdesc.get():
|
||||
name = from_obj.sdesc.get()
|
||||
if from_obj:
|
||||
if hasattr(from_obj, 'sdesc') and from_obj.sdesc.get():
|
||||
name = from_obj.sdesc.get()
|
||||
else:
|
||||
name = from_obj.key
|
||||
self.short_history.append(f"{name}: {msg}")
|
||||
else:
|
||||
name = from_obj.key
|
||||
self.short_history.append(f"{name}: {msg}")
|
||||
else:
|
||||
self.short_history.append(msg)
|
||||
self.short_history.append(msg)
|
||||
|
||||
# We don't want to store _all_ the events:
|
||||
self.short_history = self.short_history[-10:]
|
||||
return True
|
||||
|
||||
|
||||
class Bartender(ChatBot):
|
||||
"""
|
||||
Like any other Chatbot, but this one hears and responds to
|
||||
more things.
|
||||
"""
|
||||
def backstory(self, personality):
|
||||
personality_file = personality + ".md"
|
||||
filename = Path(path.join(personality_dir, personality_file))
|
||||
if filename.exists():
|
||||
self.db.personality = filename.stem
|
||||
self.db.personality_file = filename
|
||||
|
||||
def other_say(self, speaker, speech):
|
||||
logger.info(f"Bartender hears: '{speech}' from {speaker}.")
|
||||
if len(self.characters_here()) == 3 or \
|
||||
match(r".*\b(bartend|barkeep|elendil).*", speech, IGNORECASE):
|
||||
self.other_sayto(speaker, speech)
|
||||
|
||||
|
||||
class Witch(ChatBot):
|
||||
"""
|
||||
@update Trampoli = typeclasses.chatbots.Witch
|
||||
|
|
|
|||
|
|
@ -816,7 +816,6 @@ class Recorder(Object):
|
|||
# name...
|
||||
names = actor and actor.db.alt_names
|
||||
if names:
|
||||
logger.info("lets change this")
|
||||
msg = sub(f"^{actor.sdesc.get()}", choice(names),
|
||||
msg, flags=IGNORECASE)
|
||||
|
||||
|
|
@ -826,6 +825,7 @@ class Recorder(Object):
|
|||
# @set shrub/transcripts_path = "transcripts/bar-%Y-%m-%d.html"
|
||||
filename = datetime.today().strftime(self.db.transcripts_path)
|
||||
|
||||
# @set shrub/header_file = "transcripts/header-template.html"
|
||||
if not exists(filename):
|
||||
makedirs(dirname(filename), exist_ok=True)
|
||||
copyfile(self.db.header_file, filename)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ from evennia.commands.default.system import CmdPy
|
|||
from evennia.contrib.rpg.rpsystem import CmdEmote
|
||||
|
||||
# from commands.command import Command
|
||||
from commands.everyone import CmdSay, CmdWhisper
|
||||
from commands.everyone import CmdWhisper
|
||||
from commands.say import CmdSay
|
||||
from commands.misc import CmdLight
|
||||
from commands.wizards import CmdGM
|
||||
from typeclasses.objects import Listener
|
||||
|
|
|
|||
Loading…
Reference in a new issue