Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AdoptAI STT

유기동물 입양 공고 자동 생성 파이프라인.

핸즈프리 음성: TTS 안내 → 자유 발화 STT → 슬롯 추출 → 요약 확인 → (누락만) TTS 재질문 → 공고 생성

단계 모듈 기술
TTS 안내/재질문 tts/speak.py edge-tts (ko-KR)
STT stt/transcribe.py, stt/listen.py faster-whisper large-v3 (기본 VAD·환청 완화)
슬롯 추출 llm/slot_extractor.py Vertex AI Gemini (SLOT_MODEL, 기본 flash)
재질의 llm/askback.py Gemini (ASKBACK_MODEL, 기본 flash) — 누락 슬롯만
음성 세션 llm/voice_session.py TTS↔STT 순차 오케스트레이션
공고문 생성 llm/notice_generator.py Gemini (NOTICE_MODEL, 기본 pro) — 플랫폼별 맞춤
Faithfulness llm/faithfulness_checker.py Gemini NLI (CHECKER_MODEL, 기본 flash)

MODEL_TIER=auto(기본)이면 역할별로 위 모델이 적용됩니다. flash/pro로 지정하면 전 역할에 동일 모델을 씁니다.

핸즈프리 음성 흐름

서비스(프론트 연동): TTS·마이크는 프론트엔드가 담당합니다. STT/AI API는 슬롯 추출·재질문·공고 생성만 수행합니다.
상세 API contract·시퀀스·JSON 예시는 docs/API_INTEGRATION.md를 보세요.

FE: TTS 안내 → 자유 발화 녹음
  → POST /stt/transcribe-and-start
  → (pending_slot=_confirm) FE: TTS(confirmation) → 녹음 → POST /pipeline/answer
  → (question 있으면) FE: TTS(question) → 녹음 → POST /pipeline/answer  (반복)
  → POST /pipeline/complete
응답 필드 프론트 동작
question (string) TTS로 읽고 답변 녹음 후 /pipeline/answer
pending_slot: "_confirm" 자유 발화 요약 확인 단계. question/confirmation을 TTS → 긍정("네 맞아요") 또는 수정 발화 후 /answer
question: null + ready_for_notice: true /pipeline/complete 호출
missing_slots 아직 부족한 필수 슬롯 이름 목록 (참고용)
session_id /answer, /complete에 그대로 전달
confirmation 요약 확인 문구 (확인 단계에서는 question과 동일)

run_voice_session()은 로컬 데모 전용이며 API에서 호출되지 않습니다.

# 로컬 콜백 시뮬레이션 (마이크 불필요)
uv run python llm/voice_session.py

프론트에서 받는 항목(보호소명·보호시작일·접종·건강검진 등)은 STT/재질문 대상이 아닙니다.

초기 안내 TTS (권장): llm/askback.pyget_initial_guide() — 슬롯 추출 전 실무자에게 필요한 정보를 짧게 안내합니다.

품종, 나이, 성별, 체중, 구조 지역, 보호소 연락처를 말씀해주시면 바로 공고를 작성해드릴게요!

기존 4문장 안내(tts/speak.pyINTRO_LINES) 뒤에 재생하거나, FE에서 동일 문구를 TTS로 읽어주면 됩니다.

STT (보호소 배경소음 대응)

stt/transcribe.py 기본값:

  • vad_filter=True — Silero VAD로 비음성 구간(짖음·침묵) 제외
  • condition_on_previous_text=False — 이전 문맥 의존 환청 감소
  • hallucination_silence_threshold=0.5, no_speech_threshold=0.6

보호소 현장에서는 마이크를 담당자 입 가까이 두고, TTS 재생 중에는 STT를 시작하지 않는 것이 중요합니다.

프론트 ↔ STT/AI API Contract (요약)

단계 API 내부 엔진
자유 발화 POST /stt/transcribe-and-start 또는 POST /pipeline/start Whisper + SlotExtractor
재질문 답변 POST /pipeline/answer {session_id, answer} AskBackEngine
공고 생성 POST /pipeline/complete {session_id} NoticeGenerator + Faithfulness

재질문 우선순위: breedsexestimated_ageweight_kgis_neuteredrescue_regionrescue_datecontact_methods
(채워진 슬롯은 다시 묻지 않음. 한 번에 하나의 question만 반환)

플랫폼별 공고문

llm/notice_generator.py는 슬롯 데이터로 플랫폼에 맞는 공고를 생성합니다.

플랫폼 platform 스타일
인스타그램 instagram 짧고 감성적, 해시태그, 150자 이내
당근 동네생활 daangn 친근한 존댓말, 동네 강조, 200자 이내
네이버 카페 naver_cafe 격식체, 상세 본문 + info_table (기본)

주요 슬롯

필수 슬롯에 contact_methods(입양 문의 방법)가 포함됩니다. 전화·인스타·카카오 등을 {"type": "phone"|"instagram"|"kakao"|"other", "value": "..."} 형태의 리스트로 저장하며, 빈 리스트일 때만 재질의 대상이 됩니다. 공고 info_table의 연락처는 이 필드를 조합해 채웁니다.

프론트/백엔드 연동: docs/API_INTEGRATION.md 참고

