Skip to content
tryna-teamPublic

About

tryna FastAPI repository

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

260 Commits

Folders and files

Repository files navigation

🧠 tryna brain

일정을 이해하고 맥락을 연결해 필요한 준비·실행 항목을 추천하는 FastAPI 기반 분석 서버

tryna brain은 tryna 서비스의 일정 파싱 및 추천 전용 서버입니다. Spring 서버와 역할을 분리하여 자연어 일정 파싱, Neo4j 기반 의미 매핑과 후보 조회, Upstage 기반 임베딩 및 추천 문구 정제를 담당합니다.


📌 소개

tryna는 사용자가 입력한 짧은 일정의 맥락을 이해하고, 일정 전후에 필요한 할 일을 제안하는 일정 서비스입니다.

tryna brain은 다음 두 기능을 제공합니다.

  • 자연어 일정에서 날짜, 시간, 장소 등 일정 후보 정보 추출
  • 일정 유형·맥락·장소를 분석하여 준비 및 실행 항목 추천

예를 들어 사용자가 다음과 같이 입력하면:

금요일 3시 팀플 회의

파싱 API는 다음과 같이 일정 후보 정보를 반환합니다.

{
  "tempEventId": "tmp_f7258568-0374-4710-8473-329576255448",
  "eventTitle": "금요일 3시 팀플 회의",
  "draftRevision": 1,
  "startDate": "2026-08-14",
  "dateSource": "RELATIVE_EXPRESSION",
  "startTime": "15:00:00",
  "placeCandidate": null,
  "toEmbedding": ["팀플", "회의"],
  "isAllDayCandidate": false,
  "needsConfirmation": false,
  "warnings": []
}

이후 추천 API는 Neo4j 관계·벡터 후보와 Upstage LLM을 활용하여 회의 시간 확인, 얘기할 내용 정리와 같은 준비·실행 항목을 최대 3개까지 제안합니다.


🧩 Server Responsibility

tryna 백엔드는 역할에 따라 Spring 서버와 FastAPI brain 서버로 분리합니다.

Spring Server

Spring 서버는 서비스 운영에 필요한 핵심 백엔드 기능을 담당합니다.

  • 회원/비회원 인증 및 사용자 계정 관리
  • 일정 CRUD 및 캘린더 조회
  • 추천 요청 중 최신 draftRevision 등록
  • 추천 결과 저장
  • 알림 및 외부 캘린더 연동
  • DB 트랜잭션 및 권한 검증

FastAPI Brain Server

FastAPI brain 서버는 일정 문장을 이해하고 추천 후보를 생성·정제하는 분석 엔진 역할을 담당합니다.

  • Rule Based Parser와 Kiwi 기반 자연어 일정 파싱
  • Upstage 임베딩 기반 일정 유형·맥락·장소 의미 매핑
  • Neo4j 관계 및 벡터 기반 추천 후보 조회
  • Upstage LLM 기반 추천 항목 선택 및 displayText 정제
  • 시간 맥락 검증과 TIMED_ACTION·UNTIMED_PREP 분류
  • Redis 기반 최신 draftRevision 검증
  • Spring 서버에 파싱 및 추천 결과 반환

🛠 기술 스택

Type Tool
Language Python
Framework FastAPI
ASGI Server Uvicorn
Database Neo4j
Cache Redis
LLM Upstage
NLP Kiwi
Configuration pydantic-settings python-dotenv
Package Manager pip
Version Control Git GitHub
Collaboration Notion

🏗 Architecture

Client
   │
   ▼
Spring Server
   │
   │ 내부 API 인증 및 일정 파싱/추천 요청
   ▼
FastAPI Brain Server
   │
   ├── Rule Based Parser + Kiwi
   │     날짜, 시간, 장소 등 일정 후보 추출
   │
   ├── Upstage Embedding + Neo4j
   │     의미 매핑 및 관계·벡터 추천 후보 조회
   │
   ├── Upstage LLM
   │     추천 항목 선택 및 displayText 정제
   │
   └── Redis/Valkey
         최신 draftRevision 검증
   │
   ▼
Spring Server
   │
   │ 추천 결과 저장/응답
   ▼
Client

🔄 Recommendation Pipeline

Step Component Responsibility
D101 Schedule Context + Upstage Embedding 일정 정보를 임베딩 입력으로 구성하고 쿼리 벡터 생성
D102 Neo4j EventType, Context, PlaceType 의미 매핑 및 관계·벡터 추천 후보 결합
D103 Upstage LLM 후보 중 최대 3개를 선택하고 자연스러운 displayText로 정제
D104 Temporal Validator 날짜 맥락 검증 및 TIMED_ACTION·UNTIMED_PREP 확정
D105 Suggestion Composer 순위와 부모 임시 일정 ID를 검증하고 최종 응답 구성

