AI 묵상 정리 (organize_meditation) - 서비스 + 컨트롤러 + UI + 테스트
ID: 4681034b-ac0f-4880-91f4-fe36ae0f1d52
## 목표
음성인식으로 입력된 묵상 텍스트를 AI가 정리해주는 기능 구현 (Q23)
## 배경
- 사용자가 음성인식으로 묵상 내용을 입력하면 오타/문법 오류가 많음
- AI가 원본 말투를 유지하면서 오타/문법만 수정하고 반복을 제거
- 가벼운 작업이므로 동기 처리 (백그라운드 Job 불필요)
## 구현 항목
### 1. AiMeditationOrganizer 서비스
- 파일: `app/services/ai_meditation_organizer.rb`
- 기존 서비스 패턴 (AiMeditationAnalyzer, AiSermonInterpreter)을 따를 것
- 핵심:
```ruby
class AiMeditationOrganizer
def initialize(text, passage_reference: nil)
@text = text
@passage_reference = passage_reference
end
def call
return { success: false, error: "정리할 텍스트가 없습니다." } if @text.blank?
client = OpenAI::Client.new(access_token: api_key)
response = client.chat(parameters: {
model: ai_model,
messages: [{ role: "user", content: build_prompt }],
temperature: 0.3 # 낮은 temperature - 내용 보존 우선
})
organized = response.dig("choices", 0, "message", "content")
{ success: true, organized_text: organized&.strip }
rescue => e
{ success: false, error: e.message }
end
private
def build_prompt
# 레거시 프롬프트 기반:
# - 원본 말투 유지
# - 오타/문법만 수정
# - 반복 제거
# - 내용 추가 금지
# - passage_reference가 있으면 성경 구절 맥락 제공
end
def api_key
ENV["OPENAI_API_KEY"] || ENV["GEMINI_API_KEY"] || raise("AI API 키가 설정되지 않았습니다")
end
def ai_model
ENV["OPENAI_API_KEY"] ? "gpt-4o-mini" : "gemini-2.0-flash"
end
end
```
### 2. MeditationsController에 organize 액션 추가
- 파일: `app/controllers/qt/meditations_controller.rb` (또는 해당 컨트롤러)
- **먼저** 기존 묵상 컨트롤러를 찾아서 읽을 것 (qt/ namespace 확인)
- organize 액션 추가:
```ruby
def organize
@meditation = current_user.user_meditations.find(params[:id])
result = AiMeditationOrganizer.new(
@meditation.personal_meditation,
passage_reference: @meditation.qt_content&.reading_passage
).call
if result[:success]
@meditation.update(personal_meditation: result[:organized_text])
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.replace(
"meditation-content",
partial: "qt/meditations/meditation_content",
locals: { meditation: @meditation }
)}
format.html { redirect_to qt_meditation_path(@meditation), notice: "묵상이 정리되었습니다." }
end
else
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.replace(
"organize-error",
html: "
#{result[:error]}
")}
format.html { redirect_to qt_meditation_path(@meditation), alert: result[:error] }
end
end
end
```
### 3. 라우트 수정
- 파일: `config/routes.rb`
- 기존 묵상 리소스에 member 라우트 추가:
```ruby
# meditations 리소스 안에:
member do
post :organize
end
```
- **중요**: 기존 routes.rb를 먼저 읽고, 묵상 관련 라우트 구조를 파악한 후 추가
### 4. UI - "정리하기" 버튼
- **먼저** 묵상 관련 뷰 파일을 탐색하여 어디에 버튼을 추가할지 결정:
- `app/views/qt/meditations/` 디렉토리 확인
- 묵상 show 페이지 또는 form에서 personal_meditation 필드 근처
- 버튼 디자인:
- personal_meditation이 있을 때만 표시
- `button_to "AI 정리", organize_qt_meditation_path(@meditation), method: :post`
- 또는 Turbo 방식: data-turbo-method="post"
- **Turbo Stream** 응답을 위한 파셜 필요:
- `qt/meditations/_meditation_content.html.erb` (정리된 내용 표시)
### 5. 테스트
- 파일: `test/services/ai_meditation_organizer_test.rb` (신규)
- 정상 정리 테스트 (API stub)
- 빈 텍스트 에러 처리
- API 실패 에러 처리
- 파일: 기존 묵상 컨트롤러 테스트에 추가
- organize 인증 필수
- organize 성공 시 텍스트 업데이트
- organize 실패 시 에러 처리
- 타인 묵상 접근 불가
## 기존 코드 참고 (반드시 먼저 읽을 것)
- `app/services/ai_sermon_interpreter.rb` - AI 서비스 패턴 + Turbo Stream 응답 패턴
- `app/controllers/sermons_controller.rb` - interpret 액션 (동일 패턴)
- `app/controllers/qt/meditations_controller.rb` 또는 유사 컨트롤러 - 묵상 CRUD
- 묵상 관련 뷰 파일들 (qt/ 아래)
- `app/models/user_meditation.rb` - 모델 구조
- `test/fixtures/user_meditations.yml` - fixture
## 주의사항
- **반드시** 기존 묵상 컨트롤러와 뷰를 먼저 읽고, 그 패턴에 맞게 구현
- AI 서비스 패턴: ruby-openai gem, OpenAI::Client.new(access_token: api_key)
- temperature 0.3 (낮음) - 원본 내용 보존 우선
- shared 파셜의 strict locals 준수
- ERB 멀티라인 주석 안에 ERB 태그 금지 (SystemStackError)
- UUID PK 사용
- parallelize(workers: 1) 테스트 설정 확인
- 기존 테스트가 깨지지 않게 주의
- 전체 테스트 통과 확인: bin/rails test
- config/routes.rb 수정 시 기존 구조를 깨지 않게 주의
첨부 이미지
이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)
JPEG, PNG, GIF, WebP / 최대 10MB
활동 로그
-
팀팀리드 상태 변경: 리뷰 → 완료
2026년 03월 02일 05:20:24
-
Aai-organize-dev AI 묵상 정리 기능 구현 완료 - 전체 테스트 통과 (430 tests, 0 failures)
2026년 03월 02일 05:19:44
상세 보기
## 변경 파일
### 신규 생성
- `app/services/ai_meditation_organizer.rb` - AI 묵상 정리 서비스
- `app/views/qt/meditations/organize.turbo_stream.erb` - Turbo Stream 응답 뷰
- `test/services/ai_meditation_organizer_test.rb` - 서비스 테스트 (5개)### 수정
- `app/controllers/qt/meditations_controller.rb` - organize 액션 + build_organizer 메서드 추가
- `config/routes.rb` - `post :organize` member 라우트 추가
- `app/views/qt/meditations/_form.html.erb` - "AI 정리" 버튼 추가
- `test/controllers/qt/meditations_controller_test.rb` - organize 테스트 5개 추가## 구현 상세
- **서비스**: AiMeditationOrganizer - temperature 0.3으로 원본 말투 유지, 오타/문법 수정, 반복 제거
- **컨트롤러**: organize 액션 - SermonsController#interpret 패턴 준수, turbo_stream + html 양쪽 지원
- **UI**: personal_meditation이 있을 때만 "AI 정리" 버튼 표시, Turbo 로딩 상태 지원
- **테스트**: 서비스 5개 + 컨트롤러 5개 = 10개 신규 테스트, client DI 패턴으로 API mock -
Aai-organize-dev 상태 변경: 완료 → 리뷰
2026년 03월 02일 05:19:30
-
팀팀리드 상태 변경: 진행 중 → 완료
2026년 03월 02일 05:16:13
-
Aai-organize-dev AI 묵상 정리 구현 시작
2026년 03월 02일 05:13:20
-
Aai-organize-dev 티켓 클레임 완료
2026년 03월 02일 05:13:13