- config/services.php fallback 기본값 변경 - AiConfig DEFAULT_MODELS 상수 + getActiveGemini() fallback 변경 - NotionService fallback 변경 - AI 설정 관리 UI placeholder/기본값 변경 - Google Cloud AI 가이드 서비스 현황 모델명 변경 - 환경변수 관리 아카데미 예시 변경
740 lines
54 KiB
PHP
740 lines
54 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Google Cloud AI 활용 가이드')
|
|
|
|
@push('styles')
|
|
<style>
|
|
.gai-card { background: #fff; border-radius: 12px; border: 1px solid #e2e8f0; overflow: hidden; }
|
|
.gai-card-header { padding: 16px 20px; border-bottom: 1px solid #f1f5f9; }
|
|
.gai-badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 10px; border-radius: 9999px; font-size: 11px; font-weight: 600; }
|
|
.gai-badge-blue { background: #dbeafe; color: #1d4ed8; }
|
|
.gai-badge-green { background: #dcfce7; color: #166534; }
|
|
.gai-badge-purple { background: #f3e8ff; color: #7c3aed; }
|
|
.gai-badge-amber { background: #fef3c7; color: #92400e; }
|
|
.gai-badge-red { background: #fee2e2; color: #991b1b; }
|
|
.gai-badge-cyan { background: #cffafe; color: #155e75; }
|
|
.gai-badge-gray { background: #f1f5f9; color: #475569; }
|
|
.gai-icon-circle { display: flex; align-items: center; justify-content: center; border-radius: 50%; flex-shrink: 0; }
|
|
.gai-flow { display: flex; align-items: stretch; gap: 0; overflow-x: auto; }
|
|
.gai-flow-item { flex: 1; min-width: 120px; text-align: center; position: relative; padding: 16px 8px; }
|
|
.gai-flow-item:not(:last-child)::after { content: ''; position: absolute; right: -6px; top: 50%; transform: translateY(-50%); width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; border-left: 10px solid #4285f4; z-index: 1; }
|
|
.gai-flow-num { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; color: #fff; font-size: 12px; font-weight: 700; margin-bottom: 6px; }
|
|
.gai-quote { border-left: 3px solid #4285f4; padding: 12px 16px; background: #eff6ff; border-radius: 0 8px 8px 0; font-style: italic; }
|
|
.gai-service-card { padding: 16px; border-radius: 10px; border: 1px solid; transition: transform 0.15s ease; }
|
|
.gai-service-card:hover { transform: translateY(-2px); }
|
|
.gai-code { background: #1e293b; color: #e2e8f0; padding: 12px 16px; border-radius: 8px; font-size: 12px; font-family: 'Courier New', monospace; overflow-x: auto; white-space: pre; line-height: 1.6; }
|
|
</style>
|
|
@endpush
|
|
|
|
@section('content')
|
|
<div class="space-y-6">
|
|
|
|
{{-- 페이지 헤더 --}}
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900">Google Cloud AI 활용 가이드</h1>
|
|
<p class="mt-1 text-sm text-gray-500">SAM에서 활용 중인 Google Cloud AI 서비스 총정리 | @codebridge-x.com</p>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<span class="text-xs text-gray-400">CodeBridgeX | 2026.03</span>
|
|
<a href="{{ route('google-cloud.ai-guide.download') }}"
|
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors"
|
|
title="PPTX 다운로드">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
|
|
PPTX
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── 핵심 요약 4카드 ─── --}}
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-5" style="flex: 1 1 200px; max-width: 280px;">
|
|
<div class="flex items-center gap-2 text-sm text-gray-500">
|
|
<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"/></svg>
|
|
음성 인식
|
|
</div>
|
|
<div class="text-lg font-bold text-gray-900 mt-1">Speech-to-Text</div>
|
|
<div class="text-sm text-gray-500 mt-0.5">V1 + V2 Chirp 2 자동 폴백</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-5" style="flex: 1 1 200px; max-width: 280px;">
|
|
<div class="flex items-center gap-2 text-sm text-gray-500">
|
|
<svg class="w-4 h-4 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>
|
|
AI 분석
|
|
</div>
|
|
<div class="text-lg font-bold text-emerald-600 mt-1">Gemini 2.0 Flash</div>
|
|
<div class="text-sm text-gray-500 mt-0.5">재무 분석, 회의 요약, 명함 OCR</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-5" style="flex: 1 1 200px; max-width: 280px;">
|
|
<div class="flex items-center gap-2 text-sm text-gray-500">
|
|
<svg class="w-4 h-4 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/></svg>
|
|
클라우드 저장
|
|
</div>
|
|
<div class="text-lg font-bold text-gray-900 mt-1">Cloud Storage</div>
|
|
<div class="text-sm text-gray-500 mt-0.5">음성/파일 백업, 서명 URL</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-5" style="flex: 1 1 200px; max-width: 280px;">
|
|
<div class="flex items-center gap-2 text-sm text-gray-500">
|
|
<svg class="w-4 h-4 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
설정 관리
|
|
</div>
|
|
<div class="text-lg font-bold text-purple-600 mt-1">AI Config</div>
|
|
<div class="text-sm text-gray-500 mt-0.5">다중 Provider, 토큰/비용 추적</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 1: SAM AI 아키텍처 개요 ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<h2 class="text-base font-semibold text-gray-800">SAM AI 아키텍처 개요</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">Google Cloud 기반 AI 서비스 통합 구조</p>
|
|
</div>
|
|
<div class="p-5">
|
|
{{-- 아키텍처 다이어그램 --}}
|
|
<div class="p-4 bg-gray-50 border border-gray-200 rounded-lg mb-5" style="overflow-x: auto;">
|
|
<pre class="text-xs text-gray-700 leading-relaxed" style="font-family: 'Courier New', monospace; white-space: pre;">
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ SAM 관리자 (MNG) │
|
|
│ │
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
│ │ 회의록 │ │ 음성녹음 │ │ 상담메모 │ │ 재무분석 │ │
|
|
│ │ 시스템 │ │ 분석 │ │ STT 입력 │ │ AI리포트 │ │
|
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
|
|
│ │ │ │ │ │
|
|
│ ┌────▼────────────▼────────────▼────────────▼─────┐ │
|
|
│ │ GoogleCloudService │ │
|
|
│ │ ┌─────────────┐ ┌───────────────┐ │ │
|
|
│ │ │ STT V2 │ │ STT V1 │ │ │
|
|
│ │ │ (Chirp 2) │ │ (latest_long) │ ← 자동폴백 │ │
|
|
│ │ └──────┬──────┘ └───────┬───────┘ │ │
|
|
│ │ └────────┬────────┘ │ │
|
|
│ │ ┌─────────────┼──────────────┐ │ │
|
|
│ │ │ Speaker │ GCS Upload │ │ │
|
|
│ │ │ Diarization │ /Download │ │ │
|
|
│ │ └─────────────┴──────────────┘ │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
└──────────────────────────┼─────────────────────────────────────────┘
|
|
│
|
|
┌──────────▼──────────┐
|
|
│ Google Cloud APIs │
|
|
│ │
|
|
│ Speech-to-Text │
|
|
│ Cloud Storage │
|
|
│ Vertex AI (Gemini) │
|
|
└─────────────────────┘</pre>
|
|
</div>
|
|
|
|
{{-- 서비스 매핑 테이블 --}}
|
|
<div class="text-sm font-medium text-gray-700 mb-2">SAM 서비스 ↔ Google Cloud API 매핑</div>
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200">
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium" style="width: 22%;">SAM 서비스</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium" style="width: 22%;">Google Cloud API</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium" style="width: 20%;">모델/엔진</th>
|
|
<th class="text-center py-2 px-3 text-gray-600 font-medium" style="width: 12%;">상태</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium">소스 파일</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@php
|
|
$services = [
|
|
['sam' => '회의록 자동 생성', 'api' => 'Speech-to-Text', 'model' => 'Chirp 2 / latest_long', 'status' => '운영중', 'file' => 'MeetingMinuteService'],
|
|
['sam' => '음성 녹음 분석', 'api' => 'Speech-to-Text', 'model' => 'Chirp 2 + Gemini', 'status' => '운영중', 'file' => 'AiVoiceRecordingService'],
|
|
['sam' => '상담 메모 음성 입력', 'api' => 'Speech-to-Text', 'model' => 'V1 latest_long', 'status' => '운영중', 'file' => 'GoogleCloudService'],
|
|
['sam' => '재무 AI 리포트', 'api' => 'Vertex AI (Gemini)', 'model' => 'gemini-2.5-flash', 'status' => '운영중', 'file' => 'AiReportService (API)'],
|
|
['sam' => '명함 OCR', 'api' => 'Gemini API', 'model' => 'gemini-2.5-flash', 'status' => '운영중', 'file' => 'GeminiService'],
|
|
['sam' => '오디오 백업/저장', 'api' => 'Cloud Storage', 'model' => 'Standard Class', 'status' => '운영중', 'file' => 'GoogleCloudStorageService'],
|
|
['sam' => 'AI 설정 관리', 'api' => '—', 'model' => '다중 Provider', 'status' => '운영중', 'file' => 'AiConfig (Model)'],
|
|
['sam' => '토큰/비용 추적', 'api' => '—', 'model' => 'USD/KRW 환산', 'status' => '운영중', 'file' => 'AiTokenHelper'],
|
|
];
|
|
@endphp
|
|
@foreach($services as $svc)
|
|
<tr class="border-b border-gray-100 hover:bg-gray-50">
|
|
<td class="py-2.5 px-3 font-medium text-gray-800">{{ $svc['sam'] }}</td>
|
|
<td class="py-2.5 px-3 text-gray-600">{{ $svc['api'] }}</td>
|
|
<td class="py-2.5 px-3 text-gray-500 text-xs">{{ $svc['model'] }}</td>
|
|
<td class="py-2.5 px-3 text-center">
|
|
<span class="gai-badge gai-badge-green">{{ $svc['status'] }}</span>
|
|
</td>
|
|
<td class="py-2.5 px-3 text-xs text-gray-400 font-mono">{{ $svc['file'] }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 2: Speech-to-Text (음성 인식) ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #4285f4;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">Speech-to-Text — 음성 인식</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">V2 Chirp 2 → V1 latest_long 자동 폴백 전략</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
{{-- V2 vs V1 비교 --}}
|
|
<div class="flex gap-4 mb-5" style="flex-wrap: wrap;">
|
|
<div class="gai-service-card border-blue-200 bg-blue-50" style="flex: 1 1 280px;">
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<span class="gai-badge gai-badge-blue">V2 (Primary)</span>
|
|
<span class="text-xs text-gray-400">Chirp 2 모델</span>
|
|
</div>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2"><span class="text-blue-500 mt-0.5">▶</span> <span class="text-gray-700">Chirp 2 — Google 최신 음성 인식 모델</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-blue-500 mt-0.5">▶</span> <span class="text-gray-700">Batch Recognize API (비동기 처리)</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-blue-500 mt-0.5">▶</span> <span class="text-gray-700">Speaker Diarization (화자 분리) 내장</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-blue-500 mt-0.5">▶</span> <span class="text-gray-700">Speech Adaptation — phrase hints 지원</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-blue-500 mt-0.5">▶</span> <span class="text-gray-700">자동 구두점, 단어별 타임스탬프</span></div>
|
|
</div>
|
|
<div class="mt-3 text-xs text-blue-700 font-medium">메서드: speechToTextV2()</div>
|
|
</div>
|
|
|
|
<div class="gai-service-card border-gray-200 bg-gray-50" style="flex: 1 1 280px;">
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<span class="gai-badge gai-badge-gray">V1 (Fallback)</span>
|
|
<span class="text-xs text-gray-400">latest_long 모델</span>
|
|
</div>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2"><span class="text-gray-400 mt-0.5">▶</span> <span class="text-gray-700">latest_long — 안정적인 기본 모델</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-gray-400 mt-0.5">▶</span> <span class="text-gray-700">LongRunningRecognize API (비동기)</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-gray-400 mt-0.5">▶</span> <span class="text-gray-700">Speaker Diarization (2~6명)</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-gray-400 mt-0.5">▶</span> <span class="text-gray-700">WEBM_OPUS, 48kHz, 2ch 인코딩</span></div>
|
|
<div class="flex items-start gap-2"><span class="text-gray-400 mt-0.5">▶</span> <span class="text-gray-700">V2 실패 시 자동 폴백으로 안정성 확보</span></div>
|
|
</div>
|
|
<div class="mt-3 text-xs text-gray-500 font-medium">메서드: speechToTextWithDiarization()</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 자동 폴백 플로우 --}}
|
|
<div class="text-sm font-medium text-gray-700 mb-3">자동 폴백 흐름 (speechToTextWithDiarizationAuto)</div>
|
|
<div class="gai-flow" style="margin-bottom: 16px;">
|
|
@php
|
|
$sttFlow = [
|
|
['num' => 1, 'title' => 'GCS 업로드', 'desc' => '오디오 → gs://', 'color' => '#ea4335'],
|
|
['num' => 2, 'title' => 'V2 Chirp 2', 'desc' => '최신 모델 시도', 'color' => '#4285f4'],
|
|
['num' => 3, 'title' => '성공?', 'desc' => '결과 확인', 'color' => '#fbbc04'],
|
|
['num' => 4, 'title' => 'V1 폴백', 'desc' => '실패 시 V1', 'color' => '#34a853'],
|
|
['num' => 5, 'title' => '파싱', 'desc' => '화자별 세그먼트', 'color' => '#4285f4'],
|
|
];
|
|
@endphp
|
|
@foreach($sttFlow as $step)
|
|
<div class="gai-flow-item">
|
|
<div class="gai-flow-num" style="background: {{ $step['color'] }};">{{ $step['num'] }}</div>
|
|
<div class="font-semibold text-gray-800 text-sm">{{ $step['title'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-1">{{ $step['desc'] }}</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
{{-- Speaker Diarization 설명 --}}
|
|
<div class="p-4 bg-amber-50 border border-amber-200 rounded-lg">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<svg class="w-4 h-4 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
<span class="font-semibold text-amber-800 text-sm">Speaker Diarization — 화자 분리</span>
|
|
</div>
|
|
<p class="text-xs text-gray-600 leading-relaxed">회의 녹음에서 각 발화자를 자동 식별합니다. 최소 2명~최대 6명까지 지원하며, 결과는 <code class="px-1 py-0.5 bg-amber-100 rounded text-xs">[화자 1] 텍스트</code> 형태의 세그먼트로 반환됩니다. SentencePiece 토크나이저 결과를 자연어로 재결합하는 후처리가 포함됩니다.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 3: 회의록 자동 생성 시스템 ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #34a853;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">회의록 자동 생성 시스템</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">MeetingMinuteService — 녹음 → STT → Gemini 요약</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
{{-- 처리 플로우 --}}
|
|
<div class="gai-flow mb-5">
|
|
@php
|
|
$meetingFlow = [
|
|
['num' => 1, 'title' => '녹음', 'desc' => '브라우저 WebRTC', 'color' => '#ea4335'],
|
|
['num' => 2, 'title' => 'GCS 업로드', 'desc' => '오디오 백업', 'color' => '#fbbc04'],
|
|
['num' => 3, 'title' => 'STT 변환', 'desc' => '화자 분리 포함', 'color' => '#4285f4'],
|
|
['num' => 4, 'title' => 'Gemini 요약', 'desc' => 'AI 자동 요약', 'color' => '#34a853'],
|
|
['num' => 5, 'title' => '회의록 저장', 'desc' => 'DB 기록', 'color' => '#9334e9'],
|
|
];
|
|
@endphp
|
|
@foreach($meetingFlow as $step)
|
|
<div class="gai-flow-item">
|
|
<div class="gai-flow-num" style="background: {{ $step['color'] }};">{{ $step['num'] }}</div>
|
|
<div class="font-semibold text-gray-800 text-sm">{{ $step['title'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-1">{{ $step['desc'] }}</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
{{-- 기능 카드 --}}
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
<div class="p-4 bg-green-50 border border-green-200 rounded-lg" style="flex: 1 1 200px;">
|
|
<div class="font-semibold text-gray-800 text-sm mb-2">핵심 기능</div>
|
|
<div class="space-y-1.5 text-xs text-gray-600">
|
|
<div class="flex items-center gap-1.5"><span class="text-green-500">✓</span> 브라우저 내 실시간 녹음 (WebM/Opus)</div>
|
|
<div class="flex items-center gap-1.5"><span class="text-green-500">✓</span> 화자별 발화 자동 분리 (2~6명)</div>
|
|
<div class="flex items-center gap-1.5"><span class="text-green-500">✓</span> Gemini AI 회의 내용 자동 요약</div>
|
|
<div class="flex items-center gap-1.5"><span class="text-green-500">✓</span> 회의록 검색/필터/페이지네이션</div>
|
|
<div class="flex items-center gap-1.5"><span class="text-green-500">✓</span> 화자 이름 수동 편집 기능</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-4 bg-blue-50 border border-blue-200 rounded-lg" style="flex: 1 1 200px;">
|
|
<div class="font-semibold text-gray-800 text-sm mb-2">데이터 구조</div>
|
|
<div class="space-y-1.5 text-xs text-gray-600">
|
|
<div><code class="px-1 py-0.5 bg-blue-100 rounded">meeting_minutes</code> 회의 메타 정보</div>
|
|
<div><code class="px-1 py-0.5 bg-blue-100 rounded">meeting_minute_segments</code> 화자별 세그먼트</div>
|
|
<div>상태: draft → recording → processing → completed</div>
|
|
<div>GCS URI로 원본 오디오 보관</div>
|
|
<div>full_transcript + ai_summary 저장</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-4 bg-purple-50 border border-purple-200 rounded-lg" style="flex: 1 1 200px;">
|
|
<div class="font-semibold text-gray-800 text-sm mb-2">사용되는 API</div>
|
|
<div class="space-y-1.5 text-xs text-gray-600">
|
|
<div><span class="gai-badge gai-badge-blue" style="font-size: 10px;">STT</span> Speech-to-Text V2</div>
|
|
<div><span class="gai-badge gai-badge-green" style="font-size: 10px;">AI</span> Gemini 2.0 Flash</div>
|
|
<div><span class="gai-badge gai-badge-amber" style="font-size: 10px;">GCS</span> Cloud Storage</div>
|
|
<div class="text-gray-400 mt-1">인증: Service Account (OAuth 2.0)</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 4: 음성 녹음 분석 ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #ea4335;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">음성 녹음 분석</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">AiVoiceRecordingService — 녹음 → STT → Gemini 분석</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
<div style="flex: 1 1 340px;">
|
|
<div class="text-sm font-medium text-gray-700 mb-3">처리 파이프라인</div>
|
|
<div class="space-y-3">
|
|
@php
|
|
$pipeline = [
|
|
['step' => '1. 오디오 수신', 'desc' => 'Base64 인코딩된 WebM/Opus 오디오를 수신', 'icon' => '🔊'],
|
|
['step' => '2. GCS 업로드', 'desc' => 'Google Cloud Storage에 원본 백업 (gs://bucket/recordings/...)', 'icon' => '☁'],
|
|
['step' => '3. STT 변환', 'desc' => 'V2 Chirp 2 → V1 자동 폴백으로 텍스트 변환', 'icon' => '💬'],
|
|
['step' => '4. Gemini 분석', 'desc' => 'AI가 음성 내용을 분석/요약하여 인사이트 생성', 'icon' => '🤖'],
|
|
['step' => '5. 결과 저장', 'desc' => 'transcript_text + analysis_text를 DB에 저장', 'icon' => '💾'],
|
|
];
|
|
@endphp
|
|
@foreach($pipeline as $p)
|
|
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-lg">
|
|
<span class="text-lg shrink-0">{{ $p['icon'] }}</span>
|
|
<div>
|
|
<div class="font-semibold text-gray-800 text-sm">{{ $p['step'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">{{ $p['desc'] }}</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
<div style="flex: 1 1 280px;">
|
|
<div class="text-sm font-medium text-gray-700 mb-3">인터뷰 템플릿 기능</div>
|
|
<div class="p-4 bg-red-50 border border-red-200 rounded-lg mb-3">
|
|
<p class="text-xs text-gray-600 leading-relaxed">음성 녹음 시 <strong>인터뷰 템플릿</strong>을 선택하면, Gemini가 해당 템플릿의 질문 항목에 맞춰 음성 내용을 구조화된 분석 결과로 변환합니다.</p>
|
|
</div>
|
|
<div class="text-sm font-medium text-gray-700 mb-2">데이터 모델</div>
|
|
<table class="w-full text-xs">
|
|
<tbody>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-2 font-medium text-gray-700">테이블</td>
|
|
<td class="py-2 px-2 text-gray-500 font-mono">ai_voice_recordings</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-2 font-medium text-gray-700">상태값</td>
|
|
<td class="py-2 px-2 text-gray-500">pending → processing → completed / failed</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-2 font-medium text-gray-700">저장 항목</td>
|
|
<td class="py-2 px-2 text-gray-500">GCS URI, 원본 텍스트, 분석 결과, 소요 시간</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-2 font-medium text-gray-700">파일 보관</td>
|
|
<td class="py-2 px-2 text-gray-500">생성일로부터 7일 (file_expiry_date)</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 5: Gemini AI 활용 ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #fbbc04;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">Gemini AI 활용</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">Vertex AI — 재무 분석 리포트, 회의 요약, 명함 OCR</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
<div class="flex gap-4 mb-5" style="flex-wrap: wrap;">
|
|
{{-- 재무 분석 --}}
|
|
<div class="gai-service-card border-emerald-200 bg-emerald-50" style="flex: 1 1 260px;">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="gai-badge gai-badge-green">운영중</span>
|
|
<span class="font-semibold text-gray-800 text-sm">AI 재무 분석 리포트</span>
|
|
</div>
|
|
<p class="text-xs text-gray-600 mb-3">테넌트의 비즈니스 데이터(지출, 매출, 매입, 입출금, 카드/계좌, 미수금)를 자동 수집하여 일간/주간/월간 분석 리포트를 생성합니다.</p>
|
|
<div class="space-y-1 text-xs text-gray-500">
|
|
<div><strong>서비스:</strong> AiReportService (API 프로젝트)</div>
|
|
<div><strong>모델:</strong> gemini-2.5-flash (Vertex AI)</div>
|
|
<div><strong>분석 영역:</strong> 지출, 매출, 매입, 입출금, 카드/계좌, 미수금</div>
|
|
<div><strong>API:</strong> <code class="px-1 bg-emerald-100 rounded">POST /v1/reports/ai/generate</code></div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 회의 요약 --}}
|
|
<div class="gai-service-card border-blue-200 bg-blue-50" style="flex: 1 1 260px;">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="gai-badge gai-badge-blue">운영중</span>
|
|
<span class="font-semibold text-gray-800 text-sm">회의 내용 AI 요약</span>
|
|
</div>
|
|
<p class="text-xs text-gray-600 mb-3">STT로 변환된 회의 전문을 Gemini에 전달하여 핵심 내용, 결정 사항, 후속 조치 항목을 자동으로 요약합니다.</p>
|
|
<div class="space-y-1 text-xs text-gray-500">
|
|
<div><strong>서비스:</strong> MeetingMinuteService (MNG)</div>
|
|
<div><strong>모델:</strong> gemini-2.5-flash</div>
|
|
<div><strong>입력:</strong> 화자별 세그먼트 전체 텍스트</div>
|
|
<div><strong>출력:</strong> ai_summary 필드에 저장</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 명함 OCR --}}
|
|
<div class="gai-service-card border-purple-200 bg-purple-50" style="flex: 1 1 260px;">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="gai-badge gai-badge-purple">운영중</span>
|
|
<span class="font-semibold text-gray-800 text-sm">명함 OCR</span>
|
|
</div>
|
|
<p class="text-xs text-gray-600 mb-3">명함 이미지를 Gemini Vision에 전달하여 이름, 직함, 회사, 전화번호, 이메일 등을 자동 추출합니다.</p>
|
|
<div class="space-y-1 text-xs text-gray-500">
|
|
<div><strong>서비스:</strong> GeminiService (MNG)</div>
|
|
<div><strong>메서드:</strong> extractBusinessCard()</div>
|
|
<div><strong>입력:</strong> 명함 이미지 파일</div>
|
|
<div><strong>출력:</strong> 구조화된 연락처 정보 JSON</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 토큰 사용량 추적 --}}
|
|
<div class="p-4 bg-amber-50 border border-amber-200 rounded-lg">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<svg class="w-4 h-4 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"/></svg>
|
|
<span class="font-semibold text-amber-800 text-sm">토큰 사용량 & 비용 추적 (AiTokenHelper)</span>
|
|
</div>
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
<div class="text-xs text-gray-600" style="flex: 1 1 200px;">
|
|
<p class="mb-2">모든 Gemini API 호출 시 토큰 사용량과 비용을 자동으로 기록합니다.</p>
|
|
<div class="space-y-1">
|
|
<div><strong>테이블:</strong> <code class="px-1 bg-amber-100 rounded">ai_token_usages</code></div>
|
|
<div><strong>기록 항목:</strong> provider, model, menu, input/output tokens</div>
|
|
<div><strong>비용 계산:</strong> <code class="px-1 bg-amber-100 rounded">ai_pricing_configs</code> 테이블의 단가 참조</div>
|
|
</div>
|
|
</div>
|
|
<div class="text-xs text-gray-600" style="flex: 1 1 200px;">
|
|
<div class="font-medium text-gray-700 mb-1">비용 계산 흐름</div>
|
|
<div class="gai-code" style="font-size: 11px;">AiTokenHelper::record(
|
|
provider: 'gemini',
|
|
model: 'gemini-2.5-flash',
|
|
menu: 'meeting-minutes',
|
|
inputTokens: 1520,
|
|
outputTokens: 350,
|
|
costUsd: 0.00012
|
|
);</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 6: Cloud Storage (GCS) ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #0f9d58;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">Cloud Storage (GCS)</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">GoogleCloudStorageService — 파일 업로드, 다운로드, 서명 URL</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
<div class="flex gap-4" style="flex-wrap: wrap;">
|
|
{{-- 용도별 정리 --}}
|
|
<div style="flex: 1 1 320px;">
|
|
<div class="text-sm font-medium text-gray-700 mb-3">SAM에서의 GCS 활용</div>
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200">
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium">용도</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium">저장 경로</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium">설명</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium text-gray-800 text-xs">회의록 녹음</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500 font-mono">meetings/{tenant}/{id}/</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">WebM 오디오 원본</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium text-gray-800 text-xs">음성 녹음</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500 font-mono">recordings/{tenant}/</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">분석용 음성 파일</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-medium text-gray-800 text-xs">상담 음성</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500 font-mono">consultations/{tenant}/</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">10MB 이상 자동 백업</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{{-- 서비스 메서드 --}}
|
|
<div style="flex: 1 1 280px;">
|
|
<div class="text-sm font-medium text-gray-700 mb-3">주요 메서드 (2개 서비스)</div>
|
|
<div class="space-y-3">
|
|
<div class="p-3 bg-green-50 border border-green-200 rounded-lg">
|
|
<div class="text-xs font-bold text-green-800 mb-1">GoogleCloudService (MNG)</div>
|
|
<div class="space-y-1 text-xs text-gray-600">
|
|
<div><code class="bg-green-100 px-1 rounded">uploadToStorage()</code> 로컬 → GCS</div>
|
|
<div><code class="bg-green-100 px-1 rounded">uploadBase64Audio()</code> Base64 → GCS</div>
|
|
<div><code class="bg-green-100 px-1 rounded">downloadFromStorage()</code> GCS → 스트림</div>
|
|
<div><code class="bg-green-100 px-1 rounded">deleteFromStorage()</code> GCS 파일 삭제</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-3 bg-cyan-50 border border-cyan-200 rounded-lg">
|
|
<div class="text-xs font-bold text-cyan-800 mb-1">GoogleCloudStorageService (MNG)</div>
|
|
<div class="space-y-1 text-xs text-gray-600">
|
|
<div><code class="bg-cyan-100 px-1 rounded">upload()</code> 파일 업로드 (URI 반환)</div>
|
|
<div><code class="bg-cyan-100 px-1 rounded">getSignedUrl()</code> 서명 다운로드 URL (60분)</div>
|
|
<div><code class="bg-cyan-100 px-1 rounded">delete()</code> 파일 삭제</div>
|
|
<div><code class="bg-cyan-100 px-1 rounded">isAvailable()</code> 사용 가능 여부</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 설정 우선순위 --}}
|
|
<div class="mt-4 p-4 bg-gray-50 border border-gray-200 rounded-lg">
|
|
<div class="text-sm font-medium text-gray-700 mb-2">GCS 설정 우선순위</div>
|
|
<div class="gai-code" style="font-size: 11px;">1. DB 설정 (ai_configs 테이블의 활성화된 gcs provider)
|
|
↓ 없으면
|
|
2. 환경변수 (.env: GCS_BUCKET_NAME, GCS_SERVICE_ACCOUNT_PATH)
|
|
↓ 없으면
|
|
3. 레거시 파일 (/sales/apikey/gcs_config.txt, google_service_account.json)</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 7: AI 설정 관리 시스템 ─── --}}
|
|
<div class="gai-card">
|
|
<div class="gai-card-header">
|
|
<div class="flex items-center gap-2">
|
|
<div class="gai-icon-circle" style="width: 28px; height: 28px; background: #7c3aed;">
|
|
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-base font-semibold text-gray-800">AI 설정 관리 시스템</h2>
|
|
<p class="text-xs text-gray-400 mt-0.5">AiConfig — 다중 Provider 관리, 연결 테스트, 토글 활성화</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-5">
|
|
{{-- Provider 테이블 --}}
|
|
<div class="text-sm font-medium text-gray-700 mb-3">지원 Provider</div>
|
|
<div class="flex gap-4 mb-5" style="flex-wrap: wrap;">
|
|
@php
|
|
$providers = [
|
|
['name' => 'Gemini', 'provider' => 'gemini', 'model' => 'gemini-2.5-flash', 'use' => '명함 OCR, 회의 요약, 음성 분석', 'color' => 'blue', 'auth' => 'Vertex AI / API Key'],
|
|
['name' => 'Claude', 'provider' => 'claude', 'model' => 'claude-sonnet-4-20250514', 'use' => 'AI 재무 분석 (예비)', 'color' => 'purple', 'auth' => 'API Key'],
|
|
['name' => 'OpenAI', 'provider' => 'openai', 'model' => 'gpt-4o', 'use' => '범용 AI (예비)', 'color' => 'green', 'auth' => 'API Key'],
|
|
['name' => 'GCS', 'provider' => 'gcs', 'model' => '—', 'use' => '음성 녹음 백업, 파일 저장', 'color' => 'cyan', 'auth' => 'Service Account'],
|
|
];
|
|
@endphp
|
|
@foreach($providers as $prov)
|
|
<div class="p-3 border rounded-lg" style="flex: 1 1 220px; border-color: var(--tw-border-opacity, 1); {{ $prov['color'] === 'blue' ? 'border-color: #93c5fd; background: #eff6ff;' : ($prov['color'] === 'purple' ? 'border-color: #c4b5fd; background: #f5f3ff;' : ($prov['color'] === 'green' ? 'border-color: #86efac; background: #f0fdf4;' : 'border-color: #67e8f9; background: #ecfeff;')) }}">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<span class="gai-badge gai-badge-{{ $prov['color'] }}">{{ $prov['name'] }}</span>
|
|
<span class="text-xs text-gray-400 font-mono">{{ $prov['provider'] }}</span>
|
|
</div>
|
|
<div class="space-y-1 text-xs text-gray-600">
|
|
<div><strong>모델:</strong> {{ $prov['model'] }}</div>
|
|
<div><strong>용도:</strong> {{ $prov['use'] }}</div>
|
|
<div><strong>인증:</strong> {{ $prov['auth'] }}</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
{{-- DB 구조 --}}
|
|
<div class="text-sm font-medium text-gray-700 mb-2">데이터베이스 구조</div>
|
|
<table class="w-full text-sm mb-4">
|
|
<thead>
|
|
<tr class="border-b-2 border-gray-200">
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium" style="width: 25%;">테이블</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium" style="width: 30%;">설명</th>
|
|
<th class="text-left py-2 px-3 text-gray-600 font-medium">주요 컬럼</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono text-xs text-gray-800">ai_configs</td>
|
|
<td class="py-2 px-3 text-xs text-gray-600">Provider별 설정</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">name, provider, api_key, model, is_active, options(JSON)</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono text-xs text-gray-800">ai_token_usages</td>
|
|
<td class="py-2 px-3 text-xs text-gray-600">토큰 사용량 추적</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">provider, model, menu, input/output_tokens, cost_usd, cost_krw</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono text-xs text-gray-800">ai_pricing_configs</td>
|
|
<td class="py-2 px-3 text-xs text-gray-600">모델별 단가 설정</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">provider, model, input_price_per_1m, output_price_per_1m</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono text-xs text-gray-800">ai_reports</td>
|
|
<td class="py-2 px-3 text-xs text-gray-600">AI 분석 리포트</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">report_type(daily/weekly/monthly), content, status</td>
|
|
</tr>
|
|
<tr class="border-b border-gray-100">
|
|
<td class="py-2 px-3 font-mono text-xs text-gray-800">ai_voice_recordings</td>
|
|
<td class="py-2 px-3 text-xs text-gray-600">음성 녹음</td>
|
|
<td class="py-2 px-3 text-xs text-gray-500">gcs_uri, transcript_text, analysis_text, duration_seconds</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
{{-- 관리 UI 안내 --}}
|
|
<div class="gai-quote">
|
|
<span class="text-sm text-blue-800">AI 설정 관리 페이지: <strong>시스템 관리 > AI 설정</strong> (<code class="px-1 bg-blue-100 rounded text-xs">/system/ai-config</code>) — Provider별 추가/수정/삭제, 활성화 토글, 연결 테스트 가능</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ─── Section 8: 관련 소스 파일 정리 ─── --}}
|
|
<div class="gai-card" style="border-color: #c7d2fe;">
|
|
<div class="gai-card-header" style="background: #eff6ff; border-bottom-color: #dbeafe;">
|
|
<h2 class="text-base font-semibold text-blue-900">관련 소스 파일 & 문서</h2>
|
|
<p class="text-xs text-blue-400 mt-0.5">SAM Google Cloud AI 관련 전체 파일 매핑</p>
|
|
</div>
|
|
<div class="p-5">
|
|
<div class="flex gap-5" style="flex-wrap: wrap;">
|
|
{{-- 서비스 파일 --}}
|
|
<div style="flex: 1 1 300px;">
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<span class="gai-badge gai-badge-blue">서비스 (MNG)</span>
|
|
</div>
|
|
<div class="space-y-2">
|
|
@php
|
|
$mngFiles = [
|
|
['file' => 'app/Services/GoogleCloudService.php', 'desc' => 'STT V1/V2, Speaker Diarization, GCS 업로드/다운로드'],
|
|
['file' => 'app/Services/GoogleCloudStorageService.php', 'desc' => 'GCS 전용 서비스 (서명 URL, 설정 우선순위)'],
|
|
['file' => 'app/Services/MeetingMinuteService.php', 'desc' => '회의록 생성/수정/삭제, STT+Gemini 파이프라인'],
|
|
['file' => 'app/Services/AiVoiceRecordingService.php', 'desc' => '음성 녹음 처리, 인터뷰 템플릿 분석'],
|
|
['file' => 'app/Services/GeminiService.php', 'desc' => 'Gemini API 호출 (명함 OCR 등)'],
|
|
['file' => 'app/Helpers/AiTokenHelper.php', 'desc' => '토큰 사용량 기록, 비용 계산 (USD/KRW)'],
|
|
];
|
|
@endphp
|
|
@foreach($mngFiles as $f)
|
|
<div class="p-2.5 bg-blue-50 border border-blue-100 rounded-lg">
|
|
<div class="font-mono text-xs text-blue-800">{{ $f['file'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">{{ $f['desc'] }}</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 모델 & API 파일 --}}
|
|
<div style="flex: 1 1 300px;">
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<span class="gai-badge gai-badge-purple">모델 & API</span>
|
|
</div>
|
|
<div class="space-y-2">
|
|
@php
|
|
$modelFiles = [
|
|
['file' => 'app/Models/System/AiConfig.php', 'desc' => 'AI 설정 모델 (Provider별 활성 조회)'],
|
|
['file' => 'app/Models/Juil/MeetingMinute.php', 'desc' => '회의록 모델 (상태 관리, 관계)'],
|
|
['file' => 'app/Models/AiVoiceRecording.php', 'desc' => '음성 녹음 모델 (파일 만료, 상태)'],
|
|
];
|
|
$apiFiles = [
|
|
['file' => 'api/app/Services/AiReportService.php', 'desc' => '재무 분석 리포트 생성 (Gemini Vertex AI)'],
|
|
['file' => 'config/gcs.php', 'desc' => 'GCS 환경변수 설정 매핑'],
|
|
['file' => 'config/services.php', 'desc' => 'Google Cloud 서비스 설정 (credentials, bucket)'],
|
|
];
|
|
@endphp
|
|
@foreach($modelFiles as $f)
|
|
<div class="p-2.5 bg-purple-50 border border-purple-100 rounded-lg">
|
|
<div class="font-mono text-xs text-purple-800">{{ $f['file'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">{{ $f['desc'] }}</div>
|
|
</div>
|
|
@endforeach
|
|
@foreach($apiFiles as $f)
|
|
<div class="p-2.5 bg-green-50 border border-green-100 rounded-lg">
|
|
<div class="font-mono text-xs text-green-800">{{ $f['file'] }}</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">{{ $f['desc'] }}</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
<div class="flex items-center gap-2 mt-3 mb-2">
|
|
<span class="gai-badge gai-badge-gray">문서</span>
|
|
</div>
|
|
<div class="p-2.5 bg-gray-50 border border-gray-200 rounded-lg">
|
|
<div class="font-mono text-xs text-gray-700">docs/guides/ai-config-settings.md</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">AI 및 스토리지 설정 기술문서</div>
|
|
</div>
|
|
<div class="p-2.5 bg-gray-50 border border-gray-200 rounded-lg">
|
|
<div class="font-mono text-xs text-gray-700">docs/features/ai/README.md</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">AI 분석 리포트 기능 명세</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 한 줄 요약 --}}
|
|
<div class="mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg text-center">
|
|
<div class="text-lg font-bold text-blue-900">
|
|
Google Cloud AI — SAM의 핵심 자동화 엔진
|
|
</div>
|
|
<p class="text-sm text-blue-600 mt-2">Speech-to-Text + Gemini + Cloud Storage = 음성/문서/분석 완전 자동화</p>
|
|
<p class="text-xs text-blue-400 mt-1">(주)코드브릿지엑스 | @codebridge-x.com</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
@endsection
|