요구 사항

  • Python 3.12
  • uv 패키지 매니저
  • Vertex AI가 활성화된 Google Cloud 프로젝트
  • Vertex AI 사용 권한이 있는 서비스 계정 키 (gcp_key.json)
  • STT API 사용 시: NVIDIA GPU 권장 (없으면 CPU 동작, 느림)

설치

uv sync

Vertex AI 인증 설정

1. 서비스 계정 준비

Google Cloud Console에서 서비스 계정을 만들고 Vertex AI User (roles/aiplatform.user) 역할을 부여합니다.

JSON 키를 프로젝트 루트에 gcp_key.json으로 저장합니다.

2. .env 설정

GCP_PROJECT_ID=your-gcp-project-id
GOOGLE_APPLICATION_CREDENTIALS=./gcp_key.json
변수 필수 설명
GCP_PROJECT_ID 필수 GCP 프로젝트 ID
GOOGLE_APPLICATION_CREDENTIALS 필수 서비스 계정 키 경로
GCP_LOCATION 선택 Vertex AI 리전 (기본: us-central1)
MODEL_TIER 선택 flash/pro(전 역할 동일) 또는 auto(역할별 기본, 권장)
VERTEX_MODEL 선택 레거시. MODEL_TIER=flash|pro가 우선
SESSION_TTL_SECONDS 선택 파이프라인 세션 TTL (기본: 3600)
MAX_AUDIO_UPLOAD_BYTES 선택 최대 오디오 업로드 크기 (기본: 25MB)
STT_INTERNAL_API_KEY 운영 권장 BE→STT 내부 요청 인증키
REDIS_URL 운영 권장 공유 세션 저장소 URL (예: redis://redis:6379/0)
STT_REDIS_KEY_PREFIX 선택 Redis 세션 키 prefix (기본: adoptai:stt:session:)

API 서버 실행

uv run uvicorn api.app:app --host 0.0.0.0 --port 8000 --reload

Swagger UI: http://localhost:8000/docs

주요 엔드포인트

POST /stt/transcribe-and-start        # 음성 → STT → 슬롯 추출 → 세션
POST /pipeline/answer                 # 재질의 답변
POST /pipeline/complete               # 공고문 생성 + Faithfulness (naver_cafe)
POST /notice/generate?platform=...    # 슬롯만으로 플랫폼별 공고 생성
POST /notice/generate-all             # 인스타·당근·네이버 카페 3종 일괄 생성
GET  /pipeline/status/{id}            # 세션 상태

platform 쿼리: instagram | daangn | naver_cafe (기본: naver_cafe)

상세 연동 가이드: docs/API_INTEGRATION.md

스크립트 실행

# 슬롯 추출 데모
uv run python llm/slot_extractor.py

# 핸즈프리 음성 세션 데모 (speak/listen 콜백 시뮬레이션, 요약 확인 포함)
uv run python llm/voice_session.py

# 전체 파이프라인 데모 (텍스트 자유 발화 → 요약 확인 → 누락만 재질의 → 공고)
uv run python llm/pipeline.py

# 플랫폼별 공고문 생성 데모
uv run python llm/notice_generator.py

# E2E 테스트 (Vertex AI 실연동)
uv run python evaluation/e2e_test.py

# Flash vs Pro 품질·응답시간 비교 (현실 시나리오 포함)
uv run python evaluation/model_comparison.py --both
uv run python evaluation/model_comparison.py --both --scenario stt_noise
uv run python evaluation/model_comparison.py --list

# 파이프라인 구간별 latency (short / medium / ambiguous / long × 5회)
uv run python evaluation/latency_test.py

latency_test.pylong 시나리오는 품종·건강·성격·연락처가 모두 포함된 긴 자유 발화입니다. 결과는 evaluation/latency_results.json에 저장됩니다.

Python 라이브러리

from llm.pipeline import run_full_pipeline
from llm.notice_generator import generate_all_notices, generate_notice
from models.slots import AdoptionNoticeSlots
from time_utils import korea_today

# 전체 파이프라인 (슬롯 → 재질의 → 공고 → Faithfulness)
result = run_full_pipeline(
    "믹스견 추정 3살 수컷, 5kg, 슬개골 탈구 2기. 어제 OO동 구조",
    reference_date=korea_today(),
    get_answer=lambda slot, q: (
        "중성화 안 했어요" if slot == "is_neutered"
        else "064-710-4805" if slot == "contact_methods"
        else ""
    ),
)

print(result.slots)
print(result.notice.title if result.notice else None)
print(result.faithfulness.passed if result.faithfulness else None)

# 슬롯만으로 플랫폼별 공고 생성
slots = AdoptionNoticeSlots.model_validate({
    "breed": "믹스견",
    "estimated_age": {"value": 3, "unit": "년"},
    "sex": "수컷",
    "is_neutered": False,
    "weight_kg": 5.0,
    "rescue_region": "대현동",
    "rescue_date": "2026-07-13",
    "contact_methods": [{"type": "phone", "value": "064-710-4805"}],
})

instagram = generate_notice(slots, "instagram")
all_notices = generate_all_notices(slots)  # instagram, daangn, naver_cafe

테스트

uv run pytest tests/ -v

단위 테스트는 Vertex AI 클라이언트를 mock으로 주입하므로 API 키 없이 실행됩니다.

About

2026년 전국민 AI Rookie의 음성인식 레포지토리입니다.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages