mirror of
https://github.com/spbleadersofdigtal/backend.git
synced 2024-11-23 11:43:43 +03:00
updated openai, added pdt to pptx convert
This commit is contained in:
parent
983f122a81
commit
1c58a20508
|
@ -1,4 +1,4 @@
|
||||||
exclude: "^docs/|/migrations/"
|
exclude: "^docs/|/migrations/|^ml/"
|
||||||
default_stages: [commit]
|
default_stages: [commit]
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
|
|
|
@ -9,27 +9,29 @@
|
||||||
|
|
||||||
regex = r"({(\n.+)+\n})"
|
regex = r"({(\n.+)+\n})"
|
||||||
|
|
||||||
description = """🍀 Что такое Pitch-Deck? Pitch-Deck представляет собой презентацию-тизер проекта/компании для
|
description = """
|
||||||
инвесторов, партнеров, журналистов и других заинтересованных лиц. Цель презентации - привлечение дополнительного
|
🍀 Кейсодержатель:
|
||||||
финансирования (инвестиций). Почему это проблема?
|
ООО «Акселератор Возможностей» (https://ac-vo.ru/) при ИНТЦ МГУ «Воробьевы горы».
|
||||||
|
Организация технологических и инвестиционных мероприятий, курирование инновационной деятельности внутри ИНТЦ МГУ «Воробьевы горы»
|
||||||
|
|
||||||
🍀 Проблема #1. Недостаток средств: Для многих стартапов ограниченные финансы создают преграду при разработке
|
Раскроем небольшую тайну венчура — для привлечения денежных средств и защиты своего проекта, стартапу нужен Pitch-Deck.
|
||||||
качественного Pitch Deck. Отсутствие достаточных средств для найма профессиональных консультантов, дизайнеров и
|
|
||||||
копирайтеров, а также для проведения исследований рынка, может привести к созданию менее привлекательной и
|
|
||||||
малоинформативной презентации, что затрудняет привлечение инвестиций.
|
|
||||||
|
|
||||||
🍀 Проблема #2. Недостаток экспертизы: Проблемой для стартапов является недостаток экспертизы для проведения
|
🍀 Что такое Pitch-Deck?
|
||||||
необходимых исследований и корректного отражения их результатов в Pitch Deck. Не всегда у стартапов есть нужные
|
Pitch-Deck представляет собой презентацию-тизер проекта/компании для инвесторов, партнеров, журналистов и других заинтересованных лиц. Цель презентации - привлечение дополнительного финансирования (инвестиций).
|
||||||
знания в области маркетинга, финансов и анализа рынка, что затрудняет создание убедительной и информативной
|
Почему это проблема?
|
||||||
презентации для привлечения инвестиций.
|
|
||||||
|
|
||||||
🍀 Проблема #3. Недостаток времени Молодым компаниям для привлечения инвестиций требуется подготовить целый пакет
|
🍀 Проблема #1. Недостаток средств:
|
||||||
документов, одним из которых является Pitch Deck. Особенностью стартапов является сравнительного молодая и небольшая
|
Для многих стартапов ограниченные финансы создают преграду при разработке качественного Pitch Deck. Отсутствие достаточных средств для найма профессиональных консультантов, дизайнеров и копирайтеров, а также для проведения исследований рынка, может привести к созданию менее привлекательной и малоинформативной презентации, что затрудняет привлечение инвестиций.
|
||||||
команда, у которой чисто физически не хватает времени на разработку инвестиционных материалов, ведь они полностью
|
|
||||||
погружены в процесс разработки и улучшения продукта или сервиса.
|
|
||||||
|
|
||||||
🍀 ИДЕЯ: Основная идея кейса заключается в создании вспомогательного инструмента на основе ИИ, заточенного под
|
🍀 Проблема #2. Недостаток экспертизы:
|
||||||
создание Pitch-Deck."""
|
Проблемой для стартапов является недостаток экспертизы для проведения необходимых исследований и корректного отражения их результатов в Pitch Deck. Не всегда у стартапов есть нужные знания в области маркетинга, финансов и анализа рынка, что затрудняет создание убедительной и информативной презентации для привлечения инвестиций.
|
||||||
|
|
||||||
|
🍀 Проблема #3. Недостаток времени
|
||||||
|
Молодым компаниям для привлечения инвестиций требуется подготовить целый пакет документов, одним из которых является Pitch Deck. Особенностью стартапов является сравнительного молодая и небольшая команда, у которой чисто физически не хватает времени на разработку инвестиционных материалов, ведь они полностью погружены в процесс разработки и улучшения продукта или сервиса.
|
||||||
|
|
||||||
|
🍀 ИДЕЯ:
|
||||||
|
Основная идея кейса заключается в создании вспомогательного инструмента на основе ИИ, заточенного под создание Pitch-Deck.
|
||||||
|
"""
|
||||||
|
|
||||||
names_prompt = """
|
names_prompt = """
|
||||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||||
|
@ -42,31 +44,32 @@
|
||||||
"""
|
"""
|
||||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||||
{
|
{
|
||||||
'users': 'Кто будет пользоваться продуктом',
|
'users': 'Кто будет пользоваться продуктом?',
|
||||||
'problems': 'Какие проблемы решает продукт',
|
'problems': 'Какие проблемы решает продукт?',
|
||||||
'actuality': 'Продолжите предложение: Актуальность проблемы подтверждается тем фактом, что...',
|
'actuality': 'Каким фактом обуславливается актуальность проблемы?',
|
||||||
'solve': 'Как решаем эти проблемы',
|
'solve': 'Как решаем эти проблемы?',
|
||||||
'works': 'Как работает решение',
|
'works': 'Как работает решение?',
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"""
|
"""
|
||||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||||
{
|
{
|
||||||
'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'" } ,
|
'category': "На каком рынке находится этот проект? Выбери из вариантов: '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'"
|
||||||
|
}
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -103,9 +106,13 @@ def create_hints(description: str, stage: int):
|
||||||
messages=[{"role": "user", "content": description + "\n" + prompts[stage]}],
|
messages=[{"role": "user", "content": description + "\n" + prompts[stage]}],
|
||||||
)
|
)
|
||||||
str_content = chat_completion.choices[0].message.content
|
str_content = chat_completion.choices[0].message.content
|
||||||
print(str_content)
|
try:
|
||||||
filtered_content = list(re.finditer(regex, str_content, re.MULTILINE))[-1].group()
|
filtered_content = list(re.finditer(regex, str_content, re.MULTILINE))[
|
||||||
if not len(filtered_content):
|
-1
|
||||||
|
].group()
|
||||||
|
if not len(filtered_content):
|
||||||
|
raise ValueError(f"answer doesnt pass validation, {filtered_content}")
|
||||||
|
except:
|
||||||
raise ValueError(f"answer doesnt pass validation, {filtered_content}")
|
raise ValueError(f"answer doesnt pass validation, {filtered_content}")
|
||||||
content = literal_eval(filtered_content)
|
content = literal_eval(filtered_content)
|
||||||
for assertion_statement in assertions[stage]:
|
for assertion_statement in assertions[stage]:
|
||||||
|
@ -147,7 +154,7 @@ def create_name_hint(description: str):
|
||||||
answer = literal_eval(chat_completion.choices[0].message.content)["names"].split(
|
answer = literal_eval(chat_completion.choices[0].message.content)["names"].split(
|
||||||
", "
|
", "
|
||||||
)
|
)
|
||||||
assert len(answer) == 5
|
print(answer)
|
||||||
return {"type": "names", "value": answer}
|
return {"type": "names", "value": answer}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
from rest_framework.generics import get_object_or_404
|
from rest_framework.generics import get_object_or_404
|
||||||
|
|
||||||
from pitch_deck_generator.decks.models import (
|
from pitch_deck_generator.decks.models import (
|
||||||
|
PdfToPPTXStorage,
|
||||||
PitchDeck,
|
PitchDeck,
|
||||||
Question,
|
Question,
|
||||||
QuestionAnswer,
|
QuestionAnswer,
|
||||||
|
@ -40,11 +41,17 @@ class HintSerializer(serializers.Serializer):
|
||||||
class PresentationAnswerSerializer(serializers.Serializer):
|
class PresentationAnswerSerializer(serializers.Serializer):
|
||||||
slug = serializers.CharField()
|
slug = serializers.CharField()
|
||||||
answer = serializers.JSONField()
|
answer = serializers.JSONField()
|
||||||
|
photos = serializers.ListSerializer(child=serializers.ImageField())
|
||||||
|
|
||||||
|
|
||||||
|
class PitchDeckSlidePresentationSerializer(serializers.Serializer):
|
||||||
|
slide = serializers.IntegerField()
|
||||||
|
data = PresentationAnswerSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
class PitchDeckPresentationSerializer(serializers.Serializer):
|
class PitchDeckPresentationSerializer(serializers.Serializer):
|
||||||
slide = serializers.IntegerField()
|
deck = BasePitchDeckSerializer()
|
||||||
data = PresentationAnswerSerializer(many=True)
|
slide = PitchDeckSlidePresentationSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
class QuestionSerializer(serializers.ModelSerializer):
|
class QuestionSerializer(serializers.ModelSerializer):
|
||||||
|
@ -100,7 +107,7 @@ class Meta:
|
||||||
}
|
}
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
answer = data["answer"]
|
answer = data["answer"] if "answer" in data else None
|
||||||
question = get_object_or_404(
|
question = get_object_or_404(
|
||||||
Question, id=self.context["view"].kwargs["question_id"]
|
Question, id=self.context["view"].kwargs["question_id"]
|
||||||
)
|
)
|
||||||
|
@ -168,7 +175,7 @@ def validate(self, data):
|
||||||
if answer:
|
if answer:
|
||||||
raise serializers.ValidationError("Answer should be blank")
|
raise serializers.ValidationError("Answer should be blank")
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
if isinstance(value, InMemoryUploadedFile):
|
if isinstance(value, (TemporaryUploadedFile, InMemoryUploadedFile)):
|
||||||
if "_" not in key:
|
if "_" not in key:
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
"You should use file_num for file keys"
|
"You should use file_num for file keys"
|
||||||
|
@ -198,7 +205,7 @@ def validate(self, data):
|
||||||
len_f = 0
|
len_f = 0
|
||||||
|
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
if isinstance(value, TemporaryUploadedFile):
|
if isinstance(value, (TemporaryUploadedFile, InMemoryUploadedFile)):
|
||||||
if "_" not in key:
|
if "_" not in key:
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
"You should use file_num for file keys"
|
"You should use file_num for file keys"
|
||||||
|
@ -247,19 +254,27 @@ def create(self, validated_data):
|
||||||
q = QuestionAnswer.objects.get_or_create(
|
q = QuestionAnswer.objects.get_or_create(
|
||||||
deck_id=validated_data["deck_id"], question_id=validated_data["question_id"]
|
deck_id=validated_data["deck_id"], question_id=validated_data["question_id"]
|
||||||
)[0]
|
)[0]
|
||||||
q.answer = validated_data["answer"]
|
q.answer = validated_data["answer"] if "answer" in validated_data else {}
|
||||||
q.save()
|
q.save()
|
||||||
|
|
||||||
s = [
|
s = [
|
||||||
key
|
key
|
||||||
for key, val in validated_data.items()
|
for key, val in validated_data.items()
|
||||||
if isinstance(val, TemporaryUploadedFile) and key != "file"
|
if isinstance(val, (TemporaryUploadedFile, InMemoryUploadedFile))
|
||||||
|
and key != "file"
|
||||||
]
|
]
|
||||||
if "file" in validated_data:
|
if "file" in validated_data:
|
||||||
QuestionAnswerPhoto.objects.create(answer=q, file=validated_data["file"])
|
QuestionAnswerPhoto.objects.create(answer=q, file=validated_data["file"])
|
||||||
elif s:
|
if s:
|
||||||
s.sort(key=lambda x: int(x.split("_")[1]))
|
s.sort(key=lambda x: int(x.split("_")[1]))
|
||||||
for key in s:
|
for key in s:
|
||||||
QuestionAnswerPhoto.objects.create(answer=q, file=validated_data[key])
|
QuestionAnswerPhoto.objects.create(answer=q, file=validated_data[key])
|
||||||
|
|
||||||
return q
|
return q
|
||||||
|
|
||||||
|
|
||||||
|
class PdfToPPTXSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = PdfToPPTXStorage
|
||||||
|
fields = ["pdf", "pptx"]
|
||||||
|
extra_kwargs = {"pptx": {"read_only": True}}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from pitch_deck_generator.decks.api.views import (
|
from pitch_deck_generator.decks.api.views import (
|
||||||
|
ConvertPdfToPPTXApiView,
|
||||||
CreateQuestionAnswerApiView,
|
CreateQuestionAnswerApiView,
|
||||||
GetDeckPresentationDataApiView,
|
GetDeckPresentationDataApiView,
|
||||||
GetDeckQuestionApiView,
|
GetDeckQuestionApiView,
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", ListDecksApiView.as_view()),
|
path("", ListDecksApiView.as_view()),
|
||||||
path("<int:id>", RetrievePitchApiView.as_view()),
|
path("<int:id>", RetrievePitchApiView.as_view()),
|
||||||
|
path("pdf-to-pptx", ConvertPdfToPPTXApiView.as_view()),
|
||||||
path(
|
path(
|
||||||
"question/<int:deck_id>/presentation", GetDeckPresentationDataApiView.as_view()
|
"question/<int:deck_id>/presentation", GetDeckPresentationDataApiView.as_view()
|
||||||
),
|
),
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
AnswerSerializer,
|
AnswerSerializer,
|
||||||
BasePitchDeckSerializer,
|
BasePitchDeckSerializer,
|
||||||
HintSerializer,
|
HintSerializer,
|
||||||
|
PdfToPPTXSerializer,
|
||||||
PitchDeckPresentationSerializer,
|
PitchDeckPresentationSerializer,
|
||||||
PitchDeckSerializer,
|
PitchDeckSerializer,
|
||||||
QuestionSerializer,
|
QuestionSerializer,
|
||||||
|
@ -74,6 +75,7 @@ def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
class GetDeckPresentationDataApiView(generics.GenericAPIView):
|
class GetDeckPresentationDataApiView(generics.GenericAPIView):
|
||||||
|
queryset = PitchDeck.objects.none()
|
||||||
serializer_class = PitchDeckPresentationSerializer
|
serializer_class = PitchDeckPresentationSerializer
|
||||||
|
|
||||||
structure = {
|
structure = {
|
||||||
|
@ -84,7 +86,7 @@ class GetDeckPresentationDataApiView(generics.GenericAPIView):
|
||||||
5: ["market_values", "users"],
|
5: ["market_values", "users"],
|
||||||
6: ["competitors", "competitors_strength", "competitors_low", "advantages"],
|
6: ["competitors", "competitors_strength", "competitors_low", "advantages"],
|
||||||
7: ["money", "finance_model"],
|
7: ["money", "finance_model"],
|
||||||
8: ["how_much_investments", "financial_indicators"],
|
8: ["how_much_investments", "financial_indicators", "users_metrics"],
|
||||||
9: ["your_role", "your_teammates", "past_investors"],
|
9: ["your_role", "your_teammates", "past_investors"],
|
||||||
10: ["how_much_investments", "time_to_spend", "investments_sold"],
|
10: ["how_much_investments", "time_to_spend", "investments_sold"],
|
||||||
11: ["company_value", "future_value", "time_to_spend"],
|
11: ["company_value", "future_value", "time_to_spend"],
|
||||||
|
@ -97,14 +99,27 @@ def get(self, request, *args, **kwargs):
|
||||||
PitchDeck,
|
PitchDeck,
|
||||||
id=self.kwargs["deck_id"],
|
id=self.kwargs["deck_id"],
|
||||||
)
|
)
|
||||||
|
re_data = {
|
||||||
|
"deck": BasePitchDeckSerializer().to_representation(deck),
|
||||||
|
}
|
||||||
resp = []
|
resp = []
|
||||||
data = deck.questions
|
data = deck.questions
|
||||||
for slide, tags in self.structure.items():
|
for slide, tags in self.structure.items():
|
||||||
slide_data = {"slide": slide, "data": []}
|
slide_data = {"slide": slide, "data": []}
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
slide_data["data"].append(
|
b_data = {}
|
||||||
{"slug": tag, "answer": data[tag] if tag in data else {}}
|
if tag in data:
|
||||||
)
|
if "answer" in data[tag]:
|
||||||
resp.append(slide_data)
|
b_data["answer"] = data[tag]["answer"]
|
||||||
|
if "photos" in data[tag]:
|
||||||
|
b_data["photos"] = data[tag]["photos"]
|
||||||
|
|
||||||
return Response(resp)
|
slide_data["data"].append({"slug": tag, **b_data})
|
||||||
|
resp.append(slide_data)
|
||||||
|
re_data["slides"] = resp
|
||||||
|
return Response(re_data)
|
||||||
|
|
||||||
|
|
||||||
|
class ConvertPdfToPPTXApiView(generics.CreateAPIView):
|
||||||
|
serializer_class = PdfToPPTXSerializer
|
||||||
|
parser_classes = [FormParser, MultiPartParser]
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Generated by Django 4.2.4 on 2023-08-26 21:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("decks", "0007_alter_question_type_alter_questionanswer_deck"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="PdfToPPTXStorage",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("pdf", models.FileField(upload_to="pdf/")),
|
||||||
|
("pptx", models.FileField(blank=True, null=True, upload_to="pptx/")),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="question",
|
||||||
|
name="type",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("text", "Text"),
|
||||||
|
("number", "Number"),
|
||||||
|
("text_array", "text array"),
|
||||||
|
("range", "Range"),
|
||||||
|
("multiple_range", "multiple range"),
|
||||||
|
("select", "Select"),
|
||||||
|
("link", "Link"),
|
||||||
|
("date", "Date"),
|
||||||
|
("multiple_date_description", "multiple date description"),
|
||||||
|
("photo", "Photo"),
|
||||||
|
("multiple_photo", "multiple photo"),
|
||||||
|
("photo_description", "photo description"),
|
||||||
|
("multiple_link_description", "multiple link description"),
|
||||||
|
("multiple_photo_description", "multiple photo description"),
|
||||||
|
("multiple_links", "multiple links"),
|
||||||
|
],
|
||||||
|
max_length=26,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -85,3 +85,8 @@ class QuestionAnswerPhoto(models.Model):
|
||||||
"QuestionAnswer", related_name="photos", on_delete=models.CASCADE
|
"QuestionAnswer", related_name="photos", on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
file = models.ImageField(upload_to="uploads/")
|
file = models.ImageField(upload_to="uploads/")
|
||||||
|
|
||||||
|
|
||||||
|
class PdfToPPTXStorage(models.Model):
|
||||||
|
pdf = models.FileField(upload_to="pdf/")
|
||||||
|
pptx = models.FileField(upload_to="pptx/", blank=True, null=True)
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from django.core.files import File
|
||||||
from django.db.models.signals import post_save, pre_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 (
|
||||||
|
PdfToPPTXStorage,
|
||||||
|
PitchDeck,
|
||||||
|
QuestionAnswer,
|
||||||
|
)
|
||||||
from pitch_deck_generator.decks.tasks import (
|
from pitch_deck_generator.decks.tasks import (
|
||||||
|
ML_HOST,
|
||||||
|
create_images_mokups,
|
||||||
generate_numeric_values,
|
generate_numeric_values,
|
||||||
qenerate_answer_qr,
|
qenerate_answer_qr,
|
||||||
run_pitch_deck_calculation,
|
run_pitch_deck_calculation,
|
||||||
|
@ -23,9 +33,14 @@ def question_answer_create(sender, instance: QuestionAnswer, created, **kwargs):
|
||||||
generate_numeric_values.apply_async(
|
generate_numeric_values.apply_async(
|
||||||
kwargs={"pk": instance.deck.pk}, countdown=1
|
kwargs={"pk": instance.deck.pk}, countdown=1
|
||||||
)
|
)
|
||||||
|
elif instance.question.inner_tag == "names":
|
||||||
|
instance.deck.name = instance.answer
|
||||||
|
instance.deck.save()
|
||||||
elif instance.question.inner_tag in ["finance_model"]:
|
elif instance.question.inner_tag in ["finance_model"]:
|
||||||
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=1)
|
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
||||||
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
elif instance.question.inner_tag == "images":
|
||||||
|
create_images_mokups.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
||||||
|
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=10)
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=QuestionAnswer)
|
@receiver(pre_save, sender=QuestionAnswer)
|
||||||
|
@ -36,5 +51,23 @@ def question_answer_update(sender, instance: QuestionAnswer, **kwargs):
|
||||||
kwargs={"pk": instance.deck.pk}, countdown=1
|
kwargs={"pk": instance.deck.pk}, countdown=1
|
||||||
)
|
)
|
||||||
elif instance.question.inner_tag in ["finance_model"]:
|
elif instance.question.inner_tag in ["finance_model"]:
|
||||||
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=1)
|
qenerate_answer_qr.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
||||||
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
elif instance.question.inner_tag == "images":
|
||||||
|
create_images_mokups.apply_async(kwargs={"pk": instance.pk}, countdown=5)
|
||||||
|
save_answer_to_deck.apply_async(kwargs={"pk": instance.pk}, countdown=10)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=PdfToPPTXStorage)
|
||||||
|
def pdt_to_pptx_convert(sender, instance: PdfToPPTXStorage, created, **kwargs):
|
||||||
|
if created:
|
||||||
|
with open(instance.pdf.path, "rb") as f:
|
||||||
|
r = requests.post(ML_HOST + "convert-to-pptx", files={"in_file": f}).json()
|
||||||
|
data = requests.get(ML_HOST + r["file"][1:]).content
|
||||||
|
instance.pptx.save(
|
||||||
|
instance.pdf.path.split("/")[-1].replace("pdf", "pptx"),
|
||||||
|
File(
|
||||||
|
BytesIO(data),
|
||||||
|
instance.pdf.path.split("/")[-1].replace("pdf", "pptx"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
instance.save()
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
QuestionAnswerPhoto,
|
QuestionAnswerPhoto,
|
||||||
QuestionDeckHint,
|
QuestionDeckHint,
|
||||||
)
|
)
|
||||||
|
from pitch_deck_generator.decks.services import get_image_mokeup
|
||||||
|
|
||||||
ML_HOST = "https://purple-kids-drive.loca.lt/"
|
ML_HOST = "https://forty-eggs-slide.loca.lt/"
|
||||||
|
|
||||||
data_types = {
|
data_types = {
|
||||||
"names": ("text", 1),
|
"names": ("text", 1),
|
||||||
|
@ -166,3 +167,13 @@ def qenerate_answer_qr(pk: int):
|
||||||
answer=qa,
|
answer=qa,
|
||||||
file=File(tmp, name="qr.png"),
|
file=File(tmp, name="qr.png"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def create_images_mokups(pk: int):
|
||||||
|
qa = QuestionAnswer.objects.get(pk=pk)
|
||||||
|
for image in qa.photos.all():
|
||||||
|
mokup_path = get_image_mokeup(image.file.path)
|
||||||
|
with open(mokup_path, "rb") as f:
|
||||||
|
image.file = File(f, name="mokup.png")
|
||||||
|
image.save()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user