update openai, added qr and more

This commit is contained in:
Alexander Karpov 2023-08-26 14:10:10 +03:00
parent bc33ac8bad
commit 367ef3be53
9 changed files with 162 additions and 71 deletions

View File

@ -16,10 +16,11 @@
"0.0.0.0", "0.0.0.0",
"127.0.0.1", "127.0.0.1",
"192.168.83.181", "192.168.83.181",
"192.168.22.4",
"ed68-77-234-219-9.ngrok-free.app", "ed68-77-234-219-9.ngrok-free.app",
] ]
CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_ALLOW_ALL = True
CSRF_TRUSTED_ORIGINS = ["https://*.ngrok-free.app"] CSRF_TRUSTED_ORIGINS = ["https://*.ngrok-free.app", "http://192.168.83.181:8000"]
# WhiteNoise # WhiteNoise
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,5 @@
import datetime import datetime
import re
from ast import literal_eval from ast import literal_eval
import openai import openai
@ -6,6 +7,8 @@
KEY = settings.OPENAI_KEY KEY = settings.OPENAI_KEY
regex = r"({(\n.+)+\n})"
description = """🍀 Что такое Pitch-Deck? Pitch-Deck представляет собой презентацию-тизер проекта/компании для description = """🍀 Что такое Pitch-Deck? Pitch-Deck представляет собой презентацию-тизер проекта/компании для
инвесторов, партнеров, журналистов и других заинтересованных лиц. Цель презентации - привлечение дополнительного инвесторов, партнеров, журналистов и других заинтересованных лиц. Цель презентации - привлечение дополнительного
финансирования (инвестиций). Почему это проблема? финансирования (инвестиций). Почему это проблема?
@ -29,7 +32,7 @@
создание Pitch-Deck.""" создание Pitch-Deck."""
names_prompt = """ names_prompt = """
По тексту ответь или предположи ответ на вопросы в следющем формате: По тексту ответь или предположи ответ на вопросы в следующем формате:
{ {
"names": "Назови 5 имен проекта с данным описанием через запятую" "names": "Назови 5 имен проекта с данным описанием через запятую"
} }
@ -37,7 +40,7 @@
prompts = [ prompts = [
""" """
По тексту ответь или предположи ответ на вопросы в следющем формате: По тексту ответь или предположи ответ на вопросы в следующем формате:
{ {
'users': 'Кто будет пользоваться продуктом', 'users': 'Кто будет пользоваться продуктом',
'problems': 'Какие проблемы решает продукт', 'problems': 'Какие проблемы решает продукт',
@ -47,24 +50,23 @@
} }
""", """,
""" """
По тексту ответь или предположи ответ на вопросы в следющем формате: По тексту ответь или предположи ответ на вопросы в следующем формате:
{ {
'awards': 'Когда проблема будет решена, какова будет ценность для ваших пользователей', 'awards': 'Ценность продукта для пользователей',
'money': 'На чем проект зарабатывает? сколько и за что ему платят клиенты', 'money': 'На чем проект зарабатывает? сколько и за что ему платят клиенты',
'aims': Напиши 3 цели: на месяц, на полгода и год, формат: {'1': цель на месяц, '2': цель на полгода, '3': цель на год}, 'aims': Напиши 3 цели: на месяц, на полгода и год, формат: {'1': цель на месяц, '2': цель на полгода, '3': цель на год},
'investments_sold': 'На что потратить инвестиции под проект', 'investments_sold': 'На что потратить инвестиции под проект',
'financial_indicators': 'Напиши финансовые показатели проекта' 'financial_indicators': 'Напиши финансовые показатели проекта'
} }
""", """,
""" """По тексту ответь или предположи ответ на вопросы в следующем формате: { 'achieve': 'Чего добьется команда после
По тексту ответь или предположи ответ на вопросы в следющем формате: освоения инвестиций', 'competitors_strength': 'Сильные стороны конкурентов', 'competitors_low': 'Слабые стороны
{ конкурентов', 'advantages': 'Какие могут быть преимущества над конкурентами', 'category': "На каком рынке
находится этот проект? Выбери из вариантов: 'Business Software', 'IndustrialTech', 'E-commerce', 'Advertising &
'achieve': 'Чего добьется команда после освоения инвестиций', Marketing', 'Hardware', 'RetailTech', 'ConstructionTech', 'Web3', 'EdTech', 'Business Intelligence',
'competitors_strength': 'Сильные стороны конкурентов', 'Cybersecurity', 'HrTech', 'Telecom & Communication', 'Media & Entertainment', 'FinTech', 'MedTech', 'Transport &
'competitors_low': 'Слабые стороны конкурентов', Logistics', 'Gaming', 'FoodTech', 'AI', 'WorkTech', 'Consumer Goods & Services', 'Aero & SpaceTech',
'advantages': 'Какие могут быть преимущества над конкурентами' 'Legal & RegTech', 'Travel', 'PropTech', 'Energy', 'GreenTech'" } ,
}
""", """,
] ]
@ -100,7 +102,12 @@ def create_hints(description: str, stage: int):
model="gpt-3.5-turbo", model="gpt-3.5-turbo",
messages=[{"role": "user", "content": description + "\n" + prompts[stage]}], messages=[{"role": "user", "content": description + "\n" + prompts[stage]}],
) )
content = literal_eval(chat_completion.choices[0].message.content) str_content = chat_completion.choices[0].message.content
print(str_content)
filtered_content = list(re.finditer(regex, str_content, re.MULTILINE))[-1].group()
if not len(filtered_content):
raise ValueError(f"answer doesnt pass validation, {filtered_content}")
content = literal_eval(filtered_content)
for assertion_statement in assertions[stage]: for assertion_statement in assertions[stage]:
assert assertion_statement(content) assert assertion_statement(content)

