소개
안녕하세요. 저는 Ai를 활용한 개발을 좋아하는 미대생이며,
기록 및 자기계발용 서비스를 만들어 보았습니다.
평소 일기작성을 좋아했으며 근 2년간 거의 매일 작성해 왔습니다. 어떻게 하면, 일기를 통한 성장을 더욱 극대화 할 수 있을지 고민했습니다. 그 결과로 만들어진 일종의 자기계발 도구입니다.
연초부터 자기계발을 위한 프로세스를 구축하고자 하였고, 2번의 실패 후 여러 개선을 거쳐 완성한 시스템입니다. 또한, 실제로 유용하게 잘 쓰고 있기에 소개하고자 합니다.
자세한 소개 영상입니다.
핵심 기능은 두 가지 입니다.
하루동안의 활동들을 짧은 코멘트와 함께 기록하여 밤에 일기를 작성할 때, 하루를 더 면밀히 돌아 볼 수 있도록 도와줍니다.
Ai가 사용자의 목표, 성향( +MBTI), 활동을 기반으로 일기를 분석하여 질문을 만듭니다. 이 질문에 답변하는 과정에서 사용자는 자신의 감정을 더욱 자세히 들여다 보거나, 편견과 같은 자신의 사고방식 습관을 인지할 수 있습니다.
결국, 이 서비스는 매일 Ai가 자신의 일기를 기반으로 생성한 질문에 답변하는 과정에서, 사용자의 사고방식에 점진적인 변화를 일으켜 원하는 방향으로의 성장을 도와줍니다.
이해를 돕기 위한 데이터 흐름도입니다.
진행 방법
클로드를 활용하여 개발을 진행했습니다. 구조는 이렇습니다.
사용자 앱(React): 활동 기록 및 설정 관리
서버(FastAPI): 사용자 데이터 처리 및 AI 분석 중개
AI 모델 파이프라인: Gemini(초기 분석, 질문 생성) + GPT(질문 정제) 이중 구조
Notion API: 사용자별 타임라인, 일기, 성찰 질문 저장소에 문서 생성
데이터 흐름: 활동 기록 → 타임라인 생성 → 일기 작성 → AI 분석 → 성찰 질문 생성
시스템 작동 시퀀스 다이어그램입니다.
이 서비스의 핵심이 되는 질문 생성은, pydantic ai를 활용하여 코드를 구성했습니다.
질문 생성 로직입니다.
gemini 2.0 flash thinking를 사용하여 여러 데이터를 바탕으로 일기를 분석하고 여러 질문이 포함된 긴 텍스트를 생성합니다.
Gpt4o-mini를 사용하여 그 중 5개만 추려 긴 텍스트를 정제합니다.
아래는 해당 기능에 대한 이미지와 파이썬 코드입니다.
from pydantic import BaseModel
from typing import List
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.openai import OpenAIModel
import google.generativeai as genai
import os
import json
class ReasoningResult(BaseModel):
analysis: str
questions: List[str]
class QuestionsResponse(BaseModel):
questions: List[str]
class ReflectionAnalyzer:
def __init__(self, gemini_api_key: str = None):
if not gemini_api_key:
raise ValueError("Gemini API key is required")
genai.configure(api_key=gemini_api_key)
self.generation_config = {
"temperature": 0.7,
"top_p": 0.95,
"top_k": 64,
"max_output_tokens": 65536,
"response_mime_type": "text/plain",
}
self.model = genai.GenerativeModel(
model_name="gemini-2.0-flash-thinking-exp-01-21",
generation_config=self.generation_config,
)
self.gpt4_mini_model = OpenAIModel(
"gpt-4o-mini",
api_key=os.getenv("OPENAI_API_KEY")
)
self.formatter_agent = Agent(
self.gpt4_mini_model,
deps_type=dict,
result_type=QuestionsResponse,
system_prompt="""Gemini가 생성한 분석과 질문들을 검토하여, 가장 통찰력 있고 깊이 있는 질문 5개를 선택하고 정제하여 제시합니다.
선택 기준:
1. 구체적이고 명확한 질문
2. 깊은 자기성찰을 유도하는 질문
3. 감정, 행동, 가치관을 균형있게 다루는 질문
4. MBTI 특성을 고려한 질문
5. 사용자의 목표와 선호도를 반영한 질문
응답은 반드시 다음 JSON 형식으로만 출력해야 하며, 정확히 5개의 질문이어야 합니다:
{"questions": ["질문1", "질문2", "질문3", "질문4", "질문5"]}"""
)
self.user_info = {
'goals': None,
'preferences': None
}
async def get_gemini_analysis(self, journal_data: dict, mbti: str) -> ReasoningResult:
"""Gemini를 사용하여 활동 기록과 일기를 분석하고 성찰 질문 생성"""
# 타임라인 데이터를 문자열로 변환
timeline_text = ""
for activity in journal_data["timeline"]:
timeline_text += f"\n시간: {activity['time']}"
timeline_text += f"\n활동: {activity['activity']}"
if 'thoughts' in activity:
timeline_text += f"\n생각/감정: {activity['thoughts']}"
timeline_text += "\n"
prompt = f"""당신은 사용자의 하루 활동과 일기를 깊이있게 이해하고, 의미 있는 자기성찰을 돕는 전문가입니다.
객관적인 활동 기록과 순간의 감정, 그리고 하루를 정리한 일기를 모두 고려하여 사용자의 더 깊은 자기이해를 돕는 분석과 질문을 제시해주세요.
사용자 정보:
- MBTI: {mbti}
- 목표: {self.user_info.get('goals', '정보 없음')}
- 선호도: {self.user_info.get('preferences', '정보 없음')}
다음 관점들을 고려하여 분석과 5개의 질문을 생성해주세요:
1. 순간의 감정과 회고 시점의 감정 차이
2. 활동과 감정의 연관성
3. 하루 동안의 감정/생각 변화 패턴
4. 현재 상황과 장기 목표의 연결점
5. 사용자의 행동 패턴과 동기
6. 잠재된 고정관념이나 편향된 시각
7. MBTI 특성과 관련된 통찰
8. 선호하는 학습/행동 방식의 효과성
=== 하루 활동 타임라인 ===
{timeline_text}
=== 일기 내용 ===
{journal_data["journal"]}
분석과 질문을 다음과 같은 형식으로 작성해주세요:
[분석]
여기에 2-3문단의 분석을 작성해주세요.
[질문]
1. 첫 번째 질문
2. 두 번째 질문
..."""
chat = self.model.start_chat()
response = chat.send_message(prompt)
content = response.text
# 분석과 질문 부분 분리
try:
parts = content.split('[질문]')
analysis = parts[0].replace('[분석]', '').strip()
questions_text = parts[1].strip()
questions = []
for line in questions_text.split('\n'):
line = line.strip()
if line and '.' in line:
question = line.split('.', 1)[1].strip()
questions.append(question)
except Exception as e:
print(f"Error parsing Gemini response: {str(e)}")
print(f"Raw response: {content}")
analysis = content
questions = []
return ReasoningResult(
analysis=analysis,
questions=questions
)
async def generate_questions(self, journal_content: str, mbti: str, goals: str = None, preferences: str = None) -> List[str]:
try:
# 사용자 정보 업데이트
self.user_info['goals'] = goals
self.user_info['preferences'] = preferences
# 1. Gemini로 분석 및 초기 질문 생성
result = await self.get_gemini_analysis(journal_content, mbti)
print(f"Gemini questions generated: {len(result.questions)} questions")
# 2. GPT-4o-mini로 질문 정제 및 포맷팅
formatted = await self.formatter_agent.run(
f"""다음 분석과 질문들을 검토하여 가장 통찰력 있는 5개의 질문을 선택하고 정제해주세요.
분석 내용:
{result.analysis}
생성된 질문들:
{json.dumps(result.questions, ensure_ascii=False, indent=2)}""",
deps={"mbti": mbti}
)
return formatted.data.questions
except Exception as e:
print(f"Error in generate_questions: {str(e)}")
return [
"질문생성에 오류가 있습니다. gemini api키를 확인해주세요.",
"제가 직접 수정하는 게 빨라서, 디스코드 통해 연락주세요!",
"질문생성에 오류가 있습니다. gemini api키를 확인해주세요.",
"제가 직접 수정하는 게 빨라서, 디스코드 통해 연락주세요!",
"감사합니다."
]
결과와 배운 점
제가 아닌 다른 사람도 해당 서비스를 자신의 노션페이지, api를 활용하여 무료로 사용할 수 있도록 만들었습니다.
이 과정에서 기존의 노션 템플릿들에 대해 간단한 프론트와 서버만으로 커스터마이징된 ai 기능 제공 가능성을 보았습니다. 노션 유료 유저의 경우에는 자동화 버튼기능으로 별도의 프론트를 구축하지 않아도 됩니다. 또한, 노션이 아닌 다른 통합 서비스가 있을지도 모르겠습니다.