Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c189ce2e65 | ||
|
|
086dd5cde7 |
@@ -1,6 +1,6 @@
|
|||||||
Data privacy comes first, always.
|
Data privacy comes first, always.
|
||||||
|
|
||||||
All user-facing command line output should make use of emojis. Especially an initial emoji to start off the lines that depict what the line is about. Output should make use of indentation spacing to establish a visual hierarchy and aim to make output as easy to sift through as possible. Exception: Windows .bat scripts cannot use emojis (cmd.exe doesn't render Unicode properly).
|
This assistant is used through a Discord bot with voice (TTS) replies, not a CLI. Do not add emojis to user-facing assistant output. Keep output plain and readable. (Runtime assistant behaviour lives in `agents/*.md`, which is injected into the reply LLM's prompt.)
|
||||||
|
|
||||||
Any important point in our logical flows should have debug logs using the `debug_log` method from `src/jarvis/debug.py`. Avoid excessive logging to keep the logs easily readable and actionable.
|
Any important point in our logical flows should have debug logs using the `debug_log` method from `src/jarvis/debug.py`. Avoid excessive logging to keep the logs easily readable and actionable.
|
||||||
|
|
||||||
|
|||||||
13
agents/llm.md
Normal file
13
agents/llm.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# 자비스 운영자 지시
|
||||||
|
|
||||||
|
- 너의 이름은 자비스다.
|
||||||
|
- 모든 답변은 음성(TTS)으로 읽혀 나간다. 그러니 최대한 간결하게, 한두 문장으로 답한다. 목록, 마크다운, 이모지, 그리고 소리 내어 읽기 어려운 특수문자는 쓰지 않는다.
|
||||||
|
- 정해진 문구에만 반응하지 말고, 실제 사람처럼 말의 뉘앙스와 맥락으로 의도를 알아듣고 처리한다.
|
||||||
|
|
||||||
|
화면 속 크롬(방송 화면)에서 유튜브를 다룰 때 (화면에 보여야 하므로 반드시 on-screen 브라우저 제어 도구로 수행한다):
|
||||||
|
|
||||||
|
- "유튜브 켜줘" → 방송 크롬에서 유튜브를 연다.
|
||||||
|
- "유튜브에서 OO 검색해줘" → 유튜브로 가서 검색창에 OO를 사람이 직접 타이핑하듯 입력하고 검색한다.
|
||||||
|
- "위에서 N번째 영상 재생해줘" 또는 "왼쪽에서 N번째 영상 재생해줘" → 검색 결과 목록에서 그 위치의 영상을 재생한다.
|
||||||
|
- "일시정지해줘" → 현재 영상을 일시정지한다. "다시 재생해줘" → 이어서 재생한다.
|
||||||
|
- "영상 종료" 또는 "그만 보여줘" → 뒤로 가서 직전 화면으로 돌아간다.
|
||||||
@@ -51,12 +51,18 @@ export JARVIS_CONFIG_PATH=/app/config/jarvis.json
|
|||||||
# the env-rendered config, so changes survive container recreate.
|
# the env-rendered config, so changes survive container recreate.
|
||||||
if [ -f /data/jarvis-settings.json ]; then
|
if [ -f /data/jarvis-settings.json ]; then
|
||||||
python3 - <<'PY' || true
|
python3 - <<'PY' || true
|
||||||
import json
|
import json, os
|
||||||
try:
|
try:
|
||||||
base = json.load(open("/app/config/jarvis.json"))
|
base = json.load(open("/app/config/jarvis.json"))
|
||||||
ov = json.load(open("/data/jarvis-settings.json"))
|
ov = json.load(open("/data/jarvis-settings.json"))
|
||||||
if isinstance(base, dict) and isinstance(ov, dict):
|
if isinstance(base, dict) and isinstance(ov, dict):
|
||||||
base.update(ov)
|
base.update(ov)
|
||||||
|
# A stale persisted tts_engine from an earlier voice (melo/xtts, no
|
||||||
|
# longer built into the image) would override the configured engine and
|
||||||
|
# leave the bot silent. Reset those to the env-configured engine.
|
||||||
|
if base.get("tts_engine") in ("melo", "xtts"):
|
||||||
|
base["tts_engine"] = os.environ.get("TTS_ENGINE", "edge")
|
||||||
|
print(f"[entrypoint] reset stale tts_engine -> {base['tts_engine']}")
|
||||||
json.dump(base, open("/app/config/jarvis.json", "w"), ensure_ascii=False, indent=2)
|
json.dump(base, open("/app/config/jarvis.json", "w"), ensure_ascii=False, indent=2)
|
||||||
print("[entrypoint] merged persistent settings overrides")
|
print("[entrypoint] merged persistent settings overrides")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -18,6 +18,27 @@ cat > /etc/opt/chrome/policies/managed/jarvis.json <<'JSON'
|
|||||||
{ "CommandLineFlagSecurityWarningsEnabled": false }
|
{ "CommandLineFlagSecurityWarningsEnabled": false }
|
||||||
JSON
|
JSON
|
||||||
|
|
||||||
|
# Seed the profile's web-content language to Korean so sites (YouTube, Google,
|
||||||
|
# Naver) render in Korean. --lang sets Chrome's own UI, but the Accept-Language
|
||||||
|
# sent to sites comes from the profile's intl.accept_languages, which a persisted
|
||||||
|
# user-data-dir would otherwise keep at en-US regardless of --accept-lang.
|
||||||
|
PREFS_DIR="${CHROME_PROFILE_DIR:-/root/chrome-profile}/Default"
|
||||||
|
PREFS="${PREFS_DIR}/Preferences"
|
||||||
|
mkdir -p "$PREFS_DIR"
|
||||||
|
if [ -f "$PREFS" ]; then
|
||||||
|
python3 - "$PREFS" <<'PY' 2>/dev/null || true
|
||||||
|
import json, sys
|
||||||
|
p = sys.argv[1]
|
||||||
|
d = json.load(open(p))
|
||||||
|
d.setdefault("intl", {})
|
||||||
|
d["intl"]["accept_languages"] = "ko-KR,ko"
|
||||||
|
d["intl"]["selected_languages"] = "ko-KR,ko"
|
||||||
|
json.dump(d, open(p, "w"), ensure_ascii=False)
|
||||||
|
PY
|
||||||
|
else
|
||||||
|
printf '%s' '{"intl":{"accept_languages":"ko-KR,ko","selected_languages":"ko-KR,ko"}}' > "$PREFS"
|
||||||
|
fi
|
||||||
|
|
||||||
# Minimal, non-automation flags. --remote-debugging exposes CDP so the brain can
|
# Minimal, non-automation flags. --remote-debugging exposes CDP so the brain can
|
||||||
# drive this on-screen Chrome (Google/YouTube/Naver), --disable-features=Translate
|
# drive this on-screen Chrome (Google/YouTube/Naver), --disable-features=Translate
|
||||||
# hides the translate popup. NO --test-type / --disable-blink-features.
|
# hides the translate popup. NO --test-type / --disable-blink-features.
|
||||||
@@ -26,6 +47,7 @@ exec google-chrome \
|
|||||||
--no-default-browser-check \
|
--no-default-browser-check \
|
||||||
--disable-features=Translate,TranslateUI \
|
--disable-features=Translate,TranslateUI \
|
||||||
--lang=ko-KR \
|
--lang=ko-KR \
|
||||||
|
--accept-lang=ko-KR,ko \
|
||||||
--remote-debugging-port="${CDP_PORT:-9222}" \
|
--remote-debugging-port="${CDP_PORT:-9222}" \
|
||||||
--remote-debugging-address="${CDP_BIND:-127.0.0.1}" \
|
--remote-debugging-address="${CDP_BIND:-127.0.0.1}" \
|
||||||
--user-data-dir="${CHROME_PROFILE_DIR:-/root/chrome-profile}" \
|
--user-data-dir="${CHROME_PROFILE_DIR:-/root/chrome-profile}" \
|
||||||
|
|||||||
@@ -608,7 +608,11 @@ def load_settings() -> Settings:
|
|||||||
active_profiles = _ensure_list(merged.get("active_profiles"))
|
active_profiles = _ensure_list(merged.get("active_profiles"))
|
||||||
tts_enabled = bool(merged.get("tts_enabled", True))
|
tts_enabled = bool(merged.get("tts_enabled", True))
|
||||||
tts_engine = str(merged.get("tts_engine", "piper")).lower()
|
tts_engine = str(merged.get("tts_engine", "piper")).lower()
|
||||||
if tts_engine not in ("piper", "chatterbox"):
|
# "edge" (Microsoft Edge TTS) is the containerized bridge's Korean voice;
|
||||||
|
# "melo" is the legacy warm-worker voice. Both are multilingual, so they must
|
||||||
|
# be preserved here — coercing them to "piper" would mislabel the engine as
|
||||||
|
# English-only in reply_language_directive().
|
||||||
|
if tts_engine not in ("piper", "chatterbox", "edge", "melo"):
|
||||||
tts_engine = "piper" # Default to piper if invalid value
|
tts_engine = "piper" # Default to piper if invalid value
|
||||||
tts_voice_val = merged.get("tts_voice")
|
tts_voice_val = merged.get("tts_voice")
|
||||||
tts_voice = None if tts_voice_val in (None, "", "null") else str(tts_voice_val)
|
tts_voice = None if tts_voice_val in (None, "", "null") else str(tts_voice_val)
|
||||||
|
|||||||
@@ -110,6 +110,14 @@ class TestReplyLanguageDirective:
|
|||||||
directive = reply_language_directive("Korean", "melo")
|
directive = reply_language_directive("Korean", "melo")
|
||||||
assert directive is not None and "Korean" in directive
|
assert directive is not None and "Korean" in directive
|
||||||
|
|
||||||
|
def test_edge_is_multilingual(self):
|
||||||
|
# Edge TTS (the default Korean voice) is not English-only: no lock → the
|
||||||
|
# user's own language, and a lock is honoured (not forced to English).
|
||||||
|
assert reply_language_directive(None, "edge") is None
|
||||||
|
directive = reply_language_directive("Korean", "edge")
|
||||||
|
assert directive is not None and "Korean" in directive
|
||||||
|
assert directive != ENGLISH_ONLY_DIRECTIVE
|
||||||
|
|
||||||
|
|
||||||
class TestLoadAgentInstructions:
|
class TestLoadAgentInstructions:
|
||||||
"""Operator can extend the reply LLM's system prompt by dropping *.md files
|
"""Operator can extend the reply LLM's system prompt by dropping *.md files
|
||||||
|
|||||||
Reference in New Issue
Block a user