""" 세션·메시지 미러 — 프론트 `features/snap/contract/types.ts` 와 1:1. 대화 원본(컨텍스트)은 OpenCode 가 들고 있고, 여긴 목록·검색·usage·isGenerating 용 사본. OpenCode 는 페이지네이션·본문 검색·메시지별 토큰을 안 주니까 여기서 함. """ from django.conf import settings from django.db import models class ChatSession(models.Model): id = models.CharField(primary_key=True, max_length=64) # OpenCode session id 그대로 user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="chat_sessions") title = models.CharField(max_length=200, blank=True) # 사용자가 지은 제목 (지금은 안 씀) title_llm = models.CharField(max_length=200, blank=True) # OpenCode 가 지은 제목 is_generating = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-updated_at"] def as_dto(self) -> dict: return { "id": self.id, "title": self.title or None, "titleLlm": self.title_llm or None, "isGenerating": self.is_generating, "createdAt": self.created_at.isoformat(), "updatedAt": self.updated_at.isoformat(), } class ChatMessage(models.Model): ROLES = [("user", "user"), ("assistant", "assistant"), ("system", "system")] session = models.ForeignKey(ChatSession, on_delete=models.CASCADE, related_name="messages") role = models.CharField(max_length=16, choices=ROLES) content = models.TextField() # markdown created_at = models.DateTimeField(auto_now_add=True) # assistant 행에만 채움 input_tokens = models.IntegerField(null=True, blank=True) output_tokens = models.IntegerField(null=True, blank=True) cost_usd = models.FloatField(null=True, blank=True) elapsed_ms = models.IntegerField(null=True, blank=True) class Meta: ordering = ["created_at", "id"] def as_dto(self) -> dict: return { "sessionId": self.session_id, "role": self.role, "content": self.content, "createdAt": self.created_at.isoformat(), "inputTokens": self.input_tokens, "outputTokens": self.output_tokens, "costUsd": self.cost_usd, "elapsedMs": self.elapsed_ms, }