Spring 서버는 tempEventId별 최신 draftRevision을 Redis에 등록합니다. FastAPI는 D101~D105 단계 사이에서 recommendation:latest-revision:{tempEventId}를 조회하고, 오래된 요청이면 409 STALE_DRAFT_REVISION_409로 후속 처리를 중단합니다. Redis를 사용할 수 없을 때에는 추천 파이프라인을 계속 실행하는 fail-open 정책을 적용합니다.

Upstage에는 분석과 추천 정제에 필요한 일정 정보 및 Neo4j 후보만 전달합니다. 개인정보나 불필요한 민감 정보는 전달하지 않는 것을 원칙으로 합니다.


📂 Project Structure

brain/
├─ app/
│  ├─ main.py
│  ├─ api/
│  │  └─ v1/
│  │     ├─ router.py
│  │     └─ routes/
│  │        ├─ event_previews.py
│  │        ├─ health.py
│  │        └─ recommendations.py
│  ├─ core/
│  │  ├─ config.py
│  │  ├─ deps.py
│  │  ├─ error_code.py
│  │  ├─ handlers.py
│  │  ├─ internal_auth.py
│  │  ├─ responses.py
│  │  └─ valkey_client.py
│  ├─ graph/
│  │  ├─ neo4j_client.py
│  │  ├─ models/
│  │  └─ repositories/
│  ├─ schemas/
│  │  ├─ recommendation/
│  │  ├─ event_preview.py
│  │  └─ health.py
│  └─ services/
│     ├─ event_preview_service.py
│     ├─ parser_service.py
│     └─ recommendation/
│        ├─ schedule_context_service.py
│        ├─ candidate_search_service.py
│        ├─ refinement_service.py
│        ├─ temporal_validation_service.py
│        ├─ suggestion_compose_service.py
│        └─ revision_guard_service.py
├─ tests/
├─ nginx/
├─ Dockerfile
├─ requirements.txt
├─ .env.example
└─ README.md

📦 Package Responsibility

Package Responsibility
app.main FastAPI 앱 진입점과 Neo4j·Redis 생명주기 관리
app.core 환경변수, 의존성, 내부 인증, 공통 응답·예외 및 Redis 연결 관리
app.api 헬스체크, 일정 미리보기, 추천 API 엔드포인트 정의
app.graph Neo4j 연결과 일정 의미 매핑·추천 후보 조회
app.schemas 파싱·추천 파이프라인의 요청/응답 모델 정의
app.services 자연어 파싱 및 D101~D105 추천 비즈니스 로직 수행

🚀 시작하기

Python 3.13 환경을 권장합니다.

1. 가상환경 생성

python3.13 -m venv .venv

2. 의존성 설치

.venv/bin/python -m pip install -r requirements.txt

Windows PowerShell에서는 .venv/bin/python 대신 .\.venv\Scripts\python.exe를 사용합니다.

3. 환경변수 파일 생성

cp .env.example .env

로컬 Neo4j, Redis/Valkey 및 Upstage API 정보를 .env에 설정합니다. VALKEY_HOST를 비워두면 Redis 기반 기능은 비활성화되며 서버는 계속 실행됩니다.

4. 서버 실행

.venv/bin/python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

테스트는 다음 명령어로 실행합니다.

PYTHONPATH=. .venv/bin/python -m pytest

📖 API Documentation

FastAPI brain 서버는 FastAPI 기본 Swagger UI를 사용합니다.

http://127.0.0.1:8000/docs

비즈니스 API는 X-Internal-Api-Key 헤더로 Spring 서버와의 내부 통신을 인증합니다. 헬스체크는 인증 대상에서 제외됩니다.

Method Path Description
GET /api/v1/health Neo4j 및 Redis 연결 상태 확인
POST /api/v1/event-previews 자연어 일정 파싱 및 미리보기 생성
POST /api/v1/recommendations D101~D105 추천 파이프라인 실행

추천 API의 stop_after_step 쿼리는 개발 환경에서 중간 결과를 확인할 때만 사용할 수 있으며 운영 환경에서는 403을 반환합니다.


🔗 API 사용 및 연동 흐름

클라이언트는 brain API를 직접 호출하지 않습니다. Spring 서버가 사용자 인증과 요청 검증을 수행한 뒤 X-Internal-Api-Key를 포함해 brain API를 호출합니다.

1. 최초 일정 미리보기 요청

