1. 프로젝트 '능동형 AI 여자친구' 개발 계획 (1차)
1. 프로젝트 핵심 목표 및 철학
- 능동적 질의응답: 사용자가 묻는 말에만 답하는 수동적인 AI가 아닌, 사용자의 활동에 먼저 관심을 보이고 말을 거는 능동적인 AI 컴패니언을 지향한다.
- 실재감과 유대감 형성: AI가 사용자와 같은 PC 화면을 보고 있다는 느낌을 주어, 마치 같은 공간에 함께 있는 듯한 실재감과 유대감을 극대화한다.
- 로컬 중심 설계: 사용자와의 1:1 상호작용에 집중하며, 빠른 반응 속도와 자연스러운 딜레이를 추구한다. 초기에는 클라우드 API를 적극 활용하되, 장기적으로는 로컬 모델로의 확장을 염두에 둔다.
2. 시스템 아키텍처
- 구조: 코어 애플리케이션(Python)이 본체가 되고, 시각적 플러그인(Unity/C#)이 선택적으로 연동되는 구조.
- 코어 애플리케이션 (Python):
- 역할: AI의 모든 지능적인 처리와 핵심적인 사용자 인터페이스(UI, 오디오)를 담당.
- 세부 기능:
- Gemini API 연동, RAG를 통한 장기 기억 관리, 사용자 PC 활동 모니터링.
- TTS를 통해 텍스트를 음성 데이터로 변환 후, 시스템 오디오 장치로 직접 재생.
- PyQt/PySide 등을 이용해 화면에 투명 오버레이 UI(자막 창)를 직접 렌더링.
- Unity 플러그인이 연결되어 있다면, 아바타 제어 명령을 전송.
- 시각적 플러그인 (Unity/C#):
- 역할: 코어 앱(Python)으로부터 받은 시각적 지시를 아바타로 표현하는 역할만 수행.
- 세부 기능:
- 3D/2D 아바타 렌더링(Live2D, Mate Engine).
- Python으로부터 받은 emotion과 pose 명령에 따라 아바타의 애니메이션과 표정을 변경.
- 립싱크는 Python의 오디오 재생에 맞춰 반응하거나, 혹은 단순한 기본 입모양 애니메이션을 재생하는 정도로 간소화될 수 있음
- 통신 방식:
- 코어 앱과 플러그인 간의 실시간 양방향 통신을 위해 WebSockets를 사용.
- 데이터는 플러그인 제어에 필요한 최소한의 정보만 JSON 형식으로 구조화하여 주고받는다.
- 예시: { "emotion": "HAPPY", "pose": "NOD" }
3. GUI (Graphical User Interface) 구성
Python 코어 애플리케이션이 직접 렌더링하며, 전통적인 창 형태가 아닌 미니멀리즘 오버레이(Minimalist Overlay) 형태를 지향한다. 사용자의 작업에 방해되지 않으면서 자연스럽게 존재감을 드러내는 것이 목표다.
- 가. 자막 창 (Subtitle Window):
- 역할: AI의 대사 및 생각(지문)을 실시간으로 표시하는 핵심 UI.
- 디자인 및 동작:
- 항상 위(Always on Top): 모든 창보다 위에 위치한다.
- 투명 배경: 창 배경은 투명하거나 반투명하여 뒷 배경이 비쳐 보인다.
- 위치 이동 및 저장: 사용자가 마우스로 드래그하여 위치를 옮길 수 있으며, 그 위치를 기억한다.
- 동적 표시: AI가 말을 시작할 때 부드럽게 나타나고(Fade-in), 말이 끝나면 잠시 후 부드럽게 사라진다(Fade-out).
- 커스터마이징: 폰트, 크기, 색상, 외곽선 등을 설정에서 변경할 수 있다.
- 나. 상태 표시기 (Status Indicator):
- 역할: 자막 창이 없을 때도 AI의 현재 상태를 알려주는 작고 영구적인 아이콘.
- 디자인 및 동작:
- 화면 구석에 위치하며, AI의 상태에 따라 시각적으로 변화한다 (예: 대기 중-평온, 생각 중-깜빡임, 화면 분석 중-스캔 효과, 말하는 중-파동 효과).
- 사용자가 클릭하거나 우클릭하여 다른 기능(채팅 입력, 설정)을 호출하는 시작점이 된다.
- 다. 채팅 입력 창 (Chat Input Box):
- 역할: 사용자가 AI에게 직접 텍스트로 말을 걸 때 사용.
- 동작: 평소에는 숨겨져 있다가, 특정 단축키(Hotkey)를 누르거나 상태 표시기를 클릭하면 나타나는 한 줄 입력 상자.
- 라. 설정 창 (Settings Window):
- 역할: 각종 설정을 변경하는 일반적인 창. 상태 표시기 우클릭 메뉴를 통해 접근한다.
- 설정 항목: UI 커스터마이징, AI의 응답 빈도("수다스러움") 조절, TTS 목소리/볼륨, API 키 입력, 화면 분석 주기 등.
4. 상호작용 방식 (AI의 응답 트리거)
AI가 응답을 시작하는 계기는 크게 세 가지로 나뉜다.
- 가. 능동적/자동 응답 (Proactive/Automatic Response):
- 핵심 철학: 고정된 시간 간격이 아닌, **'의미 있는 변화'**를 감지하여 말을 건다.
- 트리거 조건:
- 활성 애플리케이션 변경: 활성 창의 제목이 바뀔 때 (예: 'Visual Studio Code' -> 'League of Legends').
- 사용자 비활성(Idle) 감지: 키보드/마우스 입력이 5분 이상 없을 때.
- 시간 기반 이벤트: 특정 시간대(점심시간, 늦은 밤 등)에 도달했을 때.
- 랜덤 주기 마다: 랜덤한 주기의 쿨타임 후에 말을 걸게 함.
- 조절 장치: AI가 말을 한 번 한 후에는 일정 시간 말을 걸지 않는 쿨다운(Cooldown) 시스템을 적용하여 사용자를 방해하지 않도록 한다.
- 나. 텍스트 입력 기반 응답:
- 사용자가 명확한 의도를 가지고 AI에게 말을 거는 가장 기본적인 방식.
- 작동 순서: 단축키로 채팅 입력 창 호출 -> 사용자 텍스트 입력 -> AI가 해당 텍스트를 최우선으로 고려하여 응답 생성.
- 다. 음성 인식 기반 응답:
- 가장 자연스러운 상호작용 방식.
- 구현 옵션:
- Push-to-Talk (PTT): 특정 키를 누르고 있는 동안만 음성을 인식.
- 웨이크 워드 (Wake Word): ex. "시리야" 같은 특정 호출어를 감지하면 음성 인식을 시작
- Always-On STT(?): 가장 자연스러운 방식이지만 자원 소모가 엄청 큼
- 인식된 음성은 텍스트로 변환(STT)되어, 텍스트 입력 기반 응답과 동일한 프로세스를 거쳐 처리된다.
5. 모니터링 항목
AI가 사용자의 상황과 의도를 추론하기 위해 수집하는 데이터.
분류 | 모니터링 항목 | 수집할 정보 |
---|---|---|
시각 정보 | 전체 화면 | 현재 모니터의 스크린샷 이미지 |
애플리케이션 | 활성 창 | 현재 가장 위에 있는 창의 제목 |
실행 중인 프로세스 | 실행 중인 모든 프로그램 목록 | |
사용자 입력 | 키보드/마우스 활동 | 입력 이벤트의 유무 (내용 X) |
시스템 정보 | 현재 시간 | 날짜 및 시간 |
시스템 사운드 | (심화) 현재 재생 중인 오디오 소스 |
6. 다중 턴 대화 기억 (Memory System)
AI가 사용자와의 관계를 쌓고, 이전 대화를 기억하게 하기 위해 인간의 기억 방식과 유사한 단기 기억과 장기 기억의 하이브리드 전략을 사용한다.
- 가. 단기 기억 (Short-Term Memory):
- 목표: 현재 대화의 흐름(맥락)을 유지하여 자연스러운 대화가 이어지게 한다.
- 구현: 슬라이딩 윈도우(Sliding Window) 기법을 사용. 항상 최근 N개의 대화(예: 5개)만을 메모리에 유지하고, LLM에 프롬프트를 보낼 때 이 기록을 포함시킨다. 새로운 대화가 추가되면 가장 오래된 대화는 버려진다. 이전 대화를 모두 요약하는 프롬프트를 맨뒤에 추가하는 방식은 AI가 흐름을 잘 못따라올때 한번 고려해봄
- 나. 장기 기억 (Long-Term Memory):
- 목표: 중요한 정보(사용자 취향, 함께 겪은 일 등)를 영구적으로 저장하고 필요할 때 다시 꺼내 쓴다.
- 구현: RAG (Retrieval-Augmented Generation) 파이프라인을 구축한다.
- RAG 워크플로우:
- 저장 (Memory Storage)
- 판단 및 의 동시성: AI가 사용자에게 응답을 줄때 json 필드 형식으로 respose와 rag를 함께 제공해준다.
- 데이터 처리: rag 문장을 memory_manager 모듈에 전달하여 벡터화 및 Qdrant 저장을 실행한다.
- 인출 (Retrieval):
- 사용자의 새 메시지가 들어오면, 이 메시지 또한 벡터로 변환하여 쿼리 벡터를 만든다.
- 쿼리 벡터를 Qdrant에 보내, 의미적으로 가장 유사한 과거의 '추억' 벡터들을 검색해온다.
- 증강 및 생성 (Augmentation & Generation):
- 검색된 과거 기억(장기 기억)과 최근 대화 기록(단기 기억)을 모두 LLM 프롬프트에 포함시켜, 풍부한 컨텍스트를 바탕으로 AI가 응답을 생성하게 한다.
- 저장 (Memory Storage)
7. 상황 인식 및 특징 추출 (Context Awareness & Feature Extraction)
모니터링을 통해 수집한 원시 데이터를 AI가 이해할 수 있는 의미 있는 정보로 가공하는 과정. 초기에는 Gemini API의 멀티모달 능력을 최대한 활용하는 "통합 분석" 방식을 사용한다.
- 초기 전략 (Gemini API 중심):
- 개념: 로컬에서 여러 특징을 개별적으로 추출하지 않고, 모든 원시 데이터를 Gemini API에 한 번에 보내 통합 분석을 맡긴다.
- "하나의 거대한 프롬프트 (The Grand Unified Prompt)" 구성:
- AI가 상황을 인식해야 할 때, 스크린샷 이미지, 활성 창 제목, 현재 시간, 단기 기억, 장기 기억(RAG 검색 결과) 등 모든 데이터를 한 번에 수집한다.
- 수집된 모든 데이터를 포함하는 정교한 멀티모달 프롬프트(텍스트+이미지)를 구성하여 Gemini 2.5 Pro 모델에 전송한다.
- 구조화된 출력: ... AI의 분석 내용, 실제 대사, 감정, 포즈뿐만 아니라, 이번 대화에서 장기 기억에 저장할 내용까지 구조화된 데이터로 한 번에 받아온다.
{ "analysis": "사용자가 늦은 밤까지 코딩 중이라 피곤해 보임.", "response_text": "늦게까지 고생 많아. 거의 다 끝나가는 거야?", "emotion": "PROUD_AND_WORRIED", "pose": "LEAN_FORWARD_GENTLY", "rag": [ { "memory_text": "사용자는 밤늦게까지 코딩하는 습관이 있다." } ] }
- 장점: 개발이 단순하고 빠르며, 최첨단 모델의 종합적인 판단 능력을 활용하여 매우 높은 품질의 상황 인식이 가능하다.
8. 아바타 동작 지시 생성 (Avatar Action Generation)
AI가 대사를 생각할 때, 동시에 그 대사에 어울리는 연기(표정, 몸짓)까지 스스로 결정하도록 한다.
- 핵심 전략: LLM을 단순 '작가'가 아닌, 대본과 연기 지시를 함께 내리는 '감독'으로 활용한다.
- 구현 방법: 정교한 프롬프트 엔지니어링을 사용.
- 명령어 구체화: Gemini API에 요청을 보낼 때, 우리가 제어할 수 있는 '사용 가능한 표정'과 '사용 가능한 몸짓' 목록을 시스템 프롬프트에 명시적으로 제공한다.
- 사용 가능한 표정: [NEUTRAL, HAPPY, SAD, SURPRISED, ...]
- 사용 가능한 몸짓: [IDLE, NOD, SHAKE_HEAD, WAVE_HAND, ...]
- 규칙 강제: AI에게 반드시 이 목록에 있는 키워드만을 사용하여, 지정된 JSON 형식(emotion, pose 키 포함)으로 응답하도록 강제한다.
- 명령어 구체화: Gemini API에 요청을 보낼 때, 우리가 제어할 수 있는 '사용 가능한 표정'과 '사용 가능한 몸짓' 목록을 시스템 프롬프트에 명시적으로 제공한다.
- 워크플로우:
- LLM이 프롬프트 규칙에 따라 대사와 함께 emotion, pose 키워드가 포함된 JSON을 생성한다.
- Python 백엔드는 이 JSON을 파싱한다.
- response_text는 TTS와 자막으로 처리한다.
- emotion과 pose 문자열은 WebSocket을 통해 Unity/Live2D 플러그인으로 전송된다.
- 플러그인은 전달받은 문자열에 매칭되는 아바타의 표정과 애니메이션을 재생한다.
9. 데이터 저장 및 관리 (Data Storage & Management)
사용자의 프라이버시를 최우선으로 고려하는 "로컬 우선(Local-First)" 원칙을 기반으로, 각 데이터의 목적과 특성에 맞춰 SQLite, Qdrant, 그리고 JSON 설정 파일을 조합한 하이브리드 방식으로 데이터를 관리한다.
데이터 종류 | 저장 내용 | 저장 방식 | 핵심 목적 |
---|---|---|---|
AI 장기 기억 | 의미적으로 요약/추출된 핵심 정보 | Qdrant (Vector DB) + SQLite (Metadata DB) | RAG의 핵심. 대화 중 관련 기억을 빠르게 검색하여 컨텍스트 제공. |
전체 대화 기록 | 사용자와 AI가 나눈 모든 대화의 원본 | SQLite chat_history 테이블 | 디버깅 및 기록 보관. AI의 행동을 추적하거나, 미래에 모델 파인튜닝 시 학습 데이터로 활용. |
사용자 프로필 | 사용자의 이름, 별명 등 직접 설정한 정보 | SQLite user_profile 테이블 | 개인화. AI가 사용자의 이름을 부르는 등 맞춤형 상호작용 제공. |
애플리케이션 설정 | API 키, UI 창 위치, 볼륨, 폰트 크기 등 | config.json 파일 | 앱 상태 유지. 프로그램을 껐다 켜도 사용자가 설정한 환경이 그대로 유지됨. |
- 가. AI 장기 기억 (RAG 데이터베이스):
- 듀얼 시스템: 의미 검색을 위한 벡터는 Qdrant에, 해당 벡터와 짝을 이루는 실제 텍스트와 메타데이터(생성 시각 등)는 SQLite에 저장한다.
- 작동 방식: Qdrant에서 의미가 유사한 벡터의 ID를 찾은 후, 그 ID를 이용해 SQLite에서 실제 텍스트 기억을 가져오는 효율적인 구조다.
- 나. 전체 대화 기록 및 사용자 프로필:
- 정형화된 데이터를 다루기 용이하고 로컬에서 가볍게 실행할 수 있는 SQLite를 사용하여 관리한다.
- 다. 애플리케이션 설정:
- 사람이 직접 읽고 수정하기 쉬우며 구조가 단순하므로, **JSON 파일(config.json)**을 사용해 관리한다.
10. 선택적 외부 API 활용 전략
모든 것을 로컬이나 클라우드 한쪽으로만 처리하는 것이 아니라, 각 작업의 특성에 맞춰 최적의 도구를 선택하는 실용적인 하이브리드 아키텍처를 채택한다. 시스템의 중심에는 "AI 작업 분배기(AI Task Dispatcher)"가 존재한다.
- 가. AI 작업 분배기 (AI Task Dispatcher):
- 역할: AI가 어떤 작업을 수행해야 할 때, 그 작업의 종류, 복잡도, 비용, 속도, 프라이버시, 사용자 설정 등을 고려하여 로컬 모델과 외부 API 중 어느 것을 사용할지 결정하는 지능적인 라우터.
- 나. 기능별 로컬/외부 옵션 및 분배 기준:
기능 | 로컬 옵션 (빠름/저렴/오프라인) | 외부(클라우드) 옵션 (고품질/비쌈/온라인) | 분배기의 선택 기준 (예시) |
---|---|---|---|
대화 생성 (LLM) | 소형 LLM | 대형 LLM | 단순 리액션은 로컬, 복잡한 추론이 필요한 대화는 외부. |
이미지 분석 | 소형 Vision 모델 | 대형 Vision 모델 | 단순 객체 감지는 로컬, 심층적인 이미지 이해는 외부. |
음성 합성 (TTS) | 오프라인 TTS 엔진 | 고품질 클라우드 TTS | 기본은 로컬, 사용자가 '고품질 음성' 옵션을 켜거나, 캐싱된 음성이 없을 때만 외부. |
음성 인식 (STT) | 로컬 Whisper 모델 (whisper.cpp) | Whisper API, Google STT API | 짧은 음성이나 빠른 반응이 중요할 땐 로컬, 정확도가 중요할 땐 외부. |
- 다. 이점:
- 비용 최적화: 간단한 작업에 비싼 API를 낭비하지 않는다.
- 성능 맞춤화: 필요할 땐 최고의 성능을, 평소엔 빠른 반응 속도를 누릴 수 있다.
- 오프라인 기능: 인터넷 연결이 없어도 로컬 모델을 통해 기본적인 상호작용이 가능하다.
- 미래 확장성: 더 좋은 로컬 모델이나 새로운 API가 나와도, 분배기의 규칙만 수정하면 시스템 전체를 쉽게 업그레이드할 수 있다.
2. 프로젝트 개발 우선순위
1단계: 코어 대화 시스템 구축
- 목표: 가장 기본적인 '키보드 입력/음성 입력 -> 처리 -> 자막 출력/음성 출력' 사이클을 완성한다. 키보드 입력뿐만 아니라, 버튼을 눌러 사용자의 목소리를 AI에게 전달하는 핵심적인 기능을 만드는데 집중한다.
- 세부 개발 항목:
- 프로젝트 기본 구조 설정:
- Python 프로젝트 폴더를 생성하고, main_app.py, ai_engine.py, ui_manager.py, audio_player.py, speech_recognizer.py 등 초기 모듈 파일을 만든다.
- config.json 파일을 생성하고 Gemini 및 STT/TTS API 키를 저장해 불러오는 기능을 구현한다.
- 기본 UI 구현:
- ui_manager.py 모듈에서 PyQt/PySide를 사용하여, 사용자가 텍스트를 입력할 수 있는 간단한 채팅 입력 창을 구현한다.
- 마찬가지로, AI의 응답 텍스트를 표시할 기본적인 자막 창을 구현한다. 이 단계에서는 투명화나 '항상 위' 같은 고급 기능은 잠시 보류하고, 일반적인 창 형태로 먼저 구현해도 무방하다.
- 사용자가 음성 입력을 시작하기 위해 누를 "말하기" 버튼 (Push-to-Talk Button)도 구현한다.
- 음성 인식(STT) 기능 구현:
- speech_recognizer.py 모듈을 생성한다.
- "말하기" 버튼이 눌리는 동안 마이크로부터 오디오를 녹음하는 기능을 구현한다.
- 녹음된 오디오 데이터를 외부 STT API(Google Speech-to-Text, Whisper API 등)로 보내고, 변환된 텍스트를 받아오는 기능을 구현한다.
- Gemini API 연동 및 입출력 연결:
- ai_engine.py 모듈은 텍스트 입력 창에서 온 텍스트든, speech_recognizer.py에서 온 텍스트든 동일하게 처리할 수 있도록 설계한다.
- 사용자가 "말하기" 버튼을 눌러 말을 하면 -> speech_recognizer가 음성을 텍스트로 변환 -> 이 텍스트를 ai_engine으로 전달 -> Gemini API로 전송 -> 응답을 받아서 -> ui_manager(자막)와 audio_player(음성)로 출력한다.
- 기본 음성 출력(TTS) 구현:
- audio_player.py 모듈에서, ai_engine.py가 받아온 응답 텍스트를 TTS API 또는 로컬 엔진을 통해 오디오 데이터로 변환한다.
- 변환된 오디오 데이터를 시스템 스피커로 재생하는 기능을 구현한다.
- 프로젝트 기본 구조 설정:
- 1단계 완료 시 결과물: 사용자가 키보드로 말을 걸면, AI가 목소리와 자막으로 대답하는, 가장 기본적인 형태의 챗봇 애플리케이션이 완성된다.
2단계: 장기 기억 시스템 구현
- 목표: AI가 단기 기억의 한계를 넘어, 과거의 중요한 대화 내용을 기억하고 현재 대화에 활용하게 만든다. 이를 통해 사용자와의 '관계'와 '역사'를 쌓아나가는 경험을 제공한다. RAG 파이프라인을 구축하는 단계다.
- 세부 개발 항목:
- 데이터베이스 설정:
- Qdrant 설치 및 실행: Docker를 사용하거나 로컬에 직접 설치하여 Qdrant 벡터 데이터베이스 서버를 실행한다.
- SQLite 초기화: database.py 같은 모듈을 만들어, memories (기억 메타데이터 저장), chat_history (전체 대화 로그 저장) 등의 테이블을 생성하는 초기화 코드를 작성한다.
- 기억 저장 파이프라인 구축:
- memory_manager.py 모듈을 생성한다.
- 핵심 정보 추출 기능: 대화가 끝난 후, 전체 대화 내용을 Gemini API에 보내 "이 대화에서 앞으로 기억할 만한 핵심 정보를 1~2문장으로 요약해줘" 라고 요청하는 함수를 구현한다.
- 벡터화 및 저장 기능:
- 요약된 텍스트를 sentence-transformers 라이브러리를 사용해 벡터로 변환한다.
- 변환된 벡터는 Qdrant에 저장하고, 벡터 ID와 원본 텍스트, 생성 시각 등은 SQLite의 memories 테이블에 저장하는 함수를 구현한다.
- 기억 인출 파이프라인 구축:
- 유사도 검색 기능: 사용자의 새로운 입력이 들어왔을 때, 해당 텍스트를 벡터로 변환한 뒤 Qdrant에 보내 의미적으로 가장 유사한 과거 기억(의 벡터 ID)을 검색해오는 함수를 구현한다.
- 메타데이터 조회: Qdrant로부터 받은 ID를 이용해 SQLite에서 실제 기억 텍스트를 조회하는 기능을 구현한다.
- 프롬프트에 기억 통합:
- ai_engine.py의 통합 프롬프트 구성 로직을 다시 수정한다.
- Gemini에 요청을 보내기 직전에, 기억 인출 파이프라인을 실행하여 검색된 장기 기억(RAG 결과)을 프롬프트의 '관련된 과거 기억' 섹션에 동적으로 추가하는 로직을 삽입한다.
- 데이터베이스 설정:
- 3단계 완료 시 결과물: "내가 무슨 게임 제일 좋아한다고 했지?" 라고 물으면, AI가 RAG를 통해 과거 기억을 검색하여 "팰월드 제일 좋아하잖아!" 라고 대답할 수 있게 된다. AI가 단발성 대화 기계를 넘어, 관계를 맺을 수 있는 존재로 발전한다.
3단계: 능동적 상황 인지 기능 구현
- 목표: 1단계에서 만든 수동적인 챗봇을 프로젝트의 핵심 철학인 **'먼저 말을 거는 AI'**로 진화시킨다. AI에게 '눈'을 달아주어 사용자의 상황을 인지하고 반응하게 만든다.
- 세부 개발 항목:
- 모니터링 모듈 구현:
- vision_monitor.py (또는 유사한 이름의 모듈)를 생성한다.
- 주기적으로 화면을 캡처하는 기능을 구현한다.
- 현재 활성화된 창의 제목을 가져오는 기능을 구현한다.
- 통합 프롬프트 구성 로직 개발:
- ai_engine.py를 대대적으로 수정한다.
- 단순히 텍스트만 보내는 것이 아니라, 캡처된 스크린샷 이미지와 활성 창 제목, 현재 시간 등의 정보를 모두 포함하는 "통합 멀티모달 프롬프트"를 구성하는 로직을 개발한다.
- 구조화된 JSON 응답 처리:
- 통합 프롬프트에, AI가 response_text, emotion, pose 등이 포함된 JSON 형식으로 응답하도록 강력하게 지시하는 부분을 추가한다.
- ai_engine.py에 Gemini로부터 받은 JSON 응답을 파싱하여, 각 키의 값을 추출하는 로직을 구현한다.
- 자동 응답 트리거 구현:
- main_app.py에 메인 루프를 구현한다.
- "활성 창의 제목이 바뀔 때" 또는 "일정 시간(예: 30초)마다 화면을 분석할지 여부를 결정"하는 등의 자동 응답 트리거 로직을 추가한다.
- 트리거가 발동하면, ai_engine을 통해 상황 인식 및 응답 생성 프로세스를 실행시킨다.
- 모니터링 모듈 구현:
- 2단계 완료 시 결과물: AI가 더 이상 사용자의 입력을 기다리지 않는다. 사용자가 코딩을 하거나 게임을 하면, 이를 스스로 인지하고 "코딩하고 있구나?" 와 같이 먼저 말을 거는, 프로젝트의 핵심 기능이 완성된다.
4단계: 시각적 플러그인 연동
- 목표: 지금까지 목소리와 자막으로만 존재했던 AI에게 '얼굴'과 '몸'을 부여한다. Python 코어 앱과 Unity/Live2D 플러그인을 연결하여, AI의 감정과 행동을 시각적으로 표현한다.
- 세부 개발 항목:
- WebSocket 서버 구현 (Python 측):
- plugin_server.py 모듈을 생성한다.
- FastAPI나 websockets 라이브러리를 사용하여, 연결을 기다리는 WebSocket 서버를 구현한다.
- ai_engine.py가 Gemini로부터 emotion과 pose가 포함된 JSON 응답을 파싱한 후, 이 두 값을 { "emotion": "...", "pose": "..." } 형태의 새 JSON으로 만들어 연결된 클라이언트(Unity)에게 전송하는 기능을 구현한다.
- 아바타 프로젝트 준비 (Unity/Live2D 측):
- Unity에서 새로운 프로젝트를 생성하고, Live2D 또는 Mate Engine SDK를 임포트한다.
- 사용할 아바타 모델을 씬(Scene)에 배치한다.
- 동작 목록 정의: 프롬프트에서 정의했던 사용 가능한 표정/몸짓 키워드(HAPPY, NOD 등)와 실제 아바타의 애니메이션 클립/표정 파일을 1:1로 매칭시키는 목록을 미리 정리해 둔다.
- WebSocket 클라이언트 구현 (Unity/C# 측):
- PluginClient.cs 스크립트를 생성한다.
- 앱 시작 시 Python의 WebSocket 서버(ws://localhost:PORT)에 접속하는 코드를 작성한다.
- 서버로부터 메시지를 비동기적으로 수신하고, 받은 JSON을 파싱하는 로직을 구현한다.
- 아바타 컨트롤러 구현 (Unity/C# 측):
- AvatarController.cs 스크립트를 생성하고 아바타 모델에 부착한다.
- PluginClient.cs가 파싱한 emotion과 pose 문자열을 받아, 미리 정의해 둔 동작 목록에 따라 실제 아바타의 표정을 바꾸고 애니메이션을 재생하는 함수(ExecuteAction(string emotion, string pose))를 구현한다.
- WebSocket 서버 구현 (Python 측):
- 4단계 완료 시 결과물: Python 코어 앱과 Unity 플러그인을 동시에 실행하면, AI가 말을 할 때마다 그 내용에 맞춰 아바타가 실시간으로 표정을 바꾸고 고개를 끄덕이는 등, 생동감 넘치는 완전체 AI 여자친구가 탄생한다.
5단계: 최종 다듬기 및 고도화
-
-
- 목표: 4단계까지 완료된 핵심 기능 프로토타입을 넘어, 사용자가 매일 사용하고 싶을 만큼 안정적이고 완성도 높은 정식 애플리케이션으로 만드는 단계입니다. 사용자 경험(UX)을 향상시키고, 성능을 최적화하며, 원문에서 언급되었던 추가적인 확장 기능들을 탐색합니다.
- 세부 개발 항목:
- UI/UX 고도화 (GUI Polishing):
- 시각적 효과 추가: 자막 창이 나타나고 사라질 때, 딱딱하게 나타나는 것이 아니라 부드러운 페이드인/아웃 애니메이션 효과를 추가하여 시각적 완성도를 높인다.
- 상태 표시기 개선: 상태 표시기 아이콘이 바뀔 때, 미세한 애니메이션을 적용하여 AI가 살아 숨 쉬는 듯한 느낌을 강화한다.
- 설정 UI 완성: 사용자가 폰트 종류, 크기, 색상, 외곽선, 창 투명도 등을 자유롭게 커스터마이징할 수 있는 설정 UI를 완성하고, '미리보기' 기능을 제공한다.
- 사용 편의성 개선: 자막 창이나 상태 표시기의 위치를 사용자가 옮겼을 때, 그 위치를 config.json에 정확히 저장하여 프로그램을 다시 시작해도 그대로 유지되도록 안정화한다.
- 성능 최적화 (Performance Optimization):
- API 호출 최적화: "응", "알겠어", "고마워" 처럼 자주 사용되는 짧은 응답의 경우, 한 번 생성된 오디오 파일을 로컬에 캐싱(caching)해두고, 다음부터는 API를 호출하지 않고 저장된 파일을 재생하여 비용과 딜레이를 줄인다.
- 시스템 부하 관리: 설정 창에 '성능 설정' 탭을 추가하여, 화면 분석 주기(초 단위)나 화면 변화 감지 임계치(%)를 사용자가 자신의 PC 사양에 맞게 조절할 수 있도록 한다.
- 병목 구간 분석: 주요 기능(API 요청, TTS 변환 등)의 처리 시간을 로그로 기록하여, 어떤 부분에서 딜레이가 가장 많이 발생하는지 분석하고 개선점을 찾는다.
- 고급 기능 확장 (Advanced Feature Expansion):
- 게임 연동 심화: Overwolf API나 각 게임에서 제공하는 API를 활용하여, 단순히 게임 화면을 보는 것을 넘어 '리그 오브 레전드' 같은 특정 게임의 실시간 데이터(예: 사용자의 KDA, 게임 시간, 승리/패배)를 직접 가져와 "지금 KDA가 엄청 좋네! 이번 판은 이기겠다!" 와 같이 훨씬 구체적인 대화를 생성한다.
- 로컬 툴 제어 연구: 사용자의 명시적인 허락 하에, "음악 틀어줘" 라고 말하면 로컬 음악 플레이어를 실행시키거나, 간단한 반복 작업을 위한 스크립트를 실행시켜주는 등의 '로컬 툴 연동' 기능을 연구하고 프로토타입을 제작한다.
- 안정성 및 오류 처리 강화 (Stability & Error Handling):
- 예외 처리: Gemini API 호출 실패, 인터넷 연결 끊김, Qdrant DB 연결 실패 등 발생 가능한 모든 예외 상황에 대한 처리 로직을 꼼꼼하게 추가한다. (예: 인터넷 연결이 끊기면 "어라, 인터넷 연결이 불안정하네... 잠시 후에 다시 시도해볼게." 라고 말하도록 처리)
- 방어 코드 작성: config.json 파일이나 DB 파일이 손상되었을 경우를 대비하여, 에러를 발생시키며 종료되는 대신 기본값으로 설정을 복원하고 프로그램을 실행하는 방어적인 코드를 작성한다.
- 로깅 시스템 구축: 디버깅을 용이하게 하기 위해, 단순한 print문이 아닌 logging 모듈을 사용하여 날짜별로 로그 파일을 생성하고, 오류 발생 시 상세한 정보를 기록하도록 시스템을 구축한다.
- AI 개인화 심화 (Deeper AI Personalization):
- 성격 커스터마이징: 설정 창에 'AI 성격 설정' 탭을 추가하여, 사용자가 AI의 기본 시스템 프롬프트를 직접 수정할 수 있는 고급 텍스트 상자를 제공한다. (예: "다정한 여자친구" -> "까칠하지만 속은 따뜻한 츤데레")
- 수다스러움 조절: AI의 능동적 응답 빈도(쿨다운 시간, 분석 주기)를 '차분함'부터 '활발함'까지 사용자가 슬라이더로 쉽게 조절할 수 있는 기능을 구현한다.
- UI/UX 고도화 (GUI Polishing):
-
3. 코어 애플리케이션 (Python) 세부 모듈 구성
모듈 파일명 (예시) | 주요 역할 | 다른 모듈과의 상호작용 |
---|---|---|
main.py | *메인 애플리케이션 실행점 *- 모든 모듈의 객체를 생성하고 초기화. - PyQt의 메인 이벤트 루프를 시작. - 각 모듈의 시그널(Signal)과 슬롯(Slot)을 연결하여 전체 시스템을 지휘. | (총괄) UIManager, AIEngine 등 모든 객체를 생성하고 서로 연결시켜 줌. |
ui_manager.py | *GUI 렌더링 및 사용자 입력 처리 *- PyQt를 이용해 화면에 투명 오버레이 UI(자막 창, 상태 표시기)를 생성하고 업데이트. - 사용자의 텍스트 입력, 설정 변경 등의 이벤트를 받아 다른 모듈로 전달. | • (출력) AIEngine으로부터 받은 대사를 자막 창에 표시. • (입력) 사용자가 입력한 텍스트를 AIEngine에 전달. |
ai_engine.py | *AI 프로세스 *- "하나의 거대한 프롬프트"를 구성. - Gemini API와 통신하고, 구조화된 JSON 응답을 파싱. - 응답 결과를 다른 모듈들이 사용할 수 있도록 분배. | • (입력) ActivityMonitor, MemoryManager 등으로부터 컨텍스트 정보를 받음. • (출력) 파싱된 결과를 UIManager, AudioPlayer, PluginServer로 전달. |
activity_monitor.py | *사용자 활동 감지기 *- 백그라운드 스레드에서 주기적으로 PC 활동을 모니터링. - 화면 스크린샷 캡처, 활성 창 제목 가져오기. - 의미 있는 변화가 감지되면 신호를 발생. | • (출력) 감지된 화면 정보(이미지, 창 제목)를 AIEngine이 사용할 수 있도록 신호(Signal)를 보냄. |
memory_manager.py | *장기 기억 관리자 *- RAG 파이프라인의 실제 로직. - 기억 저장: 텍스트를 벡터화하여 Qdrant/SQLite에 저장. - 기억 인출: 텍스트와 유사한 과거 기억을 Qdrant/SQLite에서 검색. | • AIEngine이 프롬프트를 구성하기 전에 retrieve_memory 함수를 호출. • AIEngine이 응답을 받은 후에 save_memory 함수를 호출. |
audio_player.py | *음성 출력기 *- 텍스트를 받아 TTS API 또는 로컬 엔진을 통해 음성 데이터로 변환. - 변환된 오디오 데이터를 시스템 스피커로 재생. | • (입력) AIEngine으로부터 재생할 텍스트(response_text)를 받음. |
speech_recognizer.py | 음성 인식 처리기 - 마이크로부터 오디오 입력을 실시간으로 캡처. - 캡처된 오디오 데이터를 STT 엔진/API로 전송하여 텍스트로 변환. - 변환된 텍스트를 AIEngine으로 전달. | • (입력) UIManager의 "말하기" 버튼 클릭 이벤트를 통해 녹음 시작/중지 신호를 받음. • (출력) STT로 변환된 최종 텍스트를 AIEngine으로 전달. AIEngine은 이 텍스트를 키보드 입력과 동일하게 취급. |
plugin_server.py | *플러그인 통신 서버 *- 백그라운드 스레드에서 WebSocket 서버를 실행. - 연결된 Unity/Live2D 클라이언트에게 아바타 제어 명령을 실시간으로 전송. | • (입력) AIEngine으로부터 아바타 제어 명령(emotion, pose)을 받음. • (출력) 연결된 Unity 클라이언트로 JSON 메시지를 브로드캐스트. |
config_manager.py | *설정 관리자 *- config.json 파일에서 API 키, UI 설정 등을 로드. - 사용자가 변경한 설정을 파일에 저장. | • (공용) 거의 모든 모듈이 시작될 때 설정을 읽기 위해 이 모듈을 사용함. |
이 계획은 언제든 변경될 수 있습니다. 긴 글 읽어주셔서 감사합니다.