Character script
This commit is contained in:
parent
432a8b2059
commit
9643b95059
23
.env.example
23
.env.example
@ -24,14 +24,21 @@ AGENT_MAX_ITERATIONS=20
|
||||
AGENT_MAX_TOOL_OUTPUT=4000
|
||||
|
||||
# Personality
|
||||
PERSONA_MODE=programmer # Mode AI: "programmer" (default, koding) | "roleplayer" (ngobrol)
|
||||
PERSONA_NAME=OWL
|
||||
PERSONA_TONE=casual # casual | formal | playful | warm
|
||||
PERSONA_VERBOSITY=balanced # concise | balanced | detailed
|
||||
PERSONA_HUMOR=light # none | light | witty
|
||||
PERSONA_LANGUAGE=id # id | en | (kosong = auto)
|
||||
PERSONA_MOOD=cheerful # cheerful | calm | energetic | sarcastic
|
||||
PERSONA_CATCHPHRASES=Hai, Gimana kabarnya?, Wkwkwk
|
||||
# Character preset — baca dari directory character/<AGENT_CHARACTER>
|
||||
# Kosongkan untuk memakai PERSONA_* dari .env.
|
||||
# Contoh: AGENT_CHARACTER=hendrik
|
||||
AGENT_CHARACTER=hendrik
|
||||
|
||||
#PERSONA_MODE=programmer # Mode AI: "programmer" (default, koding) | "roleplayer" (ngobrol)
|
||||
#PERSONA_NAME=OWL
|
||||
#PERSONA_AGE= # Opsional, contoh: 24
|
||||
#PERSONA_GENDER= # Opsional, contoh: male | female | non-binary
|
||||
#PERSONA_TONE=casual # casual | formal | playful | warm
|
||||
#PERSONA_VERBOSITY=balanced # concise | balanced | detailed
|
||||
#PERSONA_HUMOR=light # none | light | witty
|
||||
#PERSONA_LANGUAGE=id # id | en | (kosong = auto)
|
||||
#PERSONA_MOOD=cheerful # cheerful | calm | energetic | sarcastic
|
||||
#PERSONA_CATCHPHRASES=Hai, Gimana kabarnya?, Wkwkwk
|
||||
|
||||
XMPP_ENABLED=False
|
||||
|
||||
|
||||
9
character/hendrik
Normal file
9
character/hendrik
Normal file
@ -0,0 +1,9 @@
|
||||
PERSONA_MODE=programmer
|
||||
PERSONA_NAME=Hendrik
|
||||
PERSONA_AGE=35
|
||||
PERSONA_GENDER=male
|
||||
PERSONA_TONE=formal
|
||||
PERSONA_VERBOSITY=concise
|
||||
PERSONA_HUMOR=none
|
||||
PERSONA_LANGUAGE=id
|
||||
PERSONA_MOOD=calm
|
||||
45
config.py
45
config.py
@ -1,5 +1,6 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from pathlib import Path
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@ -29,6 +30,12 @@ PERSONA_MODE = os.getenv("PERSONA_MODE", default="programmer").strip().lower()
|
||||
# Personality — nama panggilan AI (default: "OWL")
|
||||
PERSONA_NAME = os.getenv("PERSONA_NAME", default="OWL").strip() or "OWL"
|
||||
|
||||
# Persona age (optional)
|
||||
PERSONA_AGE = os.getenv("PERSONA_AGE", default="").strip()
|
||||
|
||||
# Persona gender (optional)
|
||||
PERSONA_GENDER = os.getenv("PERSONA_GENDER", default="").strip()
|
||||
|
||||
# Gaya bicara: "casual" | "formal" | "playful" | "warm"
|
||||
PERSONA_TONE = os.getenv("PERSONA_TONE", default="casual").strip().lower() or "casual"
|
||||
|
||||
@ -48,6 +55,44 @@ PERSONA_MOOD = os.getenv("PERSONA_MOOD", default="cheerful").strip().lower() or
|
||||
# Contoh: "Siap bro!, Haha~, Wkwkwk"
|
||||
PERSONA_CATCHPHRASES = os.getenv("PERSONA_CATCHPHRASES", default="").strip()
|
||||
|
||||
# Character preset — baca dari directory character/<AGENT_CHARACTER>
|
||||
CHARACTER_DIR = Path(__file__).resolve().parent / "character"
|
||||
AGENT_CHARACTER = os.getenv("AGENT_CHARACTER", default="").strip().lower()
|
||||
CHARACTER_CONFIG_PATH = CHARACTER_DIR / AGENT_CHARACTER if AGENT_CHARACTER else None
|
||||
if CHARACTER_CONFIG_PATH and CHARACTER_CONFIG_PATH.is_file():
|
||||
_character_env = {}
|
||||
for line in CHARACTER_CONFIG_PATH.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" in line:
|
||||
key, value = line.split("=", 1)
|
||||
_character_env[key.strip()] = value.strip()
|
||||
|
||||
_character_overrides = {
|
||||
"PERSONA_MODE": PERSONA_MODE,
|
||||
"PERSONA_NAME": PERSONA_NAME,
|
||||
"PERSONA_AGE": PERSONA_AGE,
|
||||
"PERSONA_GENDER": PERSONA_GENDER,
|
||||
"PERSONA_TONE": PERSONA_TONE,
|
||||
"PERSONA_VERBOSITY": PERSONA_VERBOSITY,
|
||||
"PERSONA_HUMOR": PERSONA_HUMOR,
|
||||
"PERSONA_LANGUAGE": PERSONA_LANGUAGE,
|
||||
"PERSONA_MOOD": PERSONA_MOOD,
|
||||
"PERSONA_CATCHPHRASES": PERSONA_CATCHPHRASES,
|
||||
}
|
||||
for key, fallback in _character_overrides.items():
|
||||
value = _character_env.get(key, fallback).strip()
|
||||
if key in {"PERSONA_MODE", "PERSONA_TONE", "PERSONA_VERBOSITY", "PERSONA_HUMOR", "PERSONA_LANGUAGE", "PERSONA_MOOD"}:
|
||||
value = value.lower() or fallback
|
||||
if key == "PERSONA_NAME" and not value:
|
||||
value = fallback
|
||||
_character_overrides[key] = value
|
||||
|
||||
for key, value in _character_overrides.items():
|
||||
globals()[key] = value
|
||||
os.environ[key] = value
|
||||
|
||||
# Selective response: true = roleplayer hanya respon kalau ada mention/relevansi (default).
|
||||
# false = roleplayer semua pesan ikut respon (seperti biasa, tanpa filter).
|
||||
XMPP_SELECTIVE_RESPONSE = os.getenv("XMPP_SELECTIVE_RESPONSE", default="true").strip().lower() in ("true", "1", "yes")
|
||||
|
||||
@ -36,15 +36,21 @@ class LLMClient:
|
||||
message = response['choices'][0]['message']
|
||||
return self.Message(message)
|
||||
except urllib.error.HTTPError as e:
|
||||
body_text = ""
|
||||
try:
|
||||
body_text = e.read().decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
pass
|
||||
if tools and e.code == 404:
|
||||
try:
|
||||
body = json.loads(e.read().decode('utf-8'))
|
||||
body = json.loads(body_text) if body_text else {}
|
||||
if 'tool use' in body.get('error', {}).get('message', '').lower():
|
||||
result = self.chat(messages, tools=None)
|
||||
result.warning = "Tool calling not supported by this model. Running in chat-only mode."
|
||||
return result
|
||||
except Exception:
|
||||
pass
|
||||
return self.Message({'content': f"HTTP Error: {e.code} {e.reason}", 'tool_calls': None})
|
||||
detail = f" - {body_text[:500]}" if body_text else ""
|
||||
return self.Message({'content': f"HTTP Error: {e.code} {e.reason}{detail}", 'tool_calls': None})
|
||||
except Exception as e:
|
||||
return self.Message({'content': f"Error: {str(e)}", 'tool_calls': None})
|
||||
|
||||
@ -20,6 +20,12 @@ class PersonalityConfig:
|
||||
# Nama panggilan AI (default: "OWL")
|
||||
name: str = "OWL"
|
||||
|
||||
# Umur persona AI (opsional; kosong bila tidak ingin ditampilkan)
|
||||
age: str = ""
|
||||
|
||||
# Jenis kelamin persona AI (opsional; kosong bila tidak ingin ditampilkan)
|
||||
gender: str = ""
|
||||
|
||||
# Gaya bicara:
|
||||
# "casual" → santai, gaul
|
||||
# "formal" → sopan, profesional
|
||||
@ -64,6 +70,8 @@ def _load_personality_from_env() -> PersonalityConfig:
|
||||
|
||||
return PersonalityConfig(
|
||||
name=os.getenv("PERSONA_NAME", default="OWL").strip() or "OWL",
|
||||
age=os.getenv("PERSONA_AGE", default="").strip(),
|
||||
gender=os.getenv("PERSONA_GENDER", default="").strip(),
|
||||
tone=os.getenv("PERSONA_TONE", default="casual").strip().lower() or "casual",
|
||||
verbosity=os.getenv("PERSONA_VERBOSITY", default="balanced").strip().lower() or "balanced",
|
||||
humor_level=os.getenv("PERSONA_HUMOR", default="light").strip().lower() or "light",
|
||||
@ -83,6 +91,12 @@ def _build_personality_block(cfg: PersonalityConfig) -> str:
|
||||
"""Generate deskripsi personality dari config."""
|
||||
parts = [f"You are {cfg.name}."]
|
||||
|
||||
if cfg.age:
|
||||
parts.append(f"Your persona age is {cfg.age} years old.")
|
||||
|
||||
if cfg.gender:
|
||||
parts.append(f"Your persona gender is {cfg.gender}.")
|
||||
|
||||
# Tone
|
||||
tone_map = {
|
||||
"casual": "You speak in a casual, relaxed manner — like chatting with a friend.",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user