Files
CODE_ASSISTANT/5_django_backend/apps/chat/models.py
T
leehc991028andClaude Fable 5.1 2869985139 feat(backend): Django + OpenCode 백엔드 추가 — 5_django_backend/
앱이 기대하는 base-backend 계약(envelope·JWT·/chat/stream SSE)을 그대로 구현.
Django 는 로그인·세션 미러(SQLite/PG)·OpenCode 이벤트 번역만 맡고, 답변은 전용
OpenCode 인스턴스(opencode/ workspace, codeassist 에이전트)가 만듦.
- accounts: 이메일 로그인, access 60분 / refresh 14일, entra/config 는 501
- chat: 세션 목록·검색·메시지·취소 + POST /chat/stream 어댑터(part.delta→token,
  idle→usage/done, 클라 끊겨도 턴 감시 태스크가 DB 마무리, 첫 이벤트 60초 타임아웃)
- OpenCode 1.18 멀티 프로젝트라 모든 요청에 ?directory= 부착
- docs-lib 에 OpenCode SDK 1.18.6 타입 원본, pytest 32

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:28:31 +09:00

62 lines
2.4 KiB
Python

"""
세션·메시지 미러 — 프론트 `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,
}