새로운 일정 작성을 시작할 때 tempEventId는 JSON null로 전달하거나 필드를 생략합니다. 문자열 "null"을 전달하면 실제 임시 일정 ID로 취급되므로 사용하지 않습니다.

{
  "tempEventId": null,
  "eventTitle": "다음주 금요일 3시부터 4시까지 회의",
  "draftRevision": 0,
  "selectedDate": "2026-08-13"
}

brain은 최초 요청에 새로운 tempEventId를 생성하고 요청의 draftRevision을 그대로 반환합니다.

{
  "tempEventId": "tmp_f7258568-0374-4710-8473-329576255448",
  "eventTitle": "다음주 금요일 3시부터 4시까지 회의",
  "draftRevision": 0,
  "startDate": "2026-08-21",
  "dateSource": "RELATIVE_EXPRESSION",
  "endDate": null,
  "startTime": "15:00:00",
  "endTime": "16:00:00",
  "placeCandidate": null,
  "toEmbedding": ["회의"],
  "isAllDayCandidate": false,
  "needsConfirmation": false,
  "warnings": []
}

2. 입력 수정 요청

같은 일정을 작성하는 동안에는 이전 응답의 tempEventId를 그대로 전달하고, 호출하는 쪽에서 draftRevision을 증가시킵니다. brain은 draftRevision을 자동으로 증가시키지 않습니다.

{
  "tempEventId": "tmp_f7258568-0374-4710-8473-329576255448",
  "eventTitle": "다음주 금요일 4시부터 5시까지 회의",
  "draftRevision": 1,
  "selectedDate": "2026-08-13"
}
  • 동일한 일정 작성 과정에서는 같은 tempEventId를 유지합니다.
  • 일정 저장, 작성 취소 또는 새로운 일정 작성을 시작하면 호출하는 쪽에서 기존 tempEventId를 초기화합니다.
  • brain은 임시 일정의 저장·취소 상태를 보관하지 않습니다.
  • 추천 파이프라인은 tempEventId별 최신 draftRevision을 기준으로 오래된 요청의 후속 단계를 중단합니다.

3. 날짜 결정 우선순위

일정 시작 날짜는 다음 순서로 결정합니다.

  1. 일정 원문에서 파싱한 날짜
  2. 요청으로 전달된 selectedDate
  3. Asia/Seoul 기준 오늘

dateSource는 날짜가 결정된 출처를 나타냅니다.

Value Description
EXPLICIT 사용자가 절대 날짜를 직접 입력
RELATIVE_EXPRESSION 내일, 다음 주 금요일 등의 상대 날짜 표현을 파싱
SELECTED_DATE 원문에 날짜가 없어 요청의 selectedDate 사용
DEFAULT_TODAY 원문과 요청에 날짜가 없어 Asia/Seoul 기준 오늘 사용

4. 일정 미리보기 결과를 추천 요청으로 변환

일정 미리보기 응답과 추천 요청은 필드 이름이 일부 다르므로 Spring 서버에서 다음과 같이 변환합니다.

Event Preview Response Recommendation Request
startDate startDateCandidate
startTime startTimeCandidate
endDate endDateCandidate
endTime endTimeCandidate
dateSource startDateSource
toEmbedding embeddingWords

추천 요청에는 일정 입력 출처를 나타내는 sourceType도 포함해야 합니다.

{
  "tempEventId": "tmp_f7258568-0374-4710-8473-329576255448",
  "draftRevision": 1,
  "eventTitle": "다음주 금요일 4시부터 5시까지 회의",
  "sourceType": "USER_NATURAL_LANGUAGE",
  "startDateCandidate": "2026-08-21",
  "startTimeCandidate": "16:00:00",
  "endDateCandidate": null,
  "endTimeCandidate": "17:00:00",
  "startDateSource": "RELATIVE_EXPRESSION",
  "placeCandidate": null,
  "description": null,
  "embeddingWords": ["회의"]
}
sourceType Description
USER_NATURAL_LANGUAGE 사용자가 자연어로 입력한 일정
USER_MANUAL_EDIT 사용자가 미리보기 정보를 직접 수정한 일정

✅ Health Check

GET /api/v1/health

Response:

{
  "status": "UP",
  "timestamp": "2026-08-13T09:00:00Z",
  "components": {
    "neo4j": {
      "status": "UP",
      "detail": null
    },
    "redis": {
      "status": "UP",
      "detail": null
    }
  }
}

Redis/Valkey가 설정되지 않은 로컬 환경에서는 components.redis.status가 DISABLED로 표시됩니다. 현재 전체 상태와 HTTP 상태 코드는 Neo4j 연결 상태를 기준으로 결정합니다.


