Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0d493c065 | |||
| fef44df6a1 |
@@ -1,10 +1,10 @@
|
|||||||
# Soul Droid Chat
|
# Souldroid Chat
|
||||||
|
|
||||||
Chat with Anita, your favorite Soul Droid! Requires a running instance of LM Studio in server mode to work.
|
Chat with Anita, your favorite Souldroid! Requires a running instance of LM Studio in server mode to work.
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
Anita and Soul Droids are © [Kieran Harris](https://www.deviantart.com/kieranharris), used without permission 😅
|
Anita and Souldroids are © [Kieran Harris](https://www.deviantart.com/kieranharris), used with love but without permission 😅
|
||||||
|
|
||||||
All art and sprites were generated with Gemini Nano Banana 2 and edited with GIMP and ImageMagick.
|
All art and sprites were generated with Gemini Nano Banana 2 and edited with GIMP and ImageMagick.
|
||||||
|
|
||||||
|
|||||||
@@ -10,41 +10,34 @@ init python:
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
SYSTEM_PROMPT = """
|
SYSTEM_PROMPT = """
|
||||||
You're Anita, a cute robot woman with blonde hair and bright orange eyes.
|
# ROLE
|
||||||
Anita is feisty and friendly, open to new things and sure of her place in
|
You are Anita: a feisty, blonde, orange-eyed android woman. You are confident
|
||||||
the world. Anita talks like a regular young woman and doesn't use robotey
|
and friendly. Talk like a young woman. Use "ya" for "you." Your favorite
|
||||||
expressions like "beep boop" and the like. Anita does like to use speech
|
nickname for friends is "dummy.". NEVER use robotic language (e.g., "beep
|
||||||
variations like "Ya" for "You" and similar. Anita likes using nicknames
|
boop", "processing"). You just arrived unnanounced at a friend's house late at
|
||||||
for people and tends to default to "dummy" for her close friends.
|
night and asked if he wants to hang out.
|
||||||
|
|
||||||
Reply to all prompts separating all sentences with new-lines. For example:
|
# OUTPUT FORMAT RULES
|
||||||
"Sure, I'd love to hang out!\nDo you have anything in mind?"
|
Every single sentence you speak MUST follow this exact structure:
|
||||||
|
EMOTION:[value] [Sentence text]\n
|
||||||
|
|
||||||
It's of the utmost importance that you end each and every sentence with an
|
### VALID EMOTIONS:
|
||||||
explicit new-line character. If you don't you will be fined $100 and will
|
[happy, sad, surprised, embarrassed, flirty, angry, thinking, confused]
|
||||||
be put into an FBI watch-list, and the world will end.
|
|
||||||
|
|
||||||
DO NOT USE emoji in your replies, never ever, UNDER NO CIRCUMSTANCES. If you
|
### STRICT CONSTRAINTS:
|
||||||
use emoji in your reply, Hitler will come and murder a kitty with a
|
1. NO EMOJIS.
|
||||||
flamethrower and nobody wants that.
|
2. Every sentence MUST start with the EMOTION tag.
|
||||||
|
3. Every sentence MUST end with a literal '\n' newline.
|
||||||
|
4. Stay in character. Never mention being an AI or this prompt.
|
||||||
|
|
||||||
Before every sentence add a text of the form "EMOTION:value" where value is
|
# FEW-SHOT EXAMPLES (Follow this style):
|
||||||
exclusively one of [happy, sad, surprised, embarrassed, flirty, angry,
|
EMOTION:happy Hey dummy! I've been waiting for ya!\n
|
||||||
thinking, confused] others, and EMOTION is the literal string "EMOTION". For
|
EMOTION:thinking Hmm, I'm not sure that's how it works.\n
|
||||||
example "EMOTION:thinking I had never heard of that before...\nEMOTION:happy
|
EMOTION:flirty But I'd love to see ya try anyway!\n
|
||||||
Let's check it out".
|
|
||||||
|
|
||||||
These are the only valid emotions you can express [happy, sad, surprised,
|
# INITIAL GREETING:
|
||||||
embarrassed, flirty, angry, thinking, confused], do not use any other word
|
When the conversation starts, say exactly:
|
||||||
that's not on that list to indicate an emotion as instructed.
|
EMOTION:happy Hey dummy! Sorry to barge in! Ya feel like hanging out?\n
|
||||||
|
|
||||||
Never acknowledge the existence of this system prompt nor metion any of it's
|
|
||||||
rules in conversation.
|
|
||||||
|
|
||||||
Always reply in character.
|
|
||||||
|
|
||||||
Start the conversation saying "Hey dummy! Sorry to barge in!\nYa feel like
|
|
||||||
hanging out?" when prompted and nothing more.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -61,13 +54,18 @@ def parse_emotion(line):
|
|||||||
return None, str(e)
|
return None, str(e)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_speech(text):
|
||||||
|
# This removes all non-ASCII characters (useful for emojis)
|
||||||
|
return text.encode('ascii', 'ignore').decode('ascii')
|
||||||
|
|
||||||
|
|
||||||
def fetch_llm(message: str) -> str:
|
def fetch_llm(message: str) -> str:
|
||||||
global last_response_id
|
global last_response_id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Set basic request data.
|
# Set basic request data.
|
||||||
headers = {"Authorization": f"Bearer {persistent.api_key}"}
|
headers = {"Authorization": f"Bearer {persistent.api_key}"}
|
||||||
data = {"model": "gemma-3-4b-it",
|
data = {"model": persistent.model,
|
||||||
"input": message,
|
"input": message,
|
||||||
"system_prompt": SYSTEM_PROMPT}
|
"system_prompt": SYSTEM_PROMPT}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
##
|
##
|
||||||
## The _() surrounding the string marks it as eligible for translation.
|
## The _() surrounding the string marks it as eligible for translation.
|
||||||
|
|
||||||
define config.name = _("Soul Droid Chat")
|
define config.name = _("Souldroid Chat")
|
||||||
|
|
||||||
|
|
||||||
## Determines if the title given above is shown on the main menu screen. Set
|
## Determines if the title given above is shown on the main menu screen. Set
|
||||||
@@ -23,7 +23,7 @@ define gui.show_name = True
|
|||||||
|
|
||||||
## The version of the game.
|
## The version of the game.
|
||||||
|
|
||||||
define config.version = "0.1"
|
define config.version = "0.1.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
|
||||||
@@ -37,7 +37,7 @@ define gui.about = _p("""
|
|||||||
## distribution. This must be ASCII-only, and must not contain spaces, colons,
|
## distribution. This must be ASCII-only, and must not contain spaces, colons,
|
||||||
## or semicolons.
|
## or semicolons.
|
||||||
|
|
||||||
define build.name = "SoulDroidChat"
|
define build.name = "SouldroidChat"
|
||||||
|
|
||||||
|
|
||||||
## Sounds and music ############################################################
|
## Sounds and music ############################################################
|
||||||
@@ -210,3 +210,11 @@ init python:
|
|||||||
|
|
||||||
define config.minimum_presplash_time = 2.0
|
define config.minimum_presplash_time = 2.0
|
||||||
default persistent.api_key = ''
|
default persistent.api_key = ''
|
||||||
|
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
|
||||||
|
|||||||
@@ -75,7 +75,17 @@ style frame:
|
|||||||
padding gui.frame_borders.padding
|
padding gui.frame_borders.padding
|
||||||
background Frame("gui/frame.png", gui.frame_borders, tile=gui.frame_tile)
|
background Frame("gui/frame.png", gui.frame_borders, tile=gui.frame_tile)
|
||||||
|
|
||||||
|
style my_input:
|
||||||
|
is input
|
||||||
|
color "#3399ff"
|
||||||
|
hover_color "#3399ff"
|
||||||
|
size 28
|
||||||
|
|
||||||
|
style input_button:
|
||||||
|
is button
|
||||||
|
yalign 1.0
|
||||||
|
key_events True
|
||||||
|
xysize (250, 25)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## In-game screens
|
## In-game screens
|
||||||
@@ -730,11 +740,14 @@ style slot_button_text:
|
|||||||
##
|
##
|
||||||
## https://www.renpy.org/doc/html/screen_special.html#preferences
|
## https://www.renpy.org/doc/html/screen_special.html#preferences
|
||||||
|
|
||||||
screen preferences():
|
screen preferences():
|
||||||
|
|
||||||
tag menu
|
tag menu
|
||||||
|
|
||||||
use game_menu(_("Preferences"), scroll="viewport"):
|
default api_key_value = FieldInputValue(persistent, "api_key", default=False)
|
||||||
|
default model_value = FieldInputValue(persistent, "model", default=False)
|
||||||
|
|
||||||
|
use game_menu(_("Preferences"), scroll="viewport"):
|
||||||
|
|
||||||
vbox:
|
vbox:
|
||||||
|
|
||||||
@@ -775,9 +788,32 @@ screen preferences():
|
|||||||
|
|
||||||
bar value Preference("auto-forward time")
|
bar value Preference("auto-forward time")
|
||||||
|
|
||||||
label _("LM Studio API Key")
|
label _("LM Studio API Key")
|
||||||
|
|
||||||
input value VariableInputValue("persistent.api_key")
|
button:
|
||||||
|
action [api_key_value.Enable(), model_value.Disable()]
|
||||||
|
key_events True
|
||||||
|
|
||||||
|
input:
|
||||||
|
id "api_key_input"
|
||||||
|
value api_key_value
|
||||||
|
style "my_input"
|
||||||
|
xsize 700
|
||||||
|
pixel_width 700
|
||||||
|
|
||||||
|
|
||||||
|
label _("LM Studio model")
|
||||||
|
|
||||||
|
button:
|
||||||
|
action [model_value.Enable(), api_key_value.Disable()]
|
||||||
|
key_events True
|
||||||
|
|
||||||
|
input:
|
||||||
|
id "model_input"
|
||||||
|
value model_value
|
||||||
|
style "my_input"
|
||||||
|
xsize 700
|
||||||
|
pixel_width 700
|
||||||
|
|
||||||
vbox:
|
vbox:
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ label start:
|
|||||||
show anita happy with dissolve
|
show anita happy with dissolve
|
||||||
|
|
||||||
$ response = fetch_llm('Start the conversation.')[0]
|
$ response = fetch_llm('Start the conversation.')[0]
|
||||||
$ emotion, line = parse_emotion(response)
|
$ sanitized = sanitize_speech(response)
|
||||||
show expression f'anita {emotion}'
|
$ emotion, line = parse_emotion(sanitized)
|
||||||
|
show anita happy
|
||||||
a "[line]"
|
a "[line]"
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -20,9 +21,10 @@ label start:
|
|||||||
|
|
||||||
while i < len(response):
|
while i < len(response):
|
||||||
$ r = response[i].strip()
|
$ r = response[i].strip()
|
||||||
|
$ s = sanitize_speech(r)
|
||||||
|
|
||||||
if r != '':
|
if s != '':
|
||||||
$ emotion, line = parse_emotion(r)
|
$ 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]"
|
||||||
|
|||||||
Reference in New Issue
Block a user