카톡·DM 대화를 붙여넣으면 호감도, 답장 추천, 위험 신호, 다음 행동을 AI가 분석해드려요.
Translation pending
SocialTypeScript · JavaScriptGitHub @yeomhojun1OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
연애 대화 분석 AI - 카톡/DM 대화를 붙여넣으면 호감도, 답장 추천, 위험 신호를 분석 (Next.js 15 + Claude API + Kakao 로그인)
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗🔗 Live Demo: https://yeonae-ai.vercel.app
카카오톡·DM 대화를 붙여 넣으면 상대의 호감도, 좋은 신호와 위험 신호, 보낼 만한 답장, 다음에 할 행동을 정리해 주는 웹 서비스입니다.
썸을 타거나 소개팅을 한 뒤, 상대와 나눈 대화를 친구에게 보여 주며 "이 사람 나한테 관심 있는 것 같아?"라고 묻는 경우가 많습니다. 이 서비스는 그 친구 역할을 AI가 맡습니다. 대화를 넣으면 AI가 읽고 호감도 점수와 근거, 답장 예시를 정리해 줍니다.
여기에 더해, 지금까지 분석한 대화 기록을 "서운했던 순간"처럼 말뜻으로 다시 찾아보는 검색도 만들었습니다.
1. 입력 화면 — 대화를 붙여 넣거나, 카카오톡에서 내보낸 .txt 파일을 올립니다. 데모에서는 위쪽의 샘플 대화 버튼으로 바로 채울 수 있습니다.
2. 결과 화면 — 호감도 점수(0~100), 관계 흐름 요약, 좋은 신호와 참고 사항이 나옵니다. 아래로 내리면 답장 추천과 다음 행동이 이어집니다.
https://yeomhojun1.github.io/yeonae-ai/
설치나 회원가입, 로그인 없이 브라우저에서 바로 열립니다.
알아 두실 점:
대화를 보내면 Anthropic의 AI(Claude)가 대화를 읽고 결과를 돌려줍니다. 이때 AI가 자유롭게 글을 쓰게 두지 않고, "점수는 0100 사이 정수, 호감 수준은 '매우 높음매우 낮음' 다섯 가지 중 하나, 신호는 좋음/위험/참고 중 하나"처럼 정해진 양식의 빈칸을 채우게 했습니다. 시험 답안지를 주관식이 아니라 정해진 칸이 있는 답안지로 바꾼 것과 비슷합니다. 덕분에 결과가 매번 같은 모양으로 나와 화면에 깨지지 않게 보여 주고 저장할 수 있습니다.
보통 검색은 입력한 단어가 들어 있는 글을 찾습니다. 그런데 사람은 서운함을 "서운해"라고만 말하지 않습니다. "굳이 말 안 해도 알지 않아?", "또? 세 번째잖아"처럼 돌려 말합니다. 단어 검색으로는 이런 대화를 "서운했던 순간"으로 찾을 수 없습니다.
그래서 문장의 뜻을 지도 위의 좌표로 바꾸는 방법(임베딩)을 썼습니다.
이렇게 하면 단어가 하나도 겹치지 않아도 뜻이 비슷한 대화를 찾을 수 있습니다. 좌표로 바꾸는 작업은 유료 AI가 아니라 서버 안에서 직접 돌아가는 무료 모델(multilingual-e5-small)로 처리해, 검색을 아무리 많이 해도 AI 비용이 들지 않습니다.
검색이 "잘 되는 것 같다"는 느낌만으로는 판단할 수 없어서, 시험을 보듯 점수를 매겼습니다.
점수는 두 가지를 함께 봅니다.
F1은 이 둘을 하나로 합친 점수로, 0~1 사이입니다. 둘 다 높아야 높게 나옵니다.
| 시험 | 질문 수 | 대화 수 | 결과 수 | F1 |
|---|---|---|---|---|
| 첫 시험 | 3개 | 8개 | 상위 3개 | 0.40 |
| 첫 시험 | 3개 | 8개 | 상위 5개 | 0.38 |
| 늘린 시험 | 12개 | 16개 | 상위 5개 | 0.25 |
처음에는 질문 3개로 재서 F1 0.40이 나왔습니다. 그런데 질문 3개짜리 시험은 운이 크게 작용합니다. 질문을 12개로, 대화를 16개로 늘려 다시 재자 같은 조건(상위 5개)에서 0.38이던 점수가 0.25로 내려갔습니다. 처음 점수는 시험이 너무 작아서 생긴 착시였던 셈입니다.
참고로 정답이 1개뿐인 질문에 결과를 5개 보여 주면, 정답을 찾아도 정밀도는 최대 20%입니다. 그래서 F1 자체가 낮게 나오는 구조이고, 이 점수는 서로 비교하는 용도로 봐야 합니다.
뜻으로 찾는 검색은 "데이트 제안" 같은 짧은 질문에서 비슷한 분위기의 다른 대화(호감 표현)를 1등으로 올리는 실수를 했습니다. 그래서 단어가 겹치는 정도를 보는 단어 검색 순위와 뜻 검색 순위를 합쳐 최종 순위를 정하는 방식(하이브리드 검색)을 시험했습니다.
| 12문항 시험 (상위 5개) | 재현율 | 정밀도 | F1 |
|---|---|---|---|
| 뜻 검색만 | 53% | 17% | 0.25 |
| 하이브리드 검색 | 59% | 20% | 0.30 |
12문항 시험에서는 F1이 0.25에서 0.30으로 올랐습니다. 반면 첫 3문항 시험에서는 하이브리드가 한 질문을 고치면 다른 질문을 망쳐 개선이 보이지 않았습니다. 같은 방법을 두고도 시험 크기에 따라 결론이 달라진 것입니다. 이 경험에서 "개선했다"는 말은 충분히 큰 채점표로 잰 뒤에만 해야 한다는 점을 배웠습니다. 위 수치는 scripts/eval-rag.ts, scripts/eval-hybrid.ts를 실행하면 같은 값이 나옵니다(무료, 내 컴퓨터에서 실행).
AI 분석은 참고용입니다. 최종 판단은 본인의 몫입니다.
소스 코드 · 라이브 데모 (GitHub Pages, 정적 데모 모드)
개인 학습용 토이가 아니라 인증·DB·배포까지 갖춘 실동작 서비스로, AI 앱 엔지니어링의 핵심 난제들을 직접 다뤘습니다.
| 다룬 문제 | 어떻게 풀었나 | 관련 파일 |
|---|---|---|
| LLM 출력을 믿을 수 있게 | Structured Outputs(JSON 스키마 강제)로 분석 결과를 타입 안전한 데이터로 | src/lib/claude.ts |
| 긴 대화 히스토리 검색 | RAG(청킹→임베딩→벡터검색)로 "의미로 찾기" 구현 | src/lib/{chunk,embeddings,rag}.ts |
| 검색 품질을 감으로 판단하지 않기 | 골든셋 평가 파이프라인(Recall/Precision/F1)으로 측정 기반 개선 | scripts/eval-*.ts |
| 데이터가 커져도 빠르게 | JS 코사인 검색 → pgvector(HNSW 색인) 프로덕션화 | src/lib/rag.ts, scripts/setup-pgvector.ts |
| API 비용 통제 | 임베딩을 로컬 모델로 처리해 검색 비용 0원, 분석은 사용량 제한 | src/lib/embeddings.ts |
자세한 내용은 아래 기술적 하이라이트를 참고하세요.
| 구분 | 사용 기술 |
|---|---|
| 프레임워크 | Next.js 15 (App Router) + React 19 + TypeScript |
| 스타일 | Tailwind CSS |
| DB | PostgreSQL + pgvector (벡터 검색) + Prisma ORM |
| 인증 | Auth.js (NextAuth v5) · 카카오 OAuth |
| AI (분석) | Anthropic Claude API (claude-sonnet-5, structured outputs) |
| AI (검색) | @xenova/transformers · multilingual-e5-small (384차원 임베딩, 로컬 실행) |
분석 결과를 자유 텍스트가 아니라 JSON 스키마로 강제했습니다(score는 정수 0~100, interestLevel은 enum, 신호는 positive/negative/neutral). LLM 응답을 파싱 오류 없이 타입 안전하게 화면·DB로 흘려보냅니다. → src/lib/claude.ts
src/lib/chunk.tssrc/lib/embeddings.tssrc/lib/rag.ts검색 품질을 골든셋(정답 라벨) 으로 계량화하고, 개선안을 실험으로 검증했습니다.
scripts/eval-rag.ts — Recall@k / Precision@k / F1 측정scripts/eval-hybrid.ts — 임베딩 단독 vs 하이브리드(키워드 + 임베딩, RRF 융합) 비교scripts/eval-scale.ts — 카테고리 템플릿으로 대화 200여 개·질문 100여 개를 생성해 대규모 비교배운 것: "그럴듯한 개선"이 측정해보면 본전이거나 악화되기도 했고, 골든셋 크기가 결론을 바꿨습니다(3문제→"본전", 12문제→"개선"). 최적 검색법은 데이터마다 달랐습니다.
학습용 JS 코사인 검색(모든 조각을 앱으로 로드)을 DB 내부 벡터 검색으로 전환했습니다.
vector(384) 컬럼 + HNSW 코사인 색인, <=> 연산자로 최근접 검색 → src/lib/rag.ts의 searchChunksPgscripts/setup-pgvector.ts임베딩·검색을 로컬 모델로 처리해 반복 검색 비용을 0원으로 만들고, 유료 LLM 호출(분석)에는 사용량 제한을 둬 비용을 통제했습니다.
yeonae-ai/
├─ prisma/
│ └─ schema.prisma # User/Account/Session + AnalysisSession/ConversationChunk/ReplySuggestion
├─ src/
│ ├─ auth.ts # Auth.js(NextAuth) 설정 (카카오)
│ ├─ app/
│ │ ├─ page.tsx # 메인: 로그인 게이트 + 분석
│ │ ├─ login/ # 로그인 페이지
│ │ ├─ search/ # 히스토리 의미 검색 UI (RAG)
│ │ ├─ history/ # 내 분석 기록 목록 / 상세
│ │ └─ api/
│ │ ├─ auth/[...nextauth]/ # Auth.js 핸들러
│ │ ├─ analyze/ # POST 분석 실행 (로그인 필요)
│ │ ├─ rag/search/ # POST 의미 검색
│ │ ├─ rag/reindex/ # POST 임베딩 재색인
│ │ └─ sessions/ # GET 목록 / GET·DELETE 단건 (본인 것만)
│ ├─ components/
│ │ ├─ Analyzer.tsx # 대화 입력/분석 UI
│ │ ├─ AnalysisView.tsx # 결과 렌더링
│ │ └─ AuthButtons.tsx # 로그인/로그아웃 버튼
│ └─ lib/
│ ├─ claude.ts # Claude 분석 서비스 + Structured Outputs 스키마
│ ├─ chunk.ts # 청킹 (겹침 포함)
│ ├─ embeddings.ts # 로컬 임베딩(e5) + 코사인 유사도
│ ├─ rag.ts # 저장/검색 (JS 코사인 · pgvector 두 구현)
│ ├─ prisma.ts # Prisma 클라이언트
│ └─ types.ts # 공용 타입
├─ scripts/ # 평가(eval-*) · pgvector 셋업 · 재색인 스크립트
└─ .env.example
npm install
.env.example을 복사해 .env 를 만들고 값을 채워주세요.
cp .env.example .env
| 변수 | 설명 |
|---|---|
DATABASE_URL | PostgreSQL 접속 주소. 로컬 또는 Neon·Supabase 무료 DB |
ANTHROPIC_API_KEY | console.anthropic.com 발급. 비우면 목업(예시) 결과로 동작 |
AUTH_SECRET | 세션 암호화 키. npx auth secret 로 생성 |
AUTH_KAKAO_ID | 카카오 앱 REST API 키 |
AUTH_KAKAO_SECRET | 카카오 앱 Client Secret |
AUTH_KAKAO_IDAUTH_KAKAO_SECREThttp://localhost:3000/api/auth/callback/kakaohttps://<your-domain>/api/auth/callback/kakaonpm run db:push # DB에 테이블 생성
npx tsx scripts/setup-pgvector.ts # pgvector 확장·벡터컬럼·HNSW 색인·백필 (최초 1회)
npm run dev # http://localhost:3000
npx tsx scripts/eval-rag.ts # 골든셋으로 Recall/Precision/F1
npx tsx scripts/eval-hybrid.ts # 임베딩 vs 하이브리드 비교
User / Account / Session — Auth.js 표준 인증 테이블AnalysisSession — 분석 세션 (userId, title, raw_text, result_json, score)ConversationChunk — 대화 조각 + 임베딩 (embedding Float[] / embedding_vec pgvector(384)) — RAG 검색용ReplySuggestion — 추천 답장 (sessionId, tone, content)DATABASE_URL (프로덕션 Postgres)ANTHROPIC_API_KEYAUTH_SECRETAUTH_KAKAO_ID, AUTH_KAKAO_SECRETAUTH_URL/AUTH_TRUST_HOST 자동 처리)https://<프로젝트>.vercel.app/api/auth/callback/kakao# 로컬에서 .env의 DATABASE_URL을 프로덕션 DB로 두고 실행
npx prisma db push
빌드 커맨드는
package.json의build(=prisma generate && next build)를 그대로 사용합니다. 별도 설정 불필요.
NEXT_PUBLIC_DEMO=true로 빌드하면 서버·DB·AI 없이 브라우저 안에서만 동작하는 정적 데모가 out/에 만들어집니다.
next.config.mjs가 데모 빌드에서만 output: "export", basePath: "/yeonae-ai", pageExtensions: ["demo.tsx", "demo.ts"]를 켭니다. 그래서 src/app 아래 *.demo.tsx만 라우트가 되고, API 라우트와 로그인 의존 페이지는 데모 빌드에서 빠집니다. 평소 빌드에서는 *.demo.tsx가 라우트로 인식되지 않습니다.src/lib/demo/samples.ts (지어낸 대화, 분석 결과는 스키마에 맞춰 사람이 작성한 예시)src/lib/demo/search-results.json — npx tsx scripts/build-demo-search.ts로 로컬 임베딩 모델을 돌려 미리 계산 (샘플이 짧아 조각 크기만 120자로 줄임).github/workflows/pages.yml (main 푸시 시 데모 빌드 → Pages 배포)# 로컬에서 데모 빌드 (bash)
NEXT_PUBLIC_DEMO=true npx next build # 결과: out/
searchChunksPg)에 적용 (계획)