ํธ๋ฆฌํ API์ ๊ตฌ์ฑ์ ์ํด์ Mixins์ GenericViewSet์ ์ฌ์ฉํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์๋์ ๊ฐ์ด ์ฌ์ฉํ๊ฒ ๋๋ค.
class DiaryViewSet(GenericViewSet, # ๋ฏน์ค์ธ ์ฌ์ฉ์ ์ํด ๊ผญ ์ถ๊ฐ
mixins.ListModelMixin,#๋ฆฌ์คํธ API
mixins.CreateModelMixin,#์์ฑ API
mixins.RetrieveModelMixin,#์กฐํ API
mixins.UpdateModelMixin,#์์ API. ๋ถ๋ถ ์์ ๊ณผ ์ ์ฒด ์์ ์์
mixins.DestroyModelMixin):#์ญ์ API
# ์๋ ํผ๋ฏธ์
~์ฟผ๋ฆฌ์
์ ํ์ ์์ฑ
permission_classes = [IsOwner]
serializer_class = DiarySerializer
queryset = Diary.objects.all()
"""
์ฌ๊ธฐ์ ์ ๋ ์ฃผ์์ ํ์ swagger API๋ฌธ์๋ฅผ ์ํ ๊ฒ. ์ด๋ค ๋ทฐ์ธ์ง ์์ฑ.
์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ฑ.
์ผ๊ธฐ์ ๋ด์ฉ์ ๋ํ API
"""
# ์ด ๋ถ๋ถ์ ๋ฏน์ค์ธ์ ์ฌ์ฉํ ๋ ์ฟผ๋ฆฌ๋ฅผ ํํฐ๋งํ์ฌ ๋ณธ์ธ์ ๋ฐ์ดํฐ๋ง ๋ณผ ์ ์๋๋ก ์ฒ๋ฆฌํ๊ฒ
def filter_queryset(self,queryset):
queryset = queryset.filter(user=self.request.user)
return super().filter_queryset(queryset)
# ์ด ์๋๋ก ๋ถํฐ ์ถ๊ฐ๋ก ์ปค์คํ
์ด ํ์ํ ๋ฏน์ค์ธ๋ค, ํจ์๋ค์ ์์ฑํ๋ค.
# ์๋๋ถ๋ถ์์ด๋ ๊ธฐ๋ณธ ๋ฏน์ค์ธ์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ค
๊ธฐ๋ณธ ๋ฏน์ค์ธ์ ํจ์๋ค์ ์๋ ๊นํ์์ ํ์ธํ ์ ์๋ค.
https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py
django-rest-framework/rest_framework/mixins.py at master ยท encode/django-rest-framework
Web APIs for Django. ๐ธ. Contribute to encode/django-rest-framework development by creating an account on GitHub.
github.com
์ญ์ ๋ทฐ๊ฐ ์์ฒญ๋๊ฒ ๋ง๊ธฐ ๋๋ฌธ์ ํน์ํ ๊ฒฝ์ฐ๋ง ์ดํด๋ณด์.
Follow
ํ๋ก์ ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ mixins๋ค์ ๊ฐ ๊ธฐ๋ฅ๋ค์ ํ์ฉํ์ฌ ๊ตฌํํ์๋ค. (์ฝ๊ฐ ์ผ๋งค๋ก ๊ตฌํํ ๋๋.. ํ์ง๋ง ์ ๋์๊ฐ๋ค๋ฉด?)
1. permissions์ IsOwnerOrReadOnly๋ฅผ ํตํด ํ๋ก์์ ์ฐ๊ด๋ ์ฌ์ฉ์๋ง ์์ ํ ์ ์๋๋ก ํ๋ค.
2. filter_queryset์ ํตํด ์ฐ๊ด๋ ์ฌ์ฉ์๋ง ์ ๊ทผํ ์ ์๊ฒ ํ๋ค.
๊ฐ๋ณ ํจ์๋ณ ์ญํ
CREATE : ํ๋ก์ฐ ์์ฒญ
DESTROY: ํ๋ก์ฐ ์ทจ์/์ญ์
UPDATE: ํ๋ก์ฐ ํ์ฉ
PARTIAL_UPDATE: ํ๋ก์ฐ ๊ฑฐ์
class FollowViewSet(GenericViewSet,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin):
permission_classes = [IsOwnerOrReadOnly]
serializer_class = FollowSerializer
queryset = Follow.objects.all()
def filter_queryset(self,queryset):
queryset = queryset.filter(Q(follower=self.request.user) | Q(following_user=self.request.user))
return super().filter_queryset(queryset)
'''
ํ๋ก์ฐ API
---
### id : ํ๋ก์ฐ ์์ฒญ์ id
'''
@swagger_auto_schema( request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'username': openapi.Schema(type=openapi.TYPE_STRING, description='ํ๋ก์ฐ ์์ฒญํ ์ ์ ์ username')
}
))
def create(self, request, *args, **kwargs):
'''
ํ๋ก์ฐ ์์ฒญํ๋ API
---
### id : ํ๋ก์ฐ ์์ฒญํ username
## ์์ request:
{
"username": "threepark"
}
## ์์ response:
201
{
"id": 11,
"status": "requested",
"follower": 3,
"following_user": 1
}
400
'''
# ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ฌ์ฉ์ ์ด๋ฆ์ ๋ฐ์
username = request.data.get('username')
# ๋ฐ์ ์ฌ์ฉ์ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์๋ฅผ ์ฐพ์
try:
following_user = User.objects.get(username=username)
except User.DoesNotExist:
return Response({"message": f"User '{username}' does not exist"}, status=status.HTTP_404_NOT_FOUND)
# ํ๋ก์ฐ ์์ฒญ ์์ฑ์ ์ฌ์ฉํ ๋ฐ์ดํฐ ๊ตฌ์ฑ
request_data = {
'follower': request.user.id,
'following_user': following_user.id,
'status': Follow.REQUESTED
}
serializer = self.get_serializer(data=request_data)
serializer.is_valid(raise_exception=True)
user = self.request.user
followee = serializer.validated_data.get('following_user')
if followee==user:
return Response({"message": f"Cannot Follow yourself, {followee.username}."}, status=status.HTTP_400_BAD_REQUEST)
if Follow.objects.filter(follower=user, following_user=followee).exists() | Follow.objects.filter(follower=user, following_user=followee).exists():
return Response({"message": f"Follow request already sent to {followee.username}."}, status=status.HTTP_400_BAD_REQUEST)
follow_request, created = Follow.objects.get_or_create(follower=request.user, following_user=followee, status=Follow.REQUESTED)
serializer = self.get_serializer(follow_request)
if created:
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response({"message": f"Follow request already sent to {followee.username}"}, status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, *args, **kwargs):
'''
ํ๋ก์ฐ ์์ฒญ ์ญ์ /์ทจ์ํ๋ API
---
### id : ํ๋ก์ฐ ์์ฒญ์ id
## ์์ response:
204
{"message": "Follow request deleted"}
'''
instance = self.get_object()
self.perform_destroy(instance)
return Response({"message": "Follow request deleted"}, status=status.HTTP_204_NO_CONTENT)
@swagger_auto_schema(
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={}
))
def update(self, request, *args, **kwargs):
'''
ํ๋ก์ฐ ์์ฒญ ํ์ฉํ๋ API
---
### id : ํ๋ก์ฐ ์์ฒญ์ id
## ์์ response:
200
{
"id": 11,
"status": "accepted",
"follower": 3,
"following_user": 1
}
401 ๊ถํ์ด ์์ต๋๋ค
'''
instance = self.get_object()
# ์์ฒญ๋ฐ์ ์ฌ์ฉ์๊ฐ ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ์ผ์นํ๋์ง ํ์ธ
if instance.following_user != request.user:
raise PermissionDenied("๊ถํ์ด ์์ต๋๋ค")
instance.status = Follow.ACCEPTED
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
@swagger_auto_schema(
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={}
))
def partial_update(self, request, *args, **kwargs):
'''
ํ๋ก์ฐ ์์ฒญ ๊ฑฐ์ ํ๋ API
---
### id : ํ๋ก์ฐ ์์ฒญ์ id
## ์์ response:
200
{
"id": 9,
"status": "rejected",
"follower": 2,
"following_user": 1
}
'''
instance = self.get_object()
instance.status = Follow.REJECTED
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
AI ์์ ์ด ํ์ํ Viewset๋ค
์ด ์๋๋ API์์ฒญ์ด ๋ค์ด๊ฐ๋ ์ธ๋ถ ํจ์๋ฅผ ํตํด AI์ ์์ ์ด ์๋ ๋ถ๋ถ์ ๋ํ View์ด๋ค.
๋์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.

