TradingAgents/web/backend/apps/trading_api/views.py

212 lines
8.2 KiB
Python

from rest_framework import status, permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.views import APIView
from django.shortcuts import get_object_or_404
from asgiref.sync import sync_to_async
import asyncio
from datetime import datetime
from apps.authentication.models import AnalysisSession
from apps.authentication.serializers import AnalysisSessionSerializer, CreateAnalysisSessionSerializer
from .services import TradingAnalysisManager, TradingAnalysisService
class AnalysisConfigView(APIView):
"""분석 설정 정보 조회"""
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
"""분석 설정 옵션들 반환"""
config = {
'analysts': [
{'value': 'market', 'label': 'Market Analyst', 'description': '시장 데이터 분석'},
{'value': 'social', 'label': 'Social Analyst', 'description': '소셜 센티멘트 분석'},
{'value': 'news', 'label': 'News Analyst', 'description': '뉴스 분석'},
{'value': 'fundamentals', 'label': 'Fundamentals Analyst', 'description': '기본 분석'},
],
'research_depths': [
{'value': 1, 'label': 'Shallow', 'description': '빠른 분석, 적은 토론 라운드'},
{'value': 3, 'label': 'Medium', 'description': '중간 정도 분석, 보통 토론 라운드'},
{'value': 5, 'label': 'Deep', 'description': '깊은 분석, 많은 토론 라운드'},
],
'shallow_thinkers': [
{'value': 'gpt-4o-mini', 'label': 'GPT-4o-mini', 'description': '빠르고 효율적'},
{'value': 'gpt-4.1-nano', 'label': 'GPT-4.1-nano', 'description': '초경량 모델'},
{'value': 'gpt-4.1-mini', 'label': 'GPT-4.1-mini', 'description': '컴팩트 모델'},
{'value': 'gpt-4o', 'label': 'GPT-4o', 'description': '표준 모델'},
],
'deep_thinkers': [
{'value': 'gpt-4.1-nano', 'label': 'GPT-4.1-nano', 'description': '초경량 모델'},
{'value': 'gpt-4.1-mini', 'label': 'GPT-4.1-mini', 'description': '컴팩트 모델'},
{'value': 'gpt-4o', 'label': 'GPT-4o', 'description': '표준 모델'},
{'value': 'o4-mini', 'label': 'o4-mini', 'description': '추론 특화 모델 (컴팩트)'},
{'value': 'o3-mini', 'label': 'o3-mini', 'description': '고급 추론 모델 (경량)'},
{'value': 'o3', 'label': 'o3', 'description': '완전한 고급 추론 모델'},
{'value': 'o1', 'label': 'o1', 'description': '최고급 추론 및 문제 해결 모델'},
]
}
return Response(config)
class StartAnalysisView(APIView):
"""분석 시작"""
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
"""새로운 분석 시작"""
serializer = CreateAnalysisSessionSerializer(data=request.data)
if serializer.is_valid():
# 분석 세션 생성
session = serializer.save(user=request.user)
# 백그라운드에서 분석 실행
# 실제 환경에서는 Celery나 다른 task queue를 사용하는 것이 좋습니다
asyncio.create_task(self._start_analysis_async(request.user, session.id))
return Response({
'message': '분석이 시작되었습니다.',
'session_id': session.id,
'session': AnalysisSessionSerializer(session).data
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
async def _start_analysis_async(self, user, session_id):
"""비동기 분석 실행"""
try:
await TradingAnalysisManager.start_analysis(user, session_id)
except Exception as e:
print(f"분석 실행 중 오류: {e}")
class AnalysisStatusView(APIView):
"""분석 상태 조회"""
permission_classes = [permissions.IsAuthenticated]
def get(self, request, session_id):
"""특정 분석 세션의 상태 조회"""
session = get_object_or_404(
AnalysisSession,
id=session_id,
user=request.user
)
serializer = AnalysisSessionSerializer(session)
return Response(serializer.data)
class CancelAnalysisView(APIView):
"""분석 취소"""
permission_classes = [permissions.IsAuthenticated]
def post(self, request, session_id):
"""분석 취소"""
try:
success = TradingAnalysisManager.cancel_analysis(request.user, session_id)
if success:
return Response({
'message': '분석이 취소되었습니다.',
'session_id': session_id
})
else:
return Response({
'message': '취소할 수 없는 상태입니다.',
'session_id': session_id
}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
return Response({
'error': str(e)
}, status=status.HTTP_404_NOT_FOUND)
class AnalysisHistoryView(APIView):
"""분석 기록 조회"""
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
"""사용자의 분석 기록 조회"""
sessions = TradingAnalysisManager.get_user_analysis_sessions(request.user)
serializer = AnalysisSessionSerializer(sessions, many=True)
return Response({
'count': len(sessions),
'results': serializer.data
})
class AnalysisReportView(APIView):
"""분석 보고서 조회"""
permission_classes = [permissions.IsAuthenticated]
def get(self, request, session_id):
"""특정 분석 세션의 보고서 조회"""
session = get_object_or_404(
AnalysisSession,
id=session_id,
user=request.user
)
if session.status != 'completed':
return Response({
'message': '분석이 완료되지 않았습니다.',
'status': session.status
}, status=status.HTTP_400_BAD_REQUEST)
return Response({
'session_id': session.id,
'ticker': session.ticker,
'analysis_date': session.analysis_date,
'final_report': session.final_report,
'completed_at': session.completed_at,
'duration': (session.completed_at - session.started_at).total_seconds() if session.started_at and session.completed_at else None
})
@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def get_analysis_options(request):
"""분석 옵션 조회 (간단한 버전)"""
options = {
'default_values': {
'ticker': 'SPY',
'analysis_date': datetime.now().strftime('%Y-%m-%d'),
'analysts_selected': ['market', 'social', 'news', 'fundamentals'],
'research_depth': 3,
'shallow_thinker': 'gpt-4o-mini',
'deep_thinker': 'gpt-4o'
}
}
# 사용자 프로필의 기본값이 있다면 사용
if hasattr(request.user, 'profile'):
profile = request.user.profile
options['user_preferences'] = {
'default_ticker': profile.default_ticker,
'preferred_research_depth': profile.preferred_research_depth,
'preferred_shallow_thinker': profile.preferred_shallow_thinker,
'preferred_deep_thinker': profile.preferred_deep_thinker,
}
return Response(options)
@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def get_running_analyses(request):
"""실행 중인 분석 조회"""
running_sessions = AnalysisSession.objects.filter(
user=request.user,
status='running'
)
serializer = AnalysisSessionSerializer(running_sessions, many=True)
return Response({
'count': len(running_sessions),
'results': serializer.data
})