Files
sam-manage/app/Models/MeetingLog.php
hskwon 331eaebf86 feat: 웹 녹음 AI 요약 기능 구현
- MeetingLog 모델 (BelongsToTenant, SoftDeletes)
- GoogleCloudService (GCS 업로드, STT API)
- MeetingLogService (Claude API 요약)
- MeetingLogController (HTMX/JSON 듀얼 응답)
- 순수 Tailwind CSS UI 구현
- API 라우트 8개 엔드포인트 등록
2025-12-16 15:07:56 +09:00

120 lines
2.7 KiB
PHP

<?php
namespace App\Models;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 회의록 모델 (웹 녹음 AI 요약)
*
* admin_meeting_logs 테이블을 사용합니다.
*/
class MeetingLog extends Model
{
use BelongsToTenant, SoftDeletes;
protected $table = 'admin_meeting_logs';
protected $fillable = [
'tenant_id',
'user_id',
'title',
'audio_file_path',
'audio_gcs_uri',
'transcript_text',
'summary_text',
'status',
'duration_seconds',
'file_expiry_date',
];
protected $casts = [
'duration_seconds' => 'integer',
'file_expiry_date' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
/**
* 상태 상수
*/
public const STATUS_PENDING = 'PENDING';
public const STATUS_PROCESSING = 'PROCESSING';
public const STATUS_COMPLETED = 'COMPLETED';
public const STATUS_FAILED = 'FAILED';
/**
* 작성자 관계
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* 녹음 시간 포맷 (MM:SS)
*/
public function getFormattedDurationAttribute(): string
{
if (! $this->duration_seconds) {
return '00:00';
}
$minutes = floor($this->duration_seconds / 60);
$seconds = $this->duration_seconds % 60;
return sprintf('%02d:%02d', $minutes, $seconds);
}
/**
* 상태 레이블
*/
public function getStatusLabelAttribute(): string
{
return match ($this->status) {
self::STATUS_PENDING => '대기중',
self::STATUS_PROCESSING => '처리중',
self::STATUS_COMPLETED => '완료',
self::STATUS_FAILED => '실패',
default => $this->status,
};
}
/**
* 상태 색상 (Tailwind CSS)
*/
public function getStatusColorAttribute(): string
{
return match ($this->status) {
self::STATUS_PENDING => 'badge-warning',
self::STATUS_PROCESSING => 'badge-info',
self::STATUS_COMPLETED => 'badge-success',
self::STATUS_FAILED => 'badge-error',
default => 'badge-ghost',
};
}
/**
* 처리 완료 여부
*/
public function isCompleted(): bool
{
return $this->status === self::STATUS_COMPLETED;
}
/**
* 처리 중 여부
*/
public function isProcessing(): bool
{
return $this->status === self::STATUS_PROCESSING;
}
}