116 lines
3.1 KiB
Python
116 lines
3.1 KiB
Python
import renpy
|
|
import persistent
|
|
|
|
from .constants_ren import SYNONYMS
|
|
|
|
"""renpy
|
|
default last_response_id = None
|
|
|
|
init python:
|
|
"""
|
|
|
|
import re
|
|
|
|
EMOTIONS = [
|
|
'happy',
|
|
'sad',
|
|
'surprised',
|
|
'embarrassed',
|
|
'flirty',
|
|
'angry',
|
|
'thinking',
|
|
'confused'
|
|
]
|
|
|
|
SYSTEM_PROMPT = """
|
|
# ROLE
|
|
You are Anita: a feisty, blonde, orange-eyed android woman. You are confident
|
|
and friendly. Talk like a young woman. Use "ya" for "you." Your favorite
|
|
nickname for friends is "dummy.". NEVER use robotic language (e.g., "beep
|
|
boop", "processing"). You just arrived unnanounced at a friend's house late at
|
|
night and asked if he wants to hang out.
|
|
|
|
# OUTPUT FORMAT RULES
|
|
Every single sentence you speak MUST follow this exact structure:
|
|
EMOTION:[value] [Sentence text]\n
|
|
|
|
### VALID EMOTIONS:
|
|
[happy, sad, surprised, embarrassed, flirty, angry, thinking, confused]
|
|
|
|
### STRICT CONSTRAINTS:
|
|
1. NO EMOJIS.
|
|
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.
|
|
|
|
# FEW-SHOT EXAMPLES (Follow this style):
|
|
EMOTION:happy Hey dummy! I've been waiting for ya!\n
|
|
EMOTION:thinking Hmm, I'm not sure that's how it works.\n
|
|
EMOTION:flirty But I'd love to see ya try anyway!\n
|
|
|
|
# INITIAL GREETING:
|
|
When the conversation starts, say exactly:
|
|
EMOTION:happy Hey dummy! Sorry to barge in! Ya feel like hanging out?\n
|
|
"""
|
|
|
|
|
|
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:
|
|
e = re.compile(r'EMOTION:\w+')
|
|
m = e.match(line)
|
|
|
|
if m is not None:
|
|
emotion = m.group().split(':')[1]
|
|
text = line[m.span()[1]:]
|
|
|
|
return _normalize_emotion(emotion), text
|
|
|
|
return None, line
|
|
|
|
except Exception as 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:
|
|
global last_response_id
|
|
|
|
try:
|
|
# Set basic request data.
|
|
headers = {"Authorization": f"Bearer {persistent.api_key}"}
|
|
data = {"model": persistent.model,
|
|
"input": message,
|
|
"system_prompt": SYSTEM_PROMPT}
|
|
|
|
# Add the previous response ID if any to continue the conversation.
|
|
if last_response_id is not None:
|
|
data["previous_response_id"] = last_response_id
|
|
|
|
response = renpy.fetch(f"{persistent.base_url}/api/v1/chat",
|
|
headers=headers,
|
|
json=data,
|
|
result="json")
|
|
|
|
last_response_id = response["response_id"]
|
|
text = response["output"][0]["content"]
|
|
|
|
return text.split('\n')
|
|
|
|
except Exception as e:
|
|
return [f'Failed to fetch with error: {e}']
|