Music
views ์๋จ์ AI ์๋ฒ๋ก ์์ ์ถ์ฒ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ ํจ์๋ฅผ ์์ฑํ๋ค.
def request_music_from_flask(content):
"""
diary content ๋ฅผ ai์๋ฒ์ ์ ๋ฌ, ์์
์ถ์ฒ ๋ฐ์์ด
"""
flask_url = f'http://{settings.FLASK_URL}:5000/get_music'
try:
response = requests.post(flask_url, json={'content': content},verify=False, timeout=50)
if response.status_code == 200:
response_data = response.json()
time.sleep(2)
return response_data
else:
print("Failed to get music from Flask:", response.status_code)
return None
except Exception as e:
print("Error:", e)
time.sleep(10)
return None
์ด๋ฅผ ๋ฐํ์ผ๋ก ์์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ , ์ผ๊ธฐ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ฒฐํ๋ค.
def update(self, request,*args, **kwargs):
"""
diary_music_update ์ผ๊ธฐ์ ๋ํด ์์
์ ์ถ์ฒํ๋ API
---
### id = ์ผ๊ธฐ ID
์ต๋ 15์ด ์์ ๊ฐ๋ฅ
### ์์ request:
{
"user": 1,
}
### ์์ response:
200
{
"id": 1,
"user": 1,
"content": "๋๋ฌด ๋๊ทผ๊ฑฐ๋ฆฐ๋ค! ๊ณผ์ฐ rds์ ๋ด ๋ค์ด์ด๋ฆฌ๊ฐ ์ ์ฌ๋ผ๊ฐ๊น? ์ค๋ ์ด๊ฒ๋ง ์ฑ๊ณตํ๋ฉด ๋๋ฌด ์ฆ๊ฑฐ์ด ๋ง์์ผ๋ก ์ ์ ์์๊ฒ ๊ฐ๋ค!",
"music": {
"id": 1,
"music_title": "๊ทธ๋๋ง ์๋ค๋ฉด (์ฌ๋ฆ๋ ์ฐ๋ฆฌ X ๋๋์ปค๋ฅ์
(Nerd Connection))",
"artist": "๋๋์ปค๋ฅ์
(Nerd Connection)",
"genre": "๋ฐ๋ผ๋"
}
}
401
400
{'detail': 'Failed to get similar music from Flask'}
"""
partial = kwargs.pop('partial', True)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
print(serializer.data['content'])
response = request_music_from_flask(serializer.data['content'])
best_music = response.get('most_similar_song')
print(best_music)
similar_songs = response.get('similar_songs')
print(similar_songs)
if best_music:
music, created = Music.objects.get_or_create(music_title=best_music['title'], artist=best_music['artist'], genre=best_music['genre'])
instance.music = music
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response({'detail': 'Failed to get similar music from Flask'}, status=status.HTTP_400_BAD_REQUEST)
Emotion&Chat
views ์๋จ์ AI ์๋ฒ๋ก emotion label ๊ฒ์ถ๊ณผ ์์ ๋ฌธ๊ตฌ(comment) ๋ฅผ ์์ฑํ๋๋ก ์์ฒญํ๋ ํจ์๋ฅผ ์์ฑํ๋ค.
#views.py์ ์๋จ์ AI์๋ฒ๋ก ์์ฒญ์ํ๊ณ ์๋ต์ ๋ฐ๋ ํจ์ ์ถ๊ฐ
def request_emotion(content):
"""
์ผ๊ธฐ ๋ด์ฉ์ผ๋ก emootion label ๊ฒ์ถ
"""
flask_url = f'http://{settings.FLASK_URL}:5000/get_sentiment'
try:
response = requests.post(flask_url, json={'content': content},verify=False, timeout=50)
if response.status_code == 200:
response_data = response.json()
emotion_label = response_data['emotion_label']
print("Received emotion_label:", emotion_label)
time.sleep(2)
return emotion_label
else:
print("Failed to get emotion from Flask:", response.status_code)
return None
except Exception as e:
print("Error:", e)
time.sleep(10)
return None
def request_comment(content):
"""
์ผ๊ธฐ ๋ด์ฉ์ผ๋ก ์์ ๋ฌธ๊ตฌ ์์ฑ
"""
flask_url = f'http://{settings.FLASK_URL}:5000/get_comment'
try:
response = requests.post(flask_url, json={'content': content},verify=False, timeout=50)
if response.status_code == 200:
response_data = response.json()
comment = response_data['comment']
print("Received comment:", comment)
time.sleep(2)
return comment
else:
print("Failed to get comment from Flask:", response.status_code)
return None
except Exception as e:
print("Error:", e)
time.sleep(10)
return None
์ด๋ฅผ ๋ฐํ์ผ๋ก ViewSet๋ด๋ถ์ ํจ์๋ฅผ ์์ฑํ๋ค.
#ViewSet๋ด๋ถ์ create ์์ฑ
def create(self, request, *args, **kwargs):
"""
emotion_create ์ผ๊ธฐ ๋ด์ฉ์ผ๋ก ๊ฐ์ ๋ผ๋ฒจ, ์์๋ฌธ๊ตฌ ์์ฑ ํ๋ API
---
## ์์ request:
{
'diary' : 2
}
## ์์ response:
200
{
"id": 2,
"emotion_label": "๋ถ์",
"emotion_prompt": "",
"chat": " ์ด๋ณ์ ์ฌ์ค์ผ์ง๋ ๋ชจ๋ฅด๊ฒ ์ด์ ",
"diary": 2
}
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
diary = serializer.validated_data.get('diary')
if diary.user != request.user:
return Response({'error': "Diary does not belong to the current user."}, status=status.HTTP_400_BAD_REQUEST)
chat = request_comment(diary.content)
label = request_emotion(diary.content)
existing_emotion = Emotion.objects.filter(diary=diary).first()
if existing_emotion:
serializer = self.get_serializer(existing_emotion, data={'chat': chat, 'emotion_label': label}, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save(diary=diary, chat=chat, emotion_label = label)
else:
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(diary=diary, chat=chat, emotion_label = label)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Image
GPT - ์ด๋ฏธ์ง ์์ฑ์ฉ ํ๋กฌํํธ ์์ฑ
GPT API์ ๋ฏธ๋ฆฌ ์ ์ํ GPT ํ๋กฌํํธ๋ฅผ ํฉํ์ฌ GPT์ ์ด๋ฏธ์ง ์์ฑ์ฉ ํ๋กฌํํธ๋ฅผ ์์ฑํ๋ค.
from django.conf import settings
import openai
with open(f"{settings.BASE_DIR}/ai/genTextBase.txt", 'r', encoding='utf-8') as file:
base_text = ''.join(file.readlines())
api_key = settings.OPENAI_API_KEY
openai.api_key=api_key
def get_prompt(content):
"""
์ผ๊ธฐ ๋ด์ฉ์ ์
๋ ฅ๋ฐ์ ํ๋กฌํํธ ์์ฑ
"""
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": f"{base_text} {content.strip()}"},]
)
generated_text = completion["choices"][0]["message"]["content"]
output_text=generated_text.split('\n')
pre_text = "(masterpiece,detailed), (Oil Painting:1.3), (Impressionism:1.3) ,(oil painting with brush strokes:1.2), (looking away:1.1), "
prompts = [pre_text+v for v in output_text if v]
return prompts
Flask&AI์๋ฒ - ์ด๋ฏธ์ง ์์ฑ ์์ฒญ
์ด๋ฏธ์ง ํ๋กฌํํธ๋ฅผ ์ ๋ฌํด AI์๋ฒ์์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ณ , ์ด๋ฏธ์ง url์ ์๋ต์ผ๋ก ๋ฐ๋๋ค.
def request_image_from_flask(prompt):
"""
์์ฑ๋ prompt๋ก ์ด๋ฏธ์ง ์์ฑ
"""
flask_url = f'http://{settings.FLASK_URL}:5000/get_image'
try:
# HTTP POST ์์ฒญ์ผ๋ก prompt๋ฅผ Flask์ ์ ์ก
response = requests.post(flask_url, json={'prompt': prompt},verify=False, timeout=150)
# ์๋ต ํ์ธ
if response.status_code == 200:
# ์ด๋ฏธ์ง ์์ฑ ์ฑ๊ณต
response_data = response.json()
image_url = response_data['image_url']
print("Received image url:", image_url)
time.sleep(2)
return image_url
else:
# ์ด๋ฏธ์ง ์์ฑ ์คํจ
print("Failed to get image from Flask:", response.status_code)
return None
except Exception as e:
print("Error:", e)
time.sleep(10)
return None
Viewset - createํจ์ ์์ฑ
์์์ ์์ฑํ ํจ์๋ค์ ํตํด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ณ , ์ ๋ฌ๋ฐ์ url์ ํตํด ์ด๋ฏธ์ง ์๋ฆฌ์ผ๋ผ์ด์ ์์ฑ
def create(self, request, *args, **kwargs):
'''
์ด๋ฏธ์ง ์์ฑ API
---
### ์๋ต์ ์ต๋ 40์ด ์์ ๊ฐ๋ฅ
## ์์ request:
{
'diary' : 1
}
## ์์ response:
201
{
"id": 70,
"created_at": "2024-05-02T13:04:10.208658+09:00",
"image_url": "https://๋ฒํท์ฃผ์/images/826cb58e-46a3-41fc-9699-bc2eccdc1355.jpg",
"image_prompt": "(masterpiece,detailed), (Oil Painting:1.3), (Impressionism:1.3) ,(oil painting with brush strokes:1.2), (looking away:1.1), a girl in a traditional Korean hanbok, cherry blossom background, soft pastel colors, Korean artist reference, (ethereal:1.2), (delicate details:1.3), (dreamy atmosphere:1.25)",
"diary": 1
}
400
{
'error': "Failed to get image from Flask" ์ด ๊ฒฝ์ฐ AI ์๋ฒ๊ฐ ๊บผ์ ธ์์๋์
}
400
{
'error': "Error uploading image: {str(e)}"
}
401
403
'''
try:
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
diary = serializer.validated_data.get('diary')
image_prompt = get_prompt(diary.content)[0]
image_url = request_image_from_flask(image_prompt)
if not image_url:
return Response({'error': "Failed to get image from Flask"}, status=status.HTTP_400_BAD_REQUEST)
new_image = Image.objects.get_or_create(diary=diary, image_url=image_url, image_prompt=image_prompt)
serializer.validated_data['diary'] = diary
serializer.validated_data['image_url'] = image_url
serializer.validated_data['image_prompt'] = image_prompt
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
except Exception as e:
return Response({'error': f"Error uploading image: {str(e)}"}, status=status.HTTP_400_BAD_REQUEST)