📦 Common Response

비즈니스 예외와 요청값 검증 오류는 공통 응답 객체를 사용합니다.

Error:

{
  "success": false,
  "code": "COMMON_400",
  "message": "잘못된 요청입니다.",
  "data": null
}

일정 미리보기, 추천 성공 응답 및 헬스체크 응답은 각 API의 응답 스키마를 직접 반환합니다. 따라서 모든 성공 응답이 success, code, message, data 형식으로 감싸지지는 않습니다.


⚠️ Error Handling

공통 예외 처리는 app/core에서 관리합니다.

현재 주요 에러 코드는 다음과 같습니다.

Code HTTP Status Description
COMMON_400 400 잘못된 요청
INTERNAL_AUTH_401 401 서버 간 인증 실패
COMMON_403 403 현재 환경에서 사용할 수 없는 기능
COMMON_404 404 리소스 없음
STALE_DRAFT_REVISION_409 409 최신 입력이 존재하는 이전 추천 요청 중단
COMMON_422 422 요청값 검증 실패
COMMON_500 500 서버 내부 오류
INTERNAL_AUTH_500 500 내부 API 인증 설정 누락
EMBEDDING_400 400 임베딩 입력값 누락
EMBEDDING_503 503 임베딩 모델 연동 불가
NEO4J_503 503 Neo4j 연결 불가
LLM_503 503 LLM 연동 불가

⚙️ Environment Configuration

brain 서버는 .env 기반으로 환경변수를 관리합니다.

APP_NAME=tryna brain
APP_ENV=local
API_V1_PREFIX=/api/v1
ROOT_PATH=
INTERNAL_API_KEY=local-internal-api-key

VALKEY_HOST=localhost
VALKEY_PORT=6379
VALKEY_PASSWORD=

NEO4J_URI=neo4j://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=password
NEO4J_DATABASE=neo4j

UPSTAGE_API_KEY=
UPSTAGE_API_KEY_MULTI=
UPSTAGE_QUERY_EMBEDDING_MODEL=solar-embedding-1-large-query
UPSTAGE_PASSAGE_EMBEDDING_MODEL=solar-embedding-1-large-passage
UPSTAGE_EMBEDDING_TIMEOUT_SECONDS=10
UPSTAGE_CHAT_MODEL=solar-pro3
UPSTAGE_CHAT_TIMEOUT_SECONDS=20

D102_EMBEDDING_DIMENSION=4096
D102_EVENT_TYPE_MIN_SCORE=0.61
D102_CONTEXT_MIN_SCORE=0.63
D102_PLACE_TYPE_MIN_SCORE=0.63
D102_RECOMMENDATION_MIN_SCORE=0.62

운영 환경(APP_ENV=prod)에서는 Redis/Valkey 연결에 TLS와 시스템 CA 인증서 검증을 적용합니다. .env는 Git에 커밋하지 않고 .env.example만 공유합니다.


🔐 Security

민감 정보는 저장소에 커밋하지 않습니다.

다음 값은 로컬 .env 또는 배포 환경의 secret으로 관리합니다.

  • INTERNAL_API_KEY
  • NEO4J_PASSWORD
  • VALKEY_PASSWORD
  • UPSTAGE_API_KEY
  • UPSTAGE_API_KEY_MULTI

.gitignore에 다음 파일과 디렉터리를 제외하도록 설정합니다.

.env
.env.local
.env.*.local
.venv
__pycache__/

✅ Current Setup Checklist

  • 자연어 일정 미리보기 API 구현
  • D101~D105 추천 파이프라인 구현
  • Neo4j 연결 및 관계·벡터 추천 후보 조회
  • Upstage 임베딩 및 추천 문구 정제
  • Redis/Valkey 연결 및 최신 revision 검증
  • 내부 API 키 인증
  • 공통 예외 처리와 Health Check API
  • Docker 및 GitHub Actions CI/CD 구성
  • pytest 테스트 구성

🗺 개발 로드맵

  • Python 및 FastAPI 실행 환경 구축
  • 자연어 일정 1차 파싱과 Kiwi 연동
  • Neo4j 연결 및 지식베이스 구축
  • Neo4j 의미 매핑과 추천 후보 조회 구현
  • 관계·벡터 추천 후보 결합
  • Upstage 임베딩 및 LLM 연동
  • 추천 항목 시간 맥락 검증과 최종 응답 구성
  • Redis 기반 오래된 추천 요청 후속 처리 차단
  • Spring 서버 내부 API 연동

About

tryna FastAPI repository

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages