This commit is contained in:
ilia 2023-08-27 02:58:30 +03:00
commit 213d55d268
23 changed files with 11178 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/venv
/static

3
README.md Normal file
View File

@ -0,0 +1,3 @@
### Как запускать
`pip install -r requirements.txt`
`uvicorn search_server:app --reload`

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

38
a.py Normal file
View 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.

BIN
ann.ann Normal file

Binary file not shown.

32
compress.py Normal file
View 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.pic Normal file

Binary file not shown.

BIN
data_img.pic Normal file

Binary file not shown.

BIN
file.pptx Normal file

Binary file not shown.

BIN
im.pic Normal file

Binary file not shown.

42
img_search.py Normal file
View 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))

BIN
imgs.pic Normal file

Binary file not shown.

BIN
index.ann Normal file

Binary file not shown.

10681
note.ipynb Normal file

File diff suppressed because it is too large Load Diff

2
numeric_metrics.py Normal file
View File

@ -0,0 +1,2 @@
from search import search_investments

158
openai_handle.py Normal file
View 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

Binary file not shown.

164
search.py Normal file
View 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
View 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)