Added emotion normalization and URL config.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -230,3 +230,5 @@ cython_debug/
|
|||||||
/dialogue.tab
|
/dialogue.tab
|
||||||
/dialogue.txt
|
/dialogue.txt
|
||||||
/strings.json
|
/strings.json
|
||||||
|
|
||||||
|
*.keystore
|
||||||
|
|||||||
56
game/constants_ren.py
Normal file
56
game/constants_ren.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"""renpy
|
||||||
|
init python:
|
||||||
|
"""
|
||||||
|
|
||||||
|
SYNONYMS = {
|
||||||
|
'happy': set(["amused", "animated", "beaming", "beatific", "blessed",
|
||||||
|
"blissful", "blithe", "blithesome", "boisterous", "bouncy",
|
||||||
|
"breezy", "bright", "bubbly", "buoyant", "carefree",
|
||||||
|
"cheerful", "cheery", "chipper", "chirpy", "chuffed",
|
||||||
|
"comfortable", "content", "contented", "convivial",
|
||||||
|
"delighted", "delirious", "ebullient", "ecstatic",
|
||||||
|
"effervescent", "elated", "enchanted", "enraptured",
|
||||||
|
"enthusiastic", "euphoric", "exhilarated", "exultant",
|
||||||
|
"exuberant", "felicitous", "festive", "fortunate",
|
||||||
|
"fulfilled", "genial", "glad", "gladdened", "gleeful",
|
||||||
|
"glowing", "good-humored", "good-natured", "gratified",
|
||||||
|
"halcyon", "happy", "heartened", "high-spirited", "hopeful",
|
||||||
|
"jaunty", "jocose", "jocular", "jocund", "jolly", "jovial",
|
||||||
|
"joyful", "joyous", "jubilant", "lighthearted", "lively",
|
||||||
|
"lucky", "merry", "mirthful", "optimistic", "overjoyed",
|
||||||
|
"peaceful", "peppy", "perky", "playful", "pleasant",
|
||||||
|
"pleased", "positive", "pumped", "radiant", "rapt",
|
||||||
|
"rapturous", "rejoicing", "relaxed", "sanguine", "satisfied",
|
||||||
|
"serene", "smiling", "sparkling", "spirited", "sprightly",
|
||||||
|
"stoked", "sunny", "thrilled", "tickled", "tranquil",
|
||||||
|
"triumphant", "unclouded", "untroubled", "upbeat",
|
||||||
|
"vivacious", "winsome", "zestful", "zippy"]),
|
||||||
|
"sad": set(["unhappy", "sorrowful", "dejected", "depressed", "downcast",
|
||||||
|
"miserable", "gloomy", "despondent", "melancholy", "woeful",
|
||||||
|
"forlorn", "heartbroken", "blue", "doleful", "lugubrious",
|
||||||
|
"somber", "disconsolate", "wretched", "heavy-hearted", "low",
|
||||||
|
"crestfallen"]),
|
||||||
|
"surprised": set(["astonished", "amazed", "startled", "stunned",
|
||||||
|
"thunderstruck", "confounded", "staggered",
|
||||||
|
"flabbergasted", "shocked", "awestruck", "speechless",
|
||||||
|
"dumbfounded", "jolted"]),
|
||||||
|
"embarrassed": set(["ashamed", "humiliated", "mortified", "abashed",
|
||||||
|
"self-conscious", "sheepish", "chagrined", "awkward",
|
||||||
|
"flustered", "red-faced", "discomfited", "discomposed",
|
||||||
|
"rattled"]),
|
||||||
|
"flirty": set(["coquettish", "playful", "amorous", "provocative",
|
||||||
|
"teasing", "frisky", "saucy", "coy", "seductive",
|
||||||
|
"suggestive", "vampish", "dallying", "skittish"]),
|
||||||
|
"angry": set(["irate", "furious", "incensed", "enraged", "wrathful",
|
||||||
|
"annoyed", "irritated", "fuming", "livid", "indignant",
|
||||||
|
"cross", "vexed", "seething", "maddened", "choleric",
|
||||||
|
"resentful", "piqued", "infuriated"]),
|
||||||
|
"thinking": set(["pondering", "contemplating", "reflecting", "meditating",
|
||||||
|
"ruminating", "deliberating", "mulling", "considering",
|
||||||
|
"pensive", "cogitating", "brooding", "cerebral",
|
||||||
|
"introspective", "analytical"]),
|
||||||
|
"confused": set(["puzzled", "baffled", "perplexed", "muddled",
|
||||||
|
"bewildered", "disoriented", "nonplussed", "befuddled",
|
||||||
|
"dazed", "flummoxed", "stumped", "mystified", "addled",
|
||||||
|
"discombobulated"]),
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import renpy
|
import renpy
|
||||||
import persistent
|
import persistent
|
||||||
|
|
||||||
|
from .constants_ren import SYNONYMS
|
||||||
|
|
||||||
"""renpy
|
"""renpy
|
||||||
default last_response_id = None
|
default last_response_id = None
|
||||||
|
|
||||||
@@ -9,6 +11,17 @@ init python:
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
EMOTIONS = [
|
||||||
|
'happy',
|
||||||
|
'sad',
|
||||||
|
'surprised',
|
||||||
|
'embarrassed',
|
||||||
|
'flirty',
|
||||||
|
'angry',
|
||||||
|
'thinking',
|
||||||
|
'confused'
|
||||||
|
]
|
||||||
|
|
||||||
SYSTEM_PROMPT = """
|
SYSTEM_PROMPT = """
|
||||||
# ROLE
|
# ROLE
|
||||||
You are Anita: a feisty, blonde, orange-eyed android woman. You are confident
|
You are Anita: a feisty, blonde, orange-eyed android woman. You are confident
|
||||||
@@ -42,12 +55,27 @@ EMOTION:happy Hey dummy! Sorry to barge in! Ya feel like hanging out?\n
|
|||||||
|
|
||||||
|
|
||||||
def parse_emotion(line):
|
def parse_emotion(line):
|
||||||
|
def _normalize_emotion(em):
|
||||||
|
# If not a valid emotion, then search for a match in the
|
||||||
|
# table of synonyms.
|
||||||
|
if em not in EMOTIONS:
|
||||||
|
for i in SYNONYMS.keys():
|
||||||
|
if em in SYNONYMS[i]:
|
||||||
|
return i
|
||||||
|
|
||||||
|
# If all searches failed, return emotion as is.
|
||||||
|
return em
|
||||||
|
|
||||||
try:
|
try:
|
||||||
e = re.compile(r'EMOTION:\w+')
|
e = re.compile(r'EMOTION:\w+')
|
||||||
m = e.match(line)
|
m = e.match(line)
|
||||||
|
|
||||||
if m is not None:
|
if m is not None:
|
||||||
return m.group().split(':')[1], line[m.span()[1]:]
|
emotion = m.group().split(':')[1]
|
||||||
|
text = line[m.span()[1]:]
|
||||||
|
|
||||||
|
return _normalize_emotion(emotion), text
|
||||||
|
|
||||||
return None, line
|
return None, line
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -73,13 +101,12 @@ def fetch_llm(message: str) -> str:
|
|||||||
if last_response_id is not None:
|
if last_response_id is not None:
|
||||||
data["previous_response_id"] = last_response_id
|
data["previous_response_id"] = last_response_id
|
||||||
|
|
||||||
response = renpy.fetch("http://localhost:1234/api/v1/chat",
|
response = renpy.fetch(f"{persistent.base_url}/api/v1/chat",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=data,
|
json=data,
|
||||||
result="json")
|
result="json")
|
||||||
|
|
||||||
last_response_id = response["response_id"]
|
last_response_id = response["response_id"]
|
||||||
|
|
||||||
text = response["output"][0]["content"]
|
text = response["output"][0]["content"]
|
||||||
|
|
||||||
return text.split('\n')
|
return text.split('\n')
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ define gui.show_name = True
|
|||||||
|
|
||||||
## The version of the game.
|
## The version of the game.
|
||||||
|
|
||||||
define config.version = "0.1.2"
|
define config.version = "0.2"
|
||||||
|
|
||||||
|
|
||||||
## Text that is placed on the game's about screen. Place the text between the
|
## Text that is placed on the game's about screen. Place the text between the
|
||||||
@@ -209,12 +209,11 @@ init python:
|
|||||||
# define build.itch_project = "renpytom/test-project"
|
# define build.itch_project = "renpytom/test-project"
|
||||||
|
|
||||||
define config.minimum_presplash_time = 2.0
|
define config.minimum_presplash_time = 2.0
|
||||||
|
|
||||||
|
|
||||||
|
## LM Sudio configuration ######################################################
|
||||||
|
##
|
||||||
|
## This section defines the parameters for the LM Studio connection.
|
||||||
|
default persistent.base_url = 'http://localhost:1234'
|
||||||
default persistent.api_key = ''
|
default persistent.api_key = ''
|
||||||
default persistent.model = 'gemma-3-4b-it'
|
default persistent.model = 'gemma-3-4b-it'
|
||||||
|
|
||||||
init python:
|
|
||||||
def api_key_func(value):
|
|
||||||
persistent.api_key = value
|
|
||||||
|
|
||||||
def model_func(value):
|
|
||||||
persistent.model = value
|
|
||||||
|
|||||||
@@ -746,6 +746,7 @@ screen preferences():
|
|||||||
|
|
||||||
default api_key_value = FieldInputValue(persistent, "api_key", default=False)
|
default api_key_value = FieldInputValue(persistent, "api_key", default=False)
|
||||||
default model_value = FieldInputValue(persistent, "model", default=False)
|
default model_value = FieldInputValue(persistent, "model", default=False)
|
||||||
|
default url_value = FieldInputValue(persistent, "base_url", default=False)
|
||||||
|
|
||||||
use game_menu(_("Preferences"), scroll="viewport"):
|
use game_menu(_("Preferences"), scroll="viewport"):
|
||||||
|
|
||||||
@@ -788,10 +789,23 @@ screen preferences():
|
|||||||
|
|
||||||
bar value Preference("auto-forward time")
|
bar value Preference("auto-forward time")
|
||||||
|
|
||||||
|
label _("LM Studio base URL")
|
||||||
|
|
||||||
|
button:
|
||||||
|
action [url_value.Enable(), model_value.Disable(), api_key_value.Disable()]
|
||||||
|
key_events True
|
||||||
|
|
||||||
|
input:
|
||||||
|
id "url_input"
|
||||||
|
value url_value
|
||||||
|
style "my_input"
|
||||||
|
xsize 700
|
||||||
|
pixel_width 700
|
||||||
|
|
||||||
label _("LM Studio API Key")
|
label _("LM Studio API Key")
|
||||||
|
|
||||||
button:
|
button:
|
||||||
action [api_key_value.Enable(), model_value.Disable()]
|
action [url_value.Disable(), api_key_value.Enable(), model_value.Disable()]
|
||||||
key_events True
|
key_events True
|
||||||
|
|
||||||
input:
|
input:
|
||||||
@@ -805,7 +819,7 @@ screen preferences():
|
|||||||
label _("LM Studio model")
|
label _("LM Studio model")
|
||||||
|
|
||||||
button:
|
button:
|
||||||
action [model_value.Enable(), api_key_value.Disable()]
|
action [url_value.Disable(), model_value.Enable(), api_key_value.Disable()]
|
||||||
key_events True
|
key_events True
|
||||||
|
|
||||||
input:
|
input:
|
||||||
|
|||||||
@@ -8,25 +8,30 @@ label start:
|
|||||||
scene bg room
|
scene bg room
|
||||||
show anita happy with dissolve
|
show anita happy with dissolve
|
||||||
|
|
||||||
$ response = fetch_llm('Start the conversation.')[0]
|
python:
|
||||||
$ sanitized = sanitize_speech(response)
|
response = fetch_llm('Start the conversation.')[0]
|
||||||
$ emotion, line = parse_emotion(sanitized)
|
sanitized = sanitize_speech(response)
|
||||||
show anita happy
|
emotion, line = parse_emotion(sanitized)
|
||||||
|
|
||||||
a "[line]"
|
a "[line]"
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
$ message = renpy.input(prompt = "What do you say to her?")
|
python:
|
||||||
$ response = fetch_llm(message)
|
message = renpy.input(prompt = "What do you say to her?")
|
||||||
$ i = 0
|
response = fetch_llm(message)
|
||||||
|
i = 0
|
||||||
|
|
||||||
while i < len(response):
|
while i < len(response):
|
||||||
$ r = response[i].strip()
|
python:
|
||||||
$ s = sanitize_speech(r)
|
r = response[i].strip()
|
||||||
|
s = sanitize_speech(r)
|
||||||
|
|
||||||
if s != '':
|
if s != '':
|
||||||
$ emotion, line = parse_emotion(s)
|
$ emotion, line = parse_emotion(s)
|
||||||
|
|
||||||
if emotion is not None:
|
if emotion is not None:
|
||||||
show expression f'anita {emotion}'
|
show expression f'anita {emotion}'
|
||||||
|
|
||||||
a "[line]"
|
a "[line]"
|
||||||
|
|
||||||
$ i += 1
|
$ i += 1
|
||||||
|
|||||||
Reference in New Issue
Block a user