View File

@ -203,6 +203,22 @@ def validate(self, data):
raise serializers.ValidationError("Incorrect type") raise serializers.ValidationError("Incorrect type")
if any([type(x) is not str for x in answer.values()]): if any([type(x) is not str for x in answer.values()]):
raise serializers.ValidationError("Incorrect type") raise serializers.ValidationError("Incorrect type")
case "multiple_date_description":
if type(answer) is not dict:
raise serializers.ValidationError("Incorrect type")
if not (params["min"] <= len(answer) <= params["max"]):
raise serializers.ValidationError(
"number of dates is too small or too large"
)
for date in answer.keys():
try:
parse(date)
except ValueError:
raise serializers.ValidationError("Incorrect date type")
for val in answer.values():
if type(val) is not str:
raise serializers.ValidationError("Incorrect type")
data["question_id"] = question.id data["question_id"] = question.id
data["deck_id"] = deck.id data["deck_id"] = deck.id

View File

@ -32,6 +32,10 @@ class QuestionType(models.TextChoices):
select = "select" select = "select"
link = "link" link = "link"
date = "date" date = "date"
multiple_date_description = (
"multiple_date_description",
"multiple date description",
)
photo = "photo" photo = "photo"
multiple_photo = "multiple_photo", "multiple photo" multiple_photo = "multiple_photo", "multiple photo"
photo_description = "photo_description", "photo description" photo_description = "photo_description", "photo description"

View File

@ -1,21 +1,40 @@
from django.db.models.signals import post_save from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver from django.dispatch import receiver
from pitch_deck_generator.decks.models import PitchDeck, QuestionAnswer from pitch_deck_generator.decks.models import PitchDeck, QuestionAnswer
from pitch_deck_generator.decks.tasks import ( from pitch_deck_generator.decks.tasks import (
generate_numeric_values, generate_numeric_values,
qenerate_answer_qr,
run_pitch_deck_calculation, run_pitch_deck_calculation,
save_answer_to_deck,
) )
@receiver(post_save, sender=PitchDeck) @receiver(post_save, sender=PitchDeck)
def tag_create(sender, instance: PitchDeck, created, **kwargs): def pitch_deck_create(sender, instance: PitchDeck, created, **kwargs):
if created: if created:
run_pitch_deck_calculation.apply_async(kwargs={"pk": instance.pk}) run_pitch_deck_calculation.apply_async(kwargs={"pk": instance.pk}, delay=1)
@receiver(post_save, sender=QuestionAnswer) @receiver(post_save, sender=QuestionAnswer)
def question_numeric_run(sender, instance: QuestionAnswer, created, **kwargs): def question_answer_create(sender, instance: QuestionAnswer, created, **kwargs):
if created: if created:
if instance.question.inner_tag == "category": if instance.question.inner_tag == "category":
generate_numeric_values.apply_async(kwargs={"pk": instance.deck.pk}) generate_numeric_values.apply_async(
kwargs={"pk": instance.deck.pk}, countdown=1
)
elif instance.question.inner_tag in ["finance_model"]:
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=1)
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=5)
@receiver(pre_save, sender=QuestionAnswer)
def question_answer_update(sender, instance: QuestionAnswer, created, **kwargs):
if instance.id:
if instance.question.inner_tag == "category":
generate_numeric_values.apply_async(
kwargs={"pk": instance.deck.pk}, countdown=1
)
elif instance.question.inner_tag in ["finance_model"]:
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=1)
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=5)

