프로젝트 마기

0 comments0 reviews

#Project MAGI — Tauri 데스크톱 앱 제작

에반게리온의 MAGI 시스템을 재현한 Tauri v2 데스크톱 앱을 만들어줘. 질문(提訴)을 넣으면 세 대의 MAGI가 각각 판단하고, 일부러 연출한 딜레이와 효과음을 거쳐 다수결로 決議(承認/否決/保留)를 낸다. 백엔드는 단순하게, 프론트엔드 완성도가 핵심이다.

유닛원작 설정모델연결
MELCHIOR-1科学者としての赤木ナオコJev typesafe/jev-1.13OpenRouter Decisions API POST https://openrouter.ai/api/alpha/decisions
BALTHASAR-2母としての赤木ナオコLaya (오픈소스, 로컬)laya-serve → POST http://127.0.0.1:8000/v1/systemone
CASPER-3女としての赤木ナオコGPT-6 LunaOpenRouter Chat POST https://openrouter.ai/api/v1/chat/completions
  • Jev와 Laya는 채팅 LLM이 아니라 "System One" 결정 모델이다. 텍스트를 생성하지 않고 {model, state, questions}를 받아 타입이 있는 답과 보정된 확률을 돌려준다.
    • 요청: questions.verdict = {type:"choice", instructions:"<유닛 관점>: should this proposal be approved?", criteria:{approve, reject, conditional}}
    • 유닛별 추가 지표 2개: MELCHIOR는 논리정합성(score)과 실현가능성(noul), BALTHASAR는 위험도(score)와 보호적합(noul), CASPER가 결정 엔진일 때는 본심(noul)과 행복도(score)
    • 응답 예: answers.verdict = {type:"choice", choice:"reject", probabilities:{approve:0.27, reject:0.68, conditional:0.05}, confidence}. score는 {score, legend, probabilities:{"0":..}}, noul은 {noul: 0~1}. 구버전은 distribution 필드를 쓰니 둘 다 파싱할 것.
  • CASPER는 생성형이다. system prompt로 페르소나와 출력 프로토콜을 준다: 첫 줄은 반드시 VERDICT: APPROVE|REJECT|CONDITIONAL, 이어서 180단어 이내 근거, 질문과 같은 언어로 답한다. CONDITIONAL로 도망가지 말고 단호하게 판단하라고 명시하고, 파싱은 관대하게(承認/否決/승인/반대 등도 인식).
  • 유닛마다 엔진(decision/chat), 제공자(OpenRouter/로컬), 엔드포인트, 모델을 설정에서 바꿀 수 있게 할 것.
  • OpenRouter 키는 설정 입력, 비어 있으면 OPENROUTER_API_KEY 환경변수를 쓴다.

