mirror of
https://github.com/spbleadersofdigtal/ml.git
synced 2024-11-21 16:06:35 +03:00
a
This commit is contained in:
commit
213d55d268
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/venv
|
||||
/static
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
### Как запускать
|
||||
`pip install -r requirements.txt`
|
||||
`uvicorn search_server:app --reload`
|
BIN
__pycache__/compress.cpython-39.pyc
Normal file
BIN
__pycache__/compress.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/img_search.cpython-39.pyc
Normal file
BIN
__pycache__/img_search.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/numeric_metrics.cpython-39.pyc
Normal file
BIN
__pycache__/numeric_metrics.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/search.cpython-39.pyc
Normal file
BIN
__pycache__/search.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/search_server.cpython-39.pyc
Normal file
BIN
__pycache__/search_server.cpython-39.pyc
Normal file
Binary file not shown.
38
a.py
Normal file
38
a.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# coding=utf8
|
||||
# the above tag defines encoding for this document and is for Python 2.x compatibility
|
||||
|
||||
import re
|
||||
|
||||
regex = r"({(\n.+)+\n})"
|
||||
|
||||
test_str = (
|
||||
"{\n"
|
||||
" 'users': 'Кто будет пользоваться продуктом',\n"
|
||||
" 'problems': 'Какие проблемы решает продукт',\n"
|
||||
" 'actuality': 'Продолжите предложение: Актуальность проблемы подтверждается тем фактом, что...',\n"
|
||||
" 'solve': 'Как решаем эти проблемы',\n"
|
||||
" 'works': 'Как работает решение',\n"
|
||||
"}\n\n"
|
||||
"{\n"
|
||||
" 'users': 'Стартапы и компании, ищущие инвестиции',\n"
|
||||
" 'problems': '1. Недостаток средств для разработки качественного Pitch Deck. 2. Недостаток экспертизы для проведения исследований и отражения их результатов в презентации. 3. Недостаток времени для разработки инвестиционных материалов.',\n"
|
||||
" 'actuality': 'Продолжение предложения: Актуальность проблемы подтверждается тем фактом, что многие стартапы сталкиваются с ограниченными финансами и отсутствием нужных знаний в области маркетинга, финансов и анализа рынка, что затрудняет привлечение инвестиций. Они также испытывают нехватку времени из-за фокуса на разработке продукта или сервиса.',\n"
|
||||
" 'solve': 'Продукт решает эти проблемы, предоставляя вспомогательный инструмент на основе искусственного интеллекта, специализированный для создания Pitch-Deck.',\n"
|
||||
" 'works': 'Решение работает, используя возможности искусственного интеллекта для автоматизации процесса создания презентаций, учитывая требования инвесторов и примеры успешных Pitch Deck. Это позволяет стартапам и компаниям создавать более привлекательные и информативные презентации для привлечения инвестиций.'\n"
|
||||
"}"
|
||||
)
|
||||
|
||||
another_test = (
|
||||
"{\n"
|
||||
" 'users': 'Стартапы и компании, ищущие инвестиции',\n"
|
||||
" 'problems': '1. Недостаток средств для разработки качественного Pitch Deck. 2. Недостаток экспертизы для проведения исследований и отражения их результатов в презентации. 3. Недостаток времени для разработки инвестиционных материалов.',\n"
|
||||
" 'actuality': 'Продолжение предложения: Актуальность проблемы подтверждается тем фактом, что многие стартапы сталкиваются с ограниченными финансами и отсутствием нужных знаний в области маркетинга, финансов и анализа рынка, что затрудняет привлечение инвестиций. Они также испытывают нехватку времени из-за фокуса на разработке продукта или сервиса.',\n"
|
||||
" 'solve': 'Продукт решает эти проблемы, предоставляя вспомогательный инструмент на основе искусственного интеллекта, специализированный для создания Pitch-Deck.',\n"
|
||||
" 'works': 'Решение работает, используя возможности искусственного интеллекта для автоматизации процесса создания презентаций, учитывая требования инвесторов и примеры успешных Pitch Deck. Это позволяет стартапам и компаниям создавать более привлекательные и информативные презентации для привлечения инвестиций.'\n"
|
||||
"}"
|
||||
)
|
||||
|
||||
print(list(re.finditer(regex, test_str, re.MULTILINE))[-1].group())
|
||||
print(list(re.finditer(regex, another_test, re.MULTILINE))[-1].group())
|
||||
|
||||
# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.
|
32
compress.py
Normal file
32
compress.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
import torch
|
||||
from transformers import AutoModelForTokenClassification, AutoTokenizer
|
||||
|
||||
model_name = "cointegrated/rubert-tiny2-sentence-compression"
|
||||
model = AutoModelForTokenClassification.from_pretrained(model_name)
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
||||
|
||||
|
||||
def compress(text, threshold=0.5, keep_ratio=None):
|
||||
"""Compress a sentence by removing the least important words.
|
||||
Parameters:
|
||||
threshold: cutoff for predicted probabilities of word removal
|
||||
keep_ratio: proportion of words to preserve
|
||||
By default, threshold of 0.5 is used.
|
||||
"""
|
||||
with torch.inference_mode():
|
||||
tok = tokenizer(text, return_tensors="pt").to(model.device)
|
||||
proba = torch.softmax(model(**tok).logits, -1).cpu().numpy()[0, :, 1]
|
||||
if keep_ratio is not None:
|
||||
threshold = sorted(proba)[int(len(proba) * keep_ratio)]
|
||||
kept_toks = []
|
||||
keep = False
|
||||
prev_word_id = None
|
||||
for word_id, score, token in zip(tok.word_ids(), proba, tok.input_ids[0]):
|
||||
if word_id is None:
|
||||
keep = True
|
||||
elif word_id != prev_word_id:
|
||||
keep = score < threshold
|
||||
if keep:
|
||||
kept_toks.append(token)
|
||||
prev_word_id = word_id
|
||||
return tokenizer.decode(kept_toks, skip_special_tokens=True)
|
BIN
data_img.pic
Normal file
BIN
data_img.pic
Normal file
Binary file not shown.
42
img_search.py
Normal file
42
img_search.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
import pickle
|
||||
from annoy import AnnoyIndex
|
||||
from sentence_transformers import SentenceTransformer
|
||||
|
||||
data = None
|
||||
search_data = None
|
||||
model = None
|
||||
|
||||
|
||||
def get_data():
|
||||
global data
|
||||
if not data:
|
||||
with open("data_img.pic", "rb") as file:
|
||||
data = pickle.load(file)
|
||||
return data
|
||||
|
||||
|
||||
def get_search():
|
||||
global search_data
|
||||
if not search_data:
|
||||
search_data = AnnoyIndex(768, "angular")
|
||||
search_data.load("ann.ann")
|
||||
return search_data
|
||||
|
||||
|
||||
def get_model():
|
||||
global model
|
||||
if not model:
|
||||
model = SentenceTransformer("sentence-transformers/LaBSE")
|
||||
return model
|
||||
|
||||
|
||||
def search(search_str):
|
||||
vectors = get_model().encode([search_str])[0]
|
||||
inds = get_search().get_nns_by_vector(vectors, 5)
|
||||
res = []
|
||||
for ind in inds:
|
||||
try:
|
||||
res.append(get_data()[ind])
|
||||
except:
|
||||
pass
|
||||
return list(map(lambda x: x["link"], res))
|
10681
note.ipynb
Normal file
10681
note.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
2
numeric_metrics.py
Normal file
2
numeric_metrics.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
from search import search_investments
|
||||
|
158
openai_handle.py
Normal file
158
openai_handle.py
Normal file
|
@ -0,0 +1,158 @@
|
|||
import openai
|
||||
import datetime
|
||||
from ast import literal_eval
|
||||
import re
|
||||
|
||||
KEY = "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"
|
||||
|
||||
regex = r"({(\n.+)+\n})"
|
||||
|
||||
description = """
|
||||
🍀 Кейсодержатель:
|
||||
ООО «Акселератор Возможностей» (https://ac-vo.ru/) при ИНТЦ МГУ «Воробьевы горы».
|
||||
Организация технологических и инвестиционных мероприятий, курирование инновационной деятельности внутри ИНТЦ МГУ «Воробьевы горы»
|
||||
|
||||
Раскроем небольшую тайну венчура — для привлечения денежных средств и защиты своего проекта, стартапу нужен Pitch-Deck.
|
||||
|
||||
🍀 Что такое Pitch-Deck?
|
||||
Pitch-Deck представляет собой презентацию-тизер проекта/компании для инвесторов, партнеров, журналистов и других заинтересованных лиц. Цель презентации - привлечение дополнительного финансирования (инвестиций).
|
||||
Почему это проблема?
|
||||
|
||||
🍀 Проблема #1. Недостаток средств:
|
||||
Для многих стартапов ограниченные финансы создают преграду при разработке качественного Pitch Deck. Отсутствие достаточных средств для найма профессиональных консультантов, дизайнеров и копирайтеров, а также для проведения исследований рынка, может привести к созданию менее привлекательной и малоинформативной презентации, что затрудняет привлечение инвестиций.
|
||||
|
||||
🍀 Проблема #2. Недостаток экспертизы:
|
||||
Проблемой для стартапов является недостаток экспертизы для проведения необходимых исследований и корректного отражения их результатов в Pitch Deck. Не всегда у стартапов есть нужные знания в области маркетинга, финансов и анализа рынка, что затрудняет создание убедительной и информативной презентации для привлечения инвестиций.
|
||||
|
||||
🍀 Проблема #3. Недостаток времени
|
||||
Молодым компаниям для привлечения инвестиций требуется подготовить целый пакет документов, одним из которых является Pitch Deck. Особенностью стартапов является сравнительного молодая и небольшая команда, у которой чисто физически не хватает времени на разработку инвестиционных материалов, ведь они полностью погружены в процесс разработки и улучшения продукта или сервиса.
|
||||
|
||||
🍀 ИДЕЯ:
|
||||
Основная идея кейса заключается в создании вспомогательного инструмента на основе ИИ, заточенного под создание Pitch-Deck.
|
||||
"""
|
||||
|
||||
names_prompt="""
|
||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||
{
|
||||
"names": "Назови 5 имен проекта с данным описанием через запятую"
|
||||
}
|
||||
"""
|
||||
|
||||
prompts = [
|
||||
"""
|
||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||
{
|
||||
'users': 'Кто будет пользоваться продуктом?',
|
||||
'problems': 'Какие проблемы решает продукт?',
|
||||
'actuality': 'Каким фактом обуславливается актуальность проблемы?',
|
||||
'solve': 'Как решаем эти проблемы?',
|
||||
'works': 'Как работает решение?',
|
||||
}
|
||||
""",
|
||||
"""
|
||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||
{
|
||||
'awards': 'Ценность продукта для пользователей',
|
||||
'money': 'На чем проект зарабатывает? сколько и за что ему платят клиенты',
|
||||
'aims': Напиши 3 цели: на месяц, на полгода и год, формат: {'1': цель на месяц, '2': цель на полгода, '3': цель на год},
|
||||
'investments_sold': 'На что потратить инвестиции под проект',
|
||||
'financial_indicators': 'Напиши финансовые показатели проекта'
|
||||
}
|
||||
""",
|
||||
"""
|
||||
По тексту ответь или предположи ответ на вопросы в следующем формате:
|
||||
{
|
||||
'achieve': 'Чего добьется команда после освоения инвестиций',
|
||||
'competitors_strength': 'Сильные стороны конкурентов',
|
||||
'competitors_low': 'Слабые стороны конкурентов',
|
||||
'advantages': 'Какие могут быть преимущества над конкурентами',
|
||||
'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'"
|
||||
}
|
||||
"""
|
||||
]
|
||||
|
||||
|
||||
openai.api_key = KEY
|
||||
|
||||
assertions = [
|
||||
[
|
||||
lambda data: 'users' in data.keys(),
|
||||
lambda data: 'problems' in data.keys(),
|
||||
lambda data: 'actuality' in data.keys(),
|
||||
lambda data: 'solve' in data.keys(),
|
||||
lambda data: 'works' in data.keys(),
|
||||
],
|
||||
[
|
||||
lambda data: 'awards' in data.keys(),
|
||||
lambda data: 'money' in data.keys(),
|
||||
lambda data: 'aims' in data.keys(),
|
||||
lambda data: 'investments_sold' in data.keys(),
|
||||
lambda data: 'financial_indicators' in data.keys(),
|
||||
],
|
||||
[
|
||||
lambda data: 'achieve' in data.keys(),
|
||||
lambda data: 'competitors_strength' in data.keys(),
|
||||
lambda data: 'competitors_low' in data.keys(),
|
||||
lambda data: 'advantages' in data.keys(),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
def create_hints(description: str, stage: int):
|
||||
global prompts
|
||||
chat_completion = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[{"role": "user", "content": description + "\n" + prompts[stage]}],
|
||||
)
|
||||
str_content = chat_completion.choices[0].message.content
|
||||
try:
|
||||
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}')
|
||||
except:
|
||||
raise ValueError(f'answer doesnt pass validation, {filtered_content}')
|
||||
content = literal_eval(filtered_content)
|
||||
for assertion_statement in assertions[stage]:
|
||||
assert assertion_statement(content)
|
||||
|
||||
if stage == 1:
|
||||
content['aims'] = [
|
||||
{
|
||||
'aim': content['aims']['1'],
|
||||
'date': (datetime.datetime.now() + datetime.timedelta(days=30)).isoformat()
|
||||
},
|
||||
{
|
||||
'aim': content['aims']['2'],
|
||||
'date': (datetime.datetime.now() + datetime.timedelta(days=180)).isoformat()
|
||||
},
|
||||
{
|
||||
'aim': content['aims']['3'],
|
||||
'date': (datetime.datetime.now() + datetime.timedelta(days=365)).isoformat()
|
||||
}
|
||||
]
|
||||
result = []
|
||||
for key, value in content.items():
|
||||
result.append({
|
||||
'type': key,
|
||||
'value': value
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def create_name_hint(description: str):
|
||||
global names_prompt
|
||||
chat_completion = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[{"role": "user", "content": description + "\n" + names_prompt}],
|
||||
)
|
||||
answer = literal_eval(chat_completion.choices[0].message.content)['names'].split(', ')
|
||||
print(answer)
|
||||
return {
|
||||
'type': 'names',
|
||||
'value': answer
|
||||
}
|
||||
|
||||
#print(create_name_hint(description))
|
||||
print(create_hints(description, 0))
|
||||
# print(create_hints(description, 1))
|
||||
# print(create_hints(description, 2))
|
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
164
search.py
Normal file
164
search.py
Normal file
|
@ -0,0 +1,164 @@
|
|||
from annoy import AnnoyIndex
|
||||
from sentence_transformers import SentenceTransformer
|
||||
import pickle
|
||||
import os
|
||||
|
||||
model = None
|
||||
data = None
|
||||
index = None
|
||||
|
||||
|
||||
def get_model():
|
||||
global model
|
||||
if not model:
|
||||
model = SentenceTransformer("sentence-transformers/LaBSE")
|
||||
return model
|
||||
|
||||
|
||||
def get_data():
|
||||
global data
|
||||
if not data:
|
||||
with open("./data.pic", "rb") as file:
|
||||
data = pickle.load(file)
|
||||
for i in range(len(data)):
|
||||
if 'image' not in data[i].keys():
|
||||
data[i].update({'image': None})
|
||||
return data
|
||||
|
||||
|
||||
def get_index():
|
||||
global index
|
||||
if not index:
|
||||
index = AnnoyIndex(768, "angular")
|
||||
index.load("index.ann")
|
||||
return index
|
||||
|
||||
|
||||
def search(search_string):
|
||||
embs = get_model().encode([search_string])[0]
|
||||
indexes = get_index().get_nns_by_vector(embs, 5)
|
||||
res = []
|
||||
for i in indexes:
|
||||
try:
|
||||
res.append(get_data()[i])
|
||||
except: pass
|
||||
return list(map(lambda x: {'logo': x['image'], 'name': x['name'], 'description': x['description']}, res))
|
||||
|
||||
|
||||
def search_investemnts(search_string):
|
||||
embs = get_model().encode([search_string])[0]
|
||||
indexes = get_index().get_nns_by_vector(embs, 5)
|
||||
res = []
|
||||
for i in indexes:
|
||||
try:
|
||||
res.append(get_data()[i])
|
||||
except:
|
||||
pass
|
||||
if not len(res):
|
||||
res = [{'total_investments': 2000000}]
|
||||
return list(map(lambda x: x['total_investments'], res))
|
||||
|
||||
|
||||
comp_data = {
|
||||
"B2C": {
|
||||
"CAC": 10,
|
||||
"LTV": 12,
|
||||
},
|
||||
"B2B": {
|
||||
"CAC": 1000,
|
||||
"LTV": 1300
|
||||
},
|
||||
"TAM": {
|
||||
"AI": 40680000000000,
|
||||
"Business Software": 50600000000000,
|
||||
"IndustrialTech": 5000000000000,
|
||||
"E-commerce": 1440000000000000,
|
||||
"Advertising & Marketing": 47700000000000,
|
||||
"Hardware": 65700000000000,
|
||||
"RetailTech": 1080000000000,
|
||||
"ConstructionTech": 484200000000,
|
||||
"Web3": 5400000000000000,
|
||||
"EdTech": 10350000000000,
|
||||
"Business Intelligence": 2430000000000,
|
||||
"Cybersecurity": 15300000000000,
|
||||
"HrTech": 2160000000000,
|
||||
"Telecom & Communication": 162000000000000,
|
||||
"Media & Entertainment": 225000000000000,
|
||||
"FinTech": 810000000000000,
|
||||
"MedTech": 46080000000000,
|
||||
"Transport & Logistics": 90000000000000,
|
||||
"Gaming": 31230000000000,
|
||||
"FoodTech": 22230000000000,
|
||||
"WorkTech": 90000000000000,
|
||||
"Consumer Goods & Services": 8370000000000,
|
||||
"Aero & SpaceTech": 34200000000000,
|
||||
"Legal & RegTech": 720000000000,
|
||||
"Travel": 180000000000000,
|
||||
"PropTech": 2700000000000,
|
||||
"Energy": 162000000000,
|
||||
"GreenTech": 5580000000000,
|
||||
},
|
||||
"SAM": 0.3,
|
||||
"SOM": 0.13,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
def calculate_metrics(category, description, type):
|
||||
cac = comp_data[type]['CAC']
|
||||
ltv = comp_data[type]['LTV']
|
||||
try:
|
||||
tam = comp_data['TAM'][category] // 1000
|
||||
except:
|
||||
tam = comp_data['TAM']['AI'] // 1000
|
||||
sam = comp_data['SAM'] * tam
|
||||
som = comp_data["SOM"] * comp_data['SAM'] * tam
|
||||
percent_now = 0.02
|
||||
percent_then = 0.18
|
||||
|
||||
investments = search_investemnts(description)
|
||||
invest = sum(investments) / len(investments) / 300
|
||||
company_value = invest * 3
|
||||
invest_then = company_value * 1.3
|
||||
|
||||
return [
|
||||
{
|
||||
'type': 'users_metrics',
|
||||
'value': {
|
||||
'cac': cac,
|
||||
'ltv': ltv
|
||||
},
|
||||
},
|
||||
{
|
||||
'type': 'market_values',
|
||||
'value': {
|
||||
'tam': tam,
|
||||
'sam': sam,
|
||||
'som': som
|
||||
}
|
||||
},
|
||||
{
|
||||
'type': 'percentage',
|
||||
'value': {
|
||||
'now': percent_now,
|
||||
'then': percent_then
|
||||
}
|
||||
},
|
||||
{
|
||||
'type': 'how_much_investments',
|
||||
'value': invest
|
||||
},
|
||||
{
|
||||
'type': 'company_value',
|
||||
'value': company_value
|
||||
},
|
||||
{
|
||||
'type': 'future_value',
|
||||
'value': invest_then
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def pdf_to_pptx(filename: str):
|
||||
os.system(f'pdf2pptx {filename}')
|
56
search_server.py
Normal file
56
search_server.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI, UploadFile, File
|
||||
from search import search, calculate_metrics, pdf_to_pptx
|
||||
from img_search import search as image_search
|
||||
from compress import compress
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
import random
|
||||
import string
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
def random_slug():
|
||||
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8))
|
||||
|
||||
|
||||
class Request(BaseModel):
|
||||
body: str
|
||||
|
||||
|
||||
class NumericRequest(BaseModel):
|
||||
description: str
|
||||
category: str
|
||||
type: str
|
||||
|
||||
@app.post("/search")
|
||||
def read_root(body: Request):
|
||||
return search(body.body)
|
||||
|
||||
|
||||
@app.post('/numeric')
|
||||
def get_numeric(body: NumericRequest):
|
||||
return calculate_metrics(body.category, body.description, body.type)
|
||||
|
||||
|
||||
@app.post('/compress')
|
||||
def get_compressed(body: Request):
|
||||
return compress(body.body, threshold=0.8)
|
||||
|
||||
@app.post('/convert-to-pptx')
|
||||
async def convert(in_file: UploadFile):
|
||||
sl = random_slug()
|
||||
with open(f'./static/{sl}.pdf', 'wb') as file:
|
||||
content = await in_file.read()
|
||||
file.write(content)
|
||||
pdf_to_pptx(f'./static/{sl}.pdf')
|
||||
return {
|
||||
'file': f'/static/{sl}.pptx'
|
||||
}
|
||||
|
||||
@app.post('/img-search')
|
||||
async def img_search(body: Request):
|
||||
return image_search(body.body)
|
Loading…
Reference in New Issue
Block a user