View File

@ -1,14 +1,21 @@
import tempfile
import qrcode
import requests import requests
from celery import shared_task from celery import shared_task
from django.core.files import File
from ml.openai_handle import create_hints, create_name_hint from ml.openai_handle import create_hints, create_name_hint
from pitch_deck_generator.decks.models import ( from pitch_deck_generator.decks.models import (
PitchDeck, PitchDeck,
Question, Question,
QuestionAnswer, QuestionAnswer,
QuestionAnswerPhoto,
QuestionDeckHint, QuestionDeckHint,
) )
ML_HOST = "https://short-peaches-speak.loca.lt/"
data_types = { data_types = {
"names": ("text", 1), "names": ("text", 1),
"type": ("select", 13), "type": ("select", 13),
@ -25,7 +32,7 @@
"money": ("text", 11), "money": ("text", 11),
"financial_indicators": ("text", 33), "financial_indicators": ("text", 33),
"users_metrics": ("multiple_range", 12), "users_metrics": ("multiple_range", 12),
"aims": ("text", 15), "aims": ("multiple_date_description", 15),
"money_recieved": ("number", 16), "money_recieved": ("number", 16),
"past_investors": ("text", 17), "past_investors": ("text", 17),
"how_much_investments": ("range", 18), "how_much_investments": ("range", 18),
@ -51,7 +58,7 @@ def run_pitch_deck_calculation(pk: int):
generate_pitch_deck_name.apply_async(kwargs={"pk": pk}) generate_pitch_deck_name.apply_async(kwargs={"pk": pk})
generate_known_values.apply_async(kwargs={"pk": pk}) generate_known_values.apply_async(kwargs={"pk": pk})
for i in range(3): for i in range(3):
generate_batch_hints.apply_async(kwargs={"pk": pk, "num": i}) generate_batch_hints.apply_async(kwargs={"pk": pk, "num": i}, delay=1)
@shared_task @shared_task
@ -69,47 +76,8 @@ def generate_pitch_deck_name(pk: int):
@shared_task @shared_task
def generate_known_values(pk: int): def generate_known_values(pk: int):
pitch_deck = PitchDeck.objects.get(pk=pk) pitch_deck = PitchDeck.objects.get(pk=pk)
_, question_id = data_types["category"]
QuestionDeckHint.objects.create(
question_id=question_id,
deck=pitch_deck,
hint={
"type": "select",
"value": [
"Business Software",
"IndustrialTech",
"E-commerce",
"Advertising & Marketing",
"Hardware",
"RetailTech",
"ConstructionTech",
"Web3",
"EdTech",
"Business Intelligence",
"Cybersecurity",
"HrTech",
"Telecom & Communication",
"Media & Entertainment",
"FinTech",
"MedTech",
"Transport & Logistics",
"Gaming",
"FoodTech",
"AI",
"WorkTech",
"Consumer Goods & Services",
"Aero & SpaceTech",
"Legal & RegTech",
"Travel",
"PropTech",
"Energy",
"GreenTech",
],
},
)
req = requests.post( req = requests.post(
"https://rare-needles-lead.loca.lt/search", ML_HOST + "search",
json={"body": pitch_deck.description}, json={"body": pitch_deck.description},
) )
data = req.json() data = req.json()
@ -122,9 +90,23 @@ def generate_known_values(pk: int):
@shared_task @shared_task
def generate_batch_hints(pk: int, num: int): def generate_batch_hints(pk: int, num: int):
pitch_deck = PitchDeck.objects.get(pk=pk) pitch_deck = PitchDeck.objects.get(pk=pk)
try:
data = create_hints(pitch_deck.description, num)
except Exception as e:
print(e)
data = create_hints(pitch_deck.description, num) data = create_hints(pitch_deck.description, num)
for el in data: for el in data:
question_type, question_id = data_types[el["type"]] question_type, question_id = data_types[el["type"]]
if el["type"] == "aims":
dates = {}
for e in el["value"]:
dates[e["date"]] = e["aim"]
QuestionDeckHint.objects.create(
question_id=question_id,
deck=pitch_deck,
hint={"type": question_type, "value": dates},
)
else:
QuestionDeckHint.objects.create( QuestionDeckHint.objects.create(
question_id=question_id, question_id=question_id,
deck=pitch_deck, deck=pitch_deck,
@ -144,7 +126,7 @@ def generate_numeric_values(pk: int):
category = q.first().answer category = q.first().answer
type = q2.first().answer type = q2.first().answer
req = requests.post( req = requests.post(
"https://rare-needles-lead.loca.lt/numeric", ML_HOST + "numeric",
json={ json={
"description": pitch_deck.description, "description": pitch_deck.description,
"category": category, "category": category,
@ -159,3 +141,28 @@ def generate_numeric_values(pk: int):
deck=pitch_deck, deck=pitch_deck,
hint={"type": question_type, "value": el["value"]}, hint={"type": question_type, "value": el["value"]},
) )
@shared_task
def save_answer_to_deck(pk: int):
qa = QuestionAnswer.objects.get(pk=pk)
question = qa.question
deck = qa.deck
deck.questions[question.inner_tag] = {
"answer": qa.answer,
"photos": [x.file.url for x in qa.photos.all()],
}
deck.save()
@shared_task
def qenerate_answer_qr(pk: int):
qa = QuestionAnswer.objects.get(pk=pk)
link = qa.answer
img = qrcode.make(link)
with tempfile.NamedTemporaryFile() as tmp:
img.save(tmp.name)
QuestionAnswerPhoto.objects.create(
answer=qa,
file=File(tmp, name="qr.png"),
)

38
poetry.lock generated
View File

@ -2281,6 +2281,18 @@ files = [
[package.dependencies] [package.dependencies]
pylint = ">=1.7" pylint = ">=1.7"
[[package]]
name = "pypng"
version = "0.20220715.0"
description = "Pure Python library for saving and loading PNG images"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"},
{file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
]
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "7.4.0" version = "7.4.0"
@ -2455,6 +2467,30 @@ files = [
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
] ]
[[package]]
name = "qrcode"
version = "7.4.2"
description = "QR Code image generator"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"},
{file = "qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
pypng = "*"
typing-extensions = "*"
[package.extras]
all = ["pillow (>=9.1.0)", "pytest", "pytest-cov", "tox", "zest.releaser[recommended]"]
dev = ["pytest", "pytest-cov", "tox"]
maintainer = ["zest.releaser[recommended]"]
pil = ["pillow (>=9.1.0)"]
test = ["coverage", "pytest"]
[[package]] [[package]]
name = "redis" name = "redis"
version = "4.6.0" version = "4.6.0"
@ -3298,4 +3334,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "31ce390d9b50a16455803f012bd6f7eca984fbec0d0e60404edaea07b5523792" content-hash = "e22fcc25641133d1b08cd9bb014e157933077e7a6bd09ce8e4186c844777abf9"

View File

@ -49,6 +49,7 @@ pytest-django = "^4.5.2"
sentry-sdk = "^1.12.0" sentry-sdk = "^1.12.0"
openai = "^0.27.9" openai = "^0.27.9"
isort = "5.11.5" isort = "5.11.5"
qrcode = "^7.4.2"
[build-system] [build-system]