보드와 기록에는 원본 이름(MELCHIOR-1 등)과 원작 설정 문구만 표시한다. 모델명, 코드네임, 제공자는 설정 화면에만 둔다.

  • 배경은 검정. 주황(#ff7a1c) 프레임과 커넥터, 초록(#3cf06a) 이중 레일과 상태 박스, 패널은 시안(#5ccbf2)에 남색(#0a1624) 글자.
  • 가운데 콘솔(1560×720, x=780 기준 대칭): BALTHASAR는 위쪽 중앙에 아래 모서리를 깎은 육각형, CASPER는 좌하단, MELCHIOR는 우하단에 안쪽 위 모서리를 깎은 오각형. 굵은 주황 커넥터 3개가 가운데 "MAGI"(세리프, 주황 글로우)를 둘러싼다. 패널 테두리는 주황 선과 검정 틈으로 이중 처리.
  • 좌상단 주황 정보 텍스트: CODE : 473 / FILE : MAGI_SYS / EXTENTION : 3023 / EX_MODE / PRIORITY. 심의마다 번호를 바꾸고 끝나면 집계를 표시.
  • 우상단 큰 한자 상태(待機 → 提訴 → 審議 → 承認/否決/保留)와 초록 이중 레일, 아래 초록 박스 보조 상태(待機中/審議中/集計中/決議完了). 결과에 따라 초록/빨강/호박색으로 바뀐다.
  • 위쪽 띠: [提訴] 태그와 현재 질문(길면 말줄임), 제출 시각과 코드.
  • 아래쪽 띠: 유닛별 텔레메트리. 심의 중에는 헥스 스트림, 끝나면 VOTE REJECT 否決 · 67.9% · 0.2s.
  • 패널 상태: 대기(시안), 심의 중(무작위 간격 깜빡임과 이동하는 사선 스캔, SYNC 43.2% 진행 표시), 결과(承認 #45e38a, 否決 #ff3b2f, 保留 #ffb31a, 큰 명조 한자가 튀어나오듯 등장), 오류(어두운 바탕에 断絶), 오프라인. 결정 모델 유닛은 패널에 P = 0.679처럼 확률 표시.
  • 부팅: 패널이 하나씩 점등. 결의 순간에는 보드 전체에 색 플래시. 화면 위에 CRT 스캔라인과 비네팅.
  • 폰트: 한자와 MAGI는 Noto Serif JP 900(@fontsource로 번들, 오프라인 동작), 이름은 굵은 Helvetica를 textLength로 맞춤, 수치는 모노스페이스.

상단바(MAGI 로고, 가동 유닛 수, 시계, 음향 토글, SYS CONFIG) / 좌측 보드 / 우측 審議記録 패널(약 450px) / 하단 입력줄([提訴] 태그, textarea, 送信 버튼).

  • 기록 카드: 제소 내용, 유닛별 섹션. 결정 모델은 承認/否決/保留 확률 막대와 추가 지표 막대, CASPER는 타자기 효과 뒤 마크다운 렌더링(marked + DOMPurify). 마지막에 決議 결과와 집계.
  • 기록은 localStorage에 최근 40건 보관. 우측 상단 消去 버튼은 즉시 전부 지우고 보드를 대기 상태로 되돌린다. window.confirm()은 Tauri macOS 웹뷰에서 동작하지 않으니 절대 쓰지 말 것. 심의 중에는 비활성.
  • 문구 톤: 짧은 작중 명령어 스타일. 입력 placeholder는 議題を入力せよ, 빈 기록은 NO RECORD / 審議記録なし. "~하면 ~합니다" 같은 친절한 안내 문구는 쓰지 말 것.
  • 단축키: Enter 제소, Shift+Enter 줄바꿈(IME 조합 중에는 무시), ⌘, 설정.

세 유닛을 병렬로 호출하되, 결과는 최소 딜레이(기본 4.5초)가 지나기 전에는 공개하지 않는다. 이후 도착 순서대로 약 1.1초 간격(약간의 무작위)으로 하나씩 공개하고, 集計中를 거쳐 決議를 낸다. 결의 규칙은 유효표의 과반. 오류나 오프라인 유닛은 표에서 제외하고, 유효표가 없으면 不能. 딜레이, 공개 간격, 타임아웃은 설정에서 조정.

애니메이션 원본 음원은 저작권 문제로 번들하지 말 것. Web Audio로 합성한 기본음을 넣는다: boot, submit, thinking(무작위 삑 루프), unit, approve(상승 화음), reject(톱니파 경보), error. 슬롯별로 사용자 음원(mp3/wav/ogg/m4a)을 LOAD해서 앱 데이터 폴더의 sounds/<슬롯>.<확장자>로 저장하고, 폴더를 열 수 있게 하고, 파일을 직접 넣어도 인식할 것. WebKit은 사용자 입력 전에는 오디오를 막으므로 첫 입력 때 AudioContext를 unlock할 것.

커맨드: magi_decide(System One POST, 원본 JSON 반환), magi_query(OpenAI 호환 chat), list_models, load_config/save_config(앱 설정 폴더에 JSON, 권한 600), load_sounds/save_sound/remove_sound/get_sounds_dir. 연결 실패, 타임아웃, HTTP 오류는 짧은 메시지(LINK DOWN, TIMEOUT, HTTP 401: ...)로 변환한다. 설정 파일에 version을 두고 구버전 유닛 설정은 버린다.

OpenRouter 키, 유닛별 설정(ENGINE, ONLINE, PROVIDER, 로컬 ENDPOINT/KEY, MODEL, TEMPERATURE는 chat일 때만, 페르소나 또는 판단 관점 문구), 심의 설정, 오디오 설정. TEST 버튼: 결정 유닛은 실제 noul 질문 한 번을 보내 확인하고, chat 유닛은 모델 목록에 해당 모델이 있는지 확인.

  • scripts/laya-serve.sh와 npm run laya: uv로 laya/.venv에 laya[serve]를 설치하고 LAYA_HOST=127.0.0.1로 실행(기본값 0.0.0.0은 쓰지 말 것).
  • src/dev-mock.ts: Tauri 밖(npm run dev)에서 열리면 mockIPC로 가짜 응답을 돌려 브라우저만으로 UI를 확인할 수 있게. Jev/Laya와 같은 응답 형식을 흉내낸다.
  • MAGI 3패널 모양 앱 아이콘을 만들어 cargo tauri icon으로 생성. 창 크기 1480×920(최소 1100×700), 배경 검정.
  • README(실행법, 유닛 구성, 사운드 교체법)와 Rust 통합 테스트(#[ignore], 로컬 Laya 대상).
  1. tsc --noEmit, cargo check, cargo test 통과
  2. 실제 laya-serve를 띄워 Rust 커맨드로 한국어 질문에 확률 응답이 오는지 확인
  3. Playwright WebKit(Tauri macOS 웹뷰와 같은 엔진)으로 대기, 심의 중, 결의 완료, 설정, 消去 후 상태를 스크린샷으로 확인하고 콘솔 에러 0건
  4. npm run tauri dev로 실제 앱이 뜨는지 확인
  • 사용자가 1420 포트에서 tauri dev를 돌리고 있을 수 있다. 포트 기준으로 프로세스를 죽이지 말고, 직접 띄운 PID만 정리할 것.
  • 키가 없어서 못 한 검증(Jev, GPT-6 Luna)은 완료 보고에 명시할 것.