0.0.2
openAI requests for categories and questions
This commit is contained in:
@@ -28,7 +28,10 @@ class BaseModel(models.Model):
|
|||||||
json_data = models.JSONField(verbose_name=_('Дополнительные данные'), default=dict, blank=True)
|
json_data = models.JSONField(verbose_name=_('Дополнительные данные'), default=dict, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
if self.name:
|
||||||
return self.name
|
return self.name
|
||||||
|
else:
|
||||||
|
return str(self.id)
|
||||||
|
|
||||||
def get_node_by_name(self, node_name):
|
def get_node_by_name(self, node_name):
|
||||||
if not self.json_data or not node_name in self.json_data:
|
if not self.json_data or not node_name in self.json_data:
|
||||||
|
|||||||
56
BaseModels/openAI/openAI_funcs.py
Normal file
56
BaseModels/openAI/openAI_funcs.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
|
def send_request(msg):
|
||||||
|
# url = 'https://api.openai.com/v1/chat/completions'
|
||||||
|
# headers = {
|
||||||
|
# 'Content-Type': 'application/json',
|
||||||
|
# 'Authorization': 'Bearer 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'
|
||||||
|
# }
|
||||||
|
# data = {
|
||||||
|
# "model": "gpt-3.5-turbo",
|
||||||
|
# "messages": [{
|
||||||
|
# "role": "user",
|
||||||
|
# "content": msg
|
||||||
|
# }]
|
||||||
|
# }
|
||||||
|
# res = requests.post(url=url, headers=headers, data=data)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import openai
|
||||||
|
openai.api_key = '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'
|
||||||
|
|
||||||
|
res = None
|
||||||
|
|
||||||
|
while not res:
|
||||||
|
|
||||||
|
s = f'send request >>> {msg}'
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
res = openai.ChatCompletion.create(
|
||||||
|
model="gpt-3.5-turbo",
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": msg
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
msg = f'!!! --- OpenAI send_request fail = {str(e)} > sleep 60sec'
|
||||||
|
print(msg)
|
||||||
|
time.sleep(60)
|
||||||
|
# send_request(msg)
|
||||||
|
|
||||||
|
if res and 'OpenAI account' in res['choices'][0]['message']['content']:
|
||||||
|
msg = f"!!! --- OpenAI send_request fail = {str(res['choices'][0]['message']['content'])} > sleep 60sec"
|
||||||
|
print(msg)
|
||||||
|
res = None
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return res
|
||||||
@@ -121,7 +121,7 @@ TIME_ZONE = 'Europe/Minsk'
|
|||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = False
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ from django.conf import settings
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('ckeditor/', include('ckeditor_uploader.urls')),
|
path('ckeditor/', include('ckeditor_uploader.urls')),
|
||||||
|
path('', include('QuestionsApp.urls'))
|
||||||
]
|
]
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
0
GPTgeneratorAPI/__init__.py
Normal file
0
GPTgeneratorAPI/__init__.py
Normal file
3
GPTgeneratorAPI/admin.py
Normal file
3
GPTgeneratorAPI/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
GPTgeneratorAPI/apps.py
Normal file
6
GPTgeneratorAPI/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class GptgeneratorapiConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'GPTgeneratorAPI'
|
||||||
0
GPTgeneratorAPI/migrations/__init__.py
Normal file
0
GPTgeneratorAPI/migrations/__init__.py
Normal file
3
GPTgeneratorAPI/models.py
Normal file
3
GPTgeneratorAPI/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
GPTgeneratorAPI/tests.py
Normal file
3
GPTgeneratorAPI/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
195
GPTgeneratorAPI/views.py
Normal file
195
GPTgeneratorAPI/views.py
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from django.shortcuts import render
|
||||||
|
from BaseModels.openAI.openAI_funcs import send_request
|
||||||
|
|
||||||
|
def get_questions_for_category(category, quest_count, level):
|
||||||
|
# if level == 1:
|
||||||
|
name_level = 'простой'
|
||||||
|
if level == 2:
|
||||||
|
name_level = 'средний'
|
||||||
|
if level == 3:
|
||||||
|
name_level = 'сложный'
|
||||||
|
|
||||||
|
|
||||||
|
# msg = f'создай список (в одну строку, без нумерации) из {quest_count} вопросов уровня сложности "{name_level}" по 3 ответа на каждый из них по теме ' \
|
||||||
|
# f'"{category.name}", ответы выведи в одну строку с разделителем "|", перед правильным ответом поставь символ "~", перед строкой каждого вопроса ставь символ "#"'
|
||||||
|
msg = f'Cоздай список (в одну строку, без нумерации) из {quest_count} вопросов по теме "{category.name}", уровень сложности вопросов - "{name_level}", к каждому вопросу подготовь 2 неверных ответа и 1 верный (без нумерации, с разделителем "|"), перед верным ответом поставь символ "~", перед каждым вопросом поставь символ "#"'
|
||||||
|
# print(msg)
|
||||||
|
res = send_request(msg)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_questions():
|
||||||
|
from QuestionsApp.models import Question, QuestionCategory, Answer
|
||||||
|
|
||||||
|
answers_count = 3
|
||||||
|
request_questions_count = 2
|
||||||
|
|
||||||
|
from django.db.models import Count, F
|
||||||
|
cats = QuestionCategory.objects.filter(enable=True).exclude(parent_category=None).annotate(
|
||||||
|
quest_count=Count('rel_questions_for_category')
|
||||||
|
).order_by('quest_count')
|
||||||
|
for cat in cats:
|
||||||
|
for level in [1, 2, 3]:
|
||||||
|
res = get_questions_for_category(cat, request_questions_count, level)
|
||||||
|
|
||||||
|
data = res['choices'][0]['message']['content']
|
||||||
|
print(data)
|
||||||
|
res_quests = data.split('#')
|
||||||
|
for res_quest in res_quests:
|
||||||
|
if not res_quest:
|
||||||
|
continue
|
||||||
|
|
||||||
|
check_right_answer_count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
res_quest_struct_list = res_quest.split('|')
|
||||||
|
if len(res_quest_struct_list) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
quest_for_add = prepare_phrase(res_quest_struct_list[0])
|
||||||
|
if not quest_for_add:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(quest_for_add)
|
||||||
|
|
||||||
|
quest_dublicate = Question.objects.filter(name=quest_for_add).count()
|
||||||
|
if quest_dublicate:
|
||||||
|
msg = f'! - дубликат вопроса "{quest_for_add}" > пропускаем'
|
||||||
|
print(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
quest_obj = Question.objects.create(
|
||||||
|
name=quest_for_add,
|
||||||
|
category=cat,
|
||||||
|
game_level=level,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer_objs_list = []
|
||||||
|
|
||||||
|
answers_list = res_quest_struct_list[1:]#.split('|')
|
||||||
|
|
||||||
|
for answer in answers_list:
|
||||||
|
if not answer:
|
||||||
|
continue
|
||||||
|
|
||||||
|
right_answer = False
|
||||||
|
|
||||||
|
answer = answer.strip()
|
||||||
|
if answer[0] == '~':
|
||||||
|
right_answer = True
|
||||||
|
check_right_answer_count += 1
|
||||||
|
|
||||||
|
answer_for_add = prepare_phrase(answer)
|
||||||
|
if not answer_for_add:
|
||||||
|
continue
|
||||||
|
|
||||||
|
answer_obj = Answer(
|
||||||
|
name=answer_for_add,
|
||||||
|
right_answer=right_answer,
|
||||||
|
question=quest_obj
|
||||||
|
)
|
||||||
|
answer_objs_list.append(answer_obj)
|
||||||
|
print(f' - {answer_for_add} > {right_answer}')
|
||||||
|
|
||||||
|
if len(answer_objs_list) != answers_count or check_right_answer_count != 1:
|
||||||
|
Question.objects.filter(id=quest_obj.id).delete()
|
||||||
|
msg = f'!!! - неверное количество ответов или правильных ответов'
|
||||||
|
print(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
Answer.objects.bulk_create(answer_objs_list)
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg = f'!!! --- get_questions question {res_quest} > processed ERROR = {str(e)}'
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
# максимум 3 запроса в минуту
|
||||||
|
time.sleep(30)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_sub_categories_for_category(category):
|
||||||
|
msg = f'создай 500 подтематик для тематики {category.name} и выведи с разделителем ^ в одну строку без нумерации'
|
||||||
|
print(msg)
|
||||||
|
res = send_request(msg)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def prepare_phrase(phrase):
|
||||||
|
|
||||||
|
try:
|
||||||
|
name = phrase.replace('\n', '')
|
||||||
|
while name and name[-1] in (',', '.', ':', ';', '-', ' '):
|
||||||
|
name = name[:-1]
|
||||||
|
|
||||||
|
while name and name[0] in (',', '.', ':', ';', '-', ' ', '~'):
|
||||||
|
name = name[1:]
|
||||||
|
|
||||||
|
if len(name) > 3 and name[1] == '.':
|
||||||
|
name = name[2:]
|
||||||
|
|
||||||
|
if len(name) > 3 and name[1] == ' ':
|
||||||
|
try:
|
||||||
|
i = int(name[0])
|
||||||
|
name = name[2:]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
name = name[2:]
|
||||||
|
|
||||||
|
# убираем маркировку подпунктов
|
||||||
|
if name and name[1] == ')':
|
||||||
|
name = name[2:]
|
||||||
|
|
||||||
|
name = name.strip()
|
||||||
|
except Exception as e:
|
||||||
|
msg = f'prepare_phrase "{phrase}" error = {str(e)}'
|
||||||
|
print(msg)
|
||||||
|
name = ''
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def get_subcategories():
|
||||||
|
from QuestionsApp.models import QuestionCategory
|
||||||
|
categories = QuestionCategory.objects.all()
|
||||||
|
|
||||||
|
cats_names_list = list(categories.values_list('name', flat=True))
|
||||||
|
|
||||||
|
|
||||||
|
for cat in categories:
|
||||||
|
sub_cats_objs = []
|
||||||
|
|
||||||
|
res = get_sub_categories_for_category(cat)
|
||||||
|
|
||||||
|
data = res['choices'][0]['message']['content']
|
||||||
|
# data = data.replace('-', '')
|
||||||
|
|
||||||
|
sub_cats_list = data.split('^')
|
||||||
|
for sub_cat in sub_cats_list:
|
||||||
|
name = prepare_phrase(sub_cat)
|
||||||
|
if not name:
|
||||||
|
msg = f'! - {sub_cat} > проблема в строке, пропускаем'
|
||||||
|
print(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if name in cats_names_list:
|
||||||
|
msg = f'! - {name} > пропускаем, дубликат'
|
||||||
|
print(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(name)
|
||||||
|
sub_cat_obj = QuestionCategory(
|
||||||
|
name=name,
|
||||||
|
parent_category=cat
|
||||||
|
)
|
||||||
|
sub_cats_objs.append(sub_cat_obj)
|
||||||
|
cats_names_list.append(name)
|
||||||
|
|
||||||
|
QuestionCategory.objects.bulk_create(sub_cats_objs)
|
||||||
|
# cat.parsed = True
|
||||||
|
|
||||||
|
return True
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from BaseModels.admin_utils import Admin_BaseIconModel
|
from BaseModels.admin_utils import *
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
class Admin_Question(Admin_BaseIconModel):
|
class Admin_QuestionCategory(Admin_BaseIconModel):
|
||||||
pass
|
pass
|
||||||
|
admin.site.register(QuestionCategory, Admin_QuestionCategory)
|
||||||
|
|
||||||
|
class Admin_AnswerTabularInline(Admin_BaseIconTabularModel):
|
||||||
|
fields = ['name', 'right_answer', 'order']
|
||||||
|
model = Answer
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
class Admin_Question(Admin_BaseIconModel):
|
||||||
|
inlines = [Admin_AnswerTabularInline]
|
||||||
admin.site.register(Question, Admin_Question)
|
admin.site.register(Question, Admin_Question)
|
||||||
|
|
||||||
class Admin_Answer(Admin_BaseIconModel):
|
class Admin_Answer(Admin_BaseIconModel):
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.2.1 on 2023-05-19 12:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('QuestionsApp', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionCategory',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')),
|
||||||
|
('name_plural', models.TextField(blank=True, null=True, verbose_name='Название (множественное число)')),
|
||||||
|
('order', models.IntegerField(blank=True, null=True, verbose_name='Очередность отображения')),
|
||||||
|
('createDT', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время создания')),
|
||||||
|
('modifiedDT', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего изменения')),
|
||||||
|
('enable', models.BooleanField(db_index=True, default=True, verbose_name='Включено')),
|
||||||
|
('json_data', models.JSONField(blank=True, default=dict, verbose_name='Дополнительные данные')),
|
||||||
|
('parsed', models.BooleanField(default=False, verbose_name='Использован')),
|
||||||
|
('parent_category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='categories_for_parentCategory', to='QuestionsApp.questioncategory', verbose_name='Родительская категория')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Категория вопроса',
|
||||||
|
'verbose_name_plural': 'Категории вопросов',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='question',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rel_questions_for_category', to='QuestionsApp.questioncategory', verbose_name='Категория'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.1 on 2023-05-19 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('QuestionsApp', '0002_questioncategory_question_category'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='questioncategory',
|
||||||
|
name='parent_category',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='categories_for_parentCategory', to='QuestionsApp.questioncategory', verbose_name='Родительская категория'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -2,8 +2,33 @@ from django.db import models
|
|||||||
from BaseModels.base_models import BaseModel
|
from BaseModels.base_models import BaseModel
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
class QuestionCategory(BaseModel):
|
||||||
|
parent_category = models.ForeignKey(
|
||||||
|
'QuestionCategory', verbose_name=_('Родительская категория'), related_name='categories_for_parentCategory',
|
||||||
|
on_delete=models.CASCADE, null=True, blank=True
|
||||||
|
)
|
||||||
|
parsed = models.BooleanField(verbose_name='Использован', default=False)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.name:
|
||||||
|
return f'{self.name}'
|
||||||
|
else:
|
||||||
|
return str(self.id)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Категория вопроса')
|
||||||
|
verbose_name_plural = _('Категории вопросов')
|
||||||
|
|
||||||
|
|
||||||
class Question(BaseModel):
|
class Question(BaseModel):
|
||||||
|
|
||||||
|
category = models.ForeignKey(
|
||||||
|
QuestionCategory, verbose_name='Категория', related_name='rel_questions_for_category',
|
||||||
|
on_delete=models.SET_NULL, null=True
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
game_level = models.IntegerField(verbose_name=_('Уровень игры'), default=1)
|
game_level = models.IntegerField(verbose_name=_('Уровень игры'), default=1)
|
||||||
time_for_answer = models.IntegerField(verbose_name=_('Время на ответ (сек)'), default=7)
|
time_for_answer = models.IntegerField(verbose_name=_('Время на ответ (сек)'), default=7)
|
||||||
used_count = models.IntegerField(verbose_name=_('Количество использования'), default=0)
|
used_count = models.IntegerField(verbose_name=_('Количество использования'), default=0)
|
||||||
|
|||||||
7
QuestionsApp/urls.py
Normal file
7
QuestionsApp/urls.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('test_code', test_code, name='test_code')
|
||||||
|
]
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
# Create your views here.
|
def test_code(request):
|
||||||
|
from GPTgeneratorAPI.views import get_subcategories, get_questions
|
||||||
|
# res = get_subcategories()
|
||||||
|
res = get_questions()
|
||||||
|
|
||||||
|
return HttpResponse(str(res))
|
||||||
@@ -2,3 +2,5 @@ Django==4.2.1
|
|||||||
django-ckeditor==6.5.1
|
django-ckeditor==6.5.1
|
||||||
django-modeltranslation==0.18.9
|
django-modeltranslation==0.18.9
|
||||||
psycopg2-binary==2.9.6
|
psycopg2-binary==2.9.6
|
||||||
|
openai
|
||||||
|
requests
|
||||||
Reference in New Issue
Block a user