Skip to content

Django Rest Framework ve ChatGPT API Entegrasyonu

Bu yazımızda Django Rest Framework ile basit bir API geliştirecek ve ChatGPT API'ya (openai API) istek atıp chatGPT'ye gönderilen kodun hangi programlama diline ait olduğunu söylemesini isteyeceğiz.

Kurulumlar

drf_chatgpt adında bir klasör oluşturduktan sonra aşağıdaki komutlar ile sanal ortam oluşturup aktif edelim

python3.11 -m venv venv
source venv/bin/activate
- Aşağıdaki komutlar ile proje için gerekli paketleri kuralım
pip install django
pip install djangorestframework
pip install openai
pip install python-dotenv
- Kurulan paketleri dosyaya yazalım
pip freeze > requirements.txt

Django Projesi Oluşturma

cd drf_chatgpt
source venv/bin/activate
django-admin startproject src .
- api adında django app oluşturma
python manage.py startapp api
- src/settings.py dosyasında harici(externals) ve dahili(internals) uygulamaların eklenmesi
INSTALLED_APPS = [
    # external apps
    'rest_framework',
    'rest_framework.authtoken',
    # internal apps
    'api',
    # default apps
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
- src/settings.py dosyasında environment variables içeren drf_chatgpt/.env dosyasının okunabilmesi için ekleme ve düzenlemelerin yapılması
import os
from pathlib import Path
from dotenv import load_dotenv

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
load_dotenv(os.path.join(BASE_DIR, '.env'))

APIKEY = os.getenv("OPENAI_APIKEY")
- drf_chatgpt/.env içeriği
export OPENAI_APIKEY="sk-openaiAPIkeyiniz"
- src/settings.py dosyasında Django Rest Framework için yetki izin ayarlarının yapılması
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}
- api/models.py düzenlenmesi
from django.db import models

class CodeExplainer(models.Model):
    _input = models.TextField()
    _output = models.TextField()

    class Meta:
        db_table = "t_code_explainer"

Migrationların yapılması

python manage.py makemigrations
python manage.py migrate
- superuser oluşturma
python manage.py createsuperuser

ChatGPT OpenAI API ile Etkileşim

api/utils.py oluşturulması ve düzenlenmesi

import openai
from django.conf import settings

openai.api_key = settings.APIKEY

def send_code_to_api(code):
    try:
        res = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "user", "content": f"Tell me what language is this code written? {code}"},                
                {"role": "system", "content": "You are a helpful assistant that provides code explanations."},
                {"role": "assistant", "content": "Sure! Please provide the code you want me to explain."}

            ],
        )
        return res["choices"][0]["message"]["content"]
    except openai.error.APIError as e:
        raise ValueError(f"OpenAI API returned an API Error: {e}")
    except openai.error.APIConnectionError as e:
        raise ValueError(f"Failed to connect to OpenAI API: {e}")
    except openai.error.RateLimitError as e:
        raise ValueError(f"OpenAI API request exceeded rate limit: {e}")
- send_code_to_api fonksiyonu, verilen code parametresini bir sohbetin bir parçası olarak openai API'ye gönderir ve ardından API'den dönen yanıtın içeriğini döndürür. Kod, hata durumlarına karşı da bazı try-except blokları içerir. Bu bloklar, olası OpenAI API hatalarını yakalar ve uygun hata mesajlarını fırlatır. Sistem mesajı(system role and content), asistanın(chatGPT) davranışını belirlemeye yardımcı olur. Örneğin, asistanın kişiliğini değiştirebilir veya konuşma boyunca nasıl davranması gerektiğine dair özel talimatlar verebilirsiniz. Bununla birlikte, sistem mesajının isteğe bağlı olduğunu ve modelin(chatGPT) davranışının sistem mesajı olmadan genel bir mesaj kullanmaya benzer olduğunu unutmayın.

OpenAI dökümantasyonundan bir örnek istek ve api response

import openai

openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
        {"role": "user", "content": "Where was it played?"}
    ]
)
- openai API Response örneği
{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "The 2020 World Series was played in Texas at Globe Life Field in Arlington.",
        "role": "assistant"
      }
    }
  ],
  "created": 1677664795,
  "id": "chatcmpl-7QyqpwdfhqwajicIEznoc6Q47XAyW",
  "model": "gpt-3.5-turbo-0613",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 17,
    "prompt_tokens": 57,
    "total_tokens": 74
  }
}
- api/serializers.py oluşturulması ve düzenlenmesi
from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from rest_framework.authtoken.models import Token
# internals
from api.models import CodeExplainer
from api.utils import send_code_to_api

class CodeExplainSerializer(serializers.ModelSerializer):
    """
    _output alanı chatGPT'den gelen response verisi ile doldurulacak

    """
    class Meta:
        model = CodeExplainer
        fields = ("id","_input","_output")
        extra_kwargs = {
            "_output":{"read_only":True}
        }

    def create(self, validated_data):
        ce = CodeExplainer(**validated_data)
        # girilen _input degerini chatGPT'ye gonder ve gelen cevabı _output'a atama yap.
        _output = send_code_to_api(validated_data["_input"])
        ce._output = _output
        ce.save()
        return ce


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ("id", "username", "email", "password")
        # parolayi sadece veriyi yazarken kullanacagiz bu yuzden write_only olmali
        extra_kwargs = {
            "password":{"write_only":True}
        }

    def create(self, validated_data):
        password = validated_data.pop("password")
        user = User.objects.create(**validated_data)
        # parolayi kriptolu bir sekilde kaydetmek icin set_password kullanilmalidir
        user.set_password(password)
        user.save()
        # olusturulan kullanıci icin bir tane de token objesi oluşturuluyor
        Token.objects.create(user=user)
        return user


class TokenSerializer(serializers.Serializer):
    """Token oluşturmak icin username ve password alanlari gereklidir"""
    username = serializers.CharField()
    password = serializers.CharField(style={"input_type":"password"},trim_whitespace=False)

    def validate(self, attrs):
        username = attrs.get("username")
        password = attrs.get("password")
        # verilen username ve password ile yetkilendirme islemi yapilir
        user = authenticate(request=self.context.get("request"),username=username, password=password)
        # kullanıcı authenticate olamazsa dogrulama hatasi uretilir
        if not user:
            msg = "Credentials are not provided correctly..."
            raise serializers.ValidationError(msg, code="authentication")
        # kullanici authenticate olmussa attrs'e kaydedilir
        attrs["user"] = user
        return attrs
- api/views.py düzenleyelim
from rest_framework import views, status
from rest_framework.response import Response
from django.contrib.auth.models import User
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import AllowAny
# internals
from api.serializers import CodeExplainSerializer, UserSerializer, TokenSerializer
from api.models import CodeExplainer


class CodeExplainView(views.APIView):
    serializer_class = CodeExplainSerializer
    # kullanici code-explain endpointi kullanabilmek icin token almalidir
    authentication_classes = [TokenAuthentication]

    def get(self, request, format=None):
        qs = CodeExplainer.objects.all()
        serializer = self.serializer_class(qs, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class UserView(views.APIView):
    serializer_class = UserSerializer
    permission_classes = [AllowAny]

    def post(self, request, format=None):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class TokenView(ObtainAuthToken):
    serializer_class = TokenSerializer
- api/urls.py oluşturulması ve düzenlenmesi
from django.urls import path
# internals
from api.views import UserView, TokenView, CodeExplainView

urlpatterns = [
    path('users/', UserView.as_view(), name='users'),
    path('tokens/', TokenView.as_view(), name='tokens'),
    path('code-explain/', CodeExplainView.as_view(), name='code-explain' )
]
- src/urls.py düzenlenmesi
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('api.urls'))
]

Projenin Çalıştırılması

python manage.py runserver

Endpointlerin Test Edilmesi

curl, postman, thunder client gibi araçlar ile geliştirdiğimiz API'yı test edebiliriz.

  1. "users"

http://127.0.0.1:8000/api/v1/users/ adresine aşağıdaki istek gövdesi(request body) ile POST request gönderelim

{
  "username":"adnan",
  "password":"qwert",
  "email":"[email protected]"
}
- API response
{
  "id": 1,
  "username": "adnan",
  "email": "[email protected]"
}
- 2. "tokens"

Oluşturduğumuz kullanıcının username ve password bilgisi ile token oluşturalım

http://127.0.0.1:8000/api/v1/tokens/ adresine aşağıdaki request body ile POST request gönderelim

{
  "username":"adnan",
  "password":"qwert"
}
- API Response
{
  "token": "f22727755e76e5856cd1d92d1304d7fd75ebf2e9"
}
- 3. "code-explain"

Aldığımız token ile http://127.0.0.1:8000/api/v1/code-explain/ adresine aşağıdaki request body ile POST request gönderelim

{
  "_input":"[i**2 for i in range(1,100) if i%2==0]"
}
- API Response
{
  "id": 1,
  "_input": "[i**2 for i in range(1,100) if i%2==0]",
  "_output": "The code you provided is written in Python.\n\nIt is a list comprehension expression that generates a list of squares of even numbers from 1 to 99.\n\nLet's break it down:\n\n- `[i**2` is the expression that calculates the square of the current number.\n- `for i in range(1,100)` is the loop that iterates over the numbers from 1 to 99.\n- `if i%2==0]` is the condition that filters out only the even numbers.\n\nSo, the code calculates the square of each even number from 1 to 99 and returns a list containing these values."
}
- Örnek 2 Request body
{
  "_input":"fmt.Print('Hello world')"
}
- API Response
{
  "id": 2,
  "_input": "fmt.Print('Hello world')",
  "_output": "The code you provided appears to be written in Go (often referred to as Golang). In this particular example, the code uses the `fmt` package from the Go standard library to print the string \"Hello world\" to the standard output."
}
- Bu yazımızda django rest API ve chatGPT openai API temel olarak nasıl kullanılabilir öğrenmeye çalıştık.

Daha fazla yapay zeka API'ları ile etkileşime geçmek, web uygulamalarına nasıl entegre edileceğini öğrenmek için takipte kalın...