Короткая версия:
Сделал Telegram бота - https://t.me/ternausbot
Вводишь текст или загружаешь картинку - получаешь 10 похожих.
Картинки из базы данных с Ternaus.com - 8.5 миллионов картинок, сгенерированных Stable Diffusion.
Код бота на python ниже.
Длинная версия:
В прошлом посте рассказал о том, как сделал Chrome Extension, которое позволяет по любым картинкам и тестам в интернете искать сгенерированные картинки.
Там же упоминал, что планирую добавить Telegram бота.
С технической стороны - это несложное, но полезное упражнение, которое расширяет спектр моих технических навыков.
С продуктовой - телеграм - это “другой UI”, отличается от сайта, отличается от телефонных приложенией.
Мне нравится, как у меня работает поиск. Но очень не нравится, что результатами неудобно делится.
Да, при желании можно поделиться ссылками вида:
Это больше, чем ничего, но хочется усугубить. Хочется делиться с другими не только ссылками, но и самимими картинками.
И в телеграмме это очень удобно. Сделал запрос, получил картинки, сделал Forward знакомому. Магия.
Первые 100 запросов бесплатно, потом символические 1 цент за запрос. Такое ощущение, что чисто поиграться и 100 хватит, а если кому-то для чего-то надо, то и 1 цент не деньги.
Код, в котором я вырезал кусок про деньги.
import io
import logging
import os
from typing import Any
import aiogram
import httpx
import ujson as json
from PIL import Image
from aiogram import Bot, Dispatcher, types
from aiogram.utils.executor import start_webhook
from image2base64.converters import rgb2base64
APP_NAME = os.getenv("APP_NAME")
TOKEN = os.getenv("TELEGRAM_TOKEN")
# webhook settings
WEBHOOK_HOST = f"https://{APP_NAME}.herokuapp.com"
WEBHOOK_PATH = f"/webhook/{TOKEN}"
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
# webserver settings
WEBAPP_HOST = "0.0.0.0"
WEBAPP_PORT = os.getenv("PORT", default=8000)
bot = Bot(token=TOKEN)
dp = Dispatcher(bot)
headers = {
"content-type": "application/json",
"x-api-key": os.getenv("TERNAUS_TOKEN"),
}
SIMILARITY_SEARCH_API = "https://simages.info"
def get_image_data(url: str) -> types.InputMediaPhoto:
return aiogram.types.InputMediaPhoto(url)
async def on_startup(dispatcher):
await bot.set_webhook(WEBHOOK_URL, drop_pending_updates=True)
async def on_shutdown(dispatcher):
await bot.delete_webhook()
async def get_result(body: dict[str, str | int]) -> dict[str, Any]:
async with httpx.AsyncClient(headers=headers, timeout=600) as client:
return (await client.post(SIMILARITY_SEARCH_API, data=json.dumps(body))).json()
@dp.message_handler(content_types=["photo"])
async def photo_handler(message: types.Message) -> None:
file_in_io = io.BytesIO()
await (await message.photo[-1].get_file()).download(destination_file=file_in_io)
image = Image.open(file_in_io).convert("RGB").resize((TARGET_SIZE, TARGET_SIZE))
base64 = rgb2base64(image, quality=80)
result = await get_result({"image": base64, "num_similar": 10})
output = [get_image_data(item["url"]) for item in json.loads(result["body"])["images"]]
await bot.send_media_group(message.from_user.id, output)
@dp.message_handler(commands=["text"])
async def text_handler(message: types.Message) -> None:
text = message.text.replace("/text", "").strip()
result = await get_result({"text": text, "num_similar": 10})
output = [get_image_data(item["url"]) for item in json.loads(result["body"])["images"]]
await bot.send_media_group(message.from_user.id, output)
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
start_webhook(
dispatcher=dp,
webhook_path=WEBHOOK_PATH,
skip_updates=True,
on_startup=on_startup,
on_shutdown=on_shutdown,
host=WEBAPP_HOST,
port=WEBAPP_PORT,
)

Q: А почему не сделать все бесплатным, к чему эти центы?
Тут, наверное, так - гештальт с тем, чтобы от души сделать что-то полезное для людей у меня закрыт разработкой Open Source библиотекой Albumentations. Сейчас у нас 16 тысяч скачиваний в день.
Следуюдий незакрытый гештальт - сделать продукт, который приносит деньги.
Картина про монетизацию у меня в голове выглядит так:
Если вы строите бесплатный продукт, но планируете продавать рекламу или данные юзеров, тогда не надо пытаться просить деньги - качайте базу юзеров. Примеры: Google, Facebook
Если продукт имеет очевидные Network Effects, тогда тоже имеет смысл качать число юзеров, даже в убыток. Удачный пример: PayPal. Неудачный: Uber, Lyft
Если планируете раскачать базу пользователей и продать кому-то еще, чтобы другая компания ломала голову с монетизацией, то тоже не надо давить рост базы пользователей попытками выдоить копеечку. Пример: PayPal, Kaggle. Есть мысль, что это кривая дорожка и на нее встают от безысходности.
Если планируете в будущем снимать деньги с пользователей, то просить денег надо уже сейчас. Да, платить никто не будет, и смотреть каждый день на строчку Revenue = 0 - это боль. Но это необходимая боль, которая будет заставляет думать в нужную сторону.
И так как Network effects не просматриваются - идем по 4 варианту.
Так что любой запрос к серверу с GPU, которые обрабатывает запросы на похожие картинки должен что-то давать. Либо маркетинг, либо деньги.
Поиск на сайте и скачивание картинок - бесплатные.
Использование Chrome Extension, которое позволяет по картинкам и тексту искать у меня в базе данных - бесплатные.
API - 1 цент за удачный запрос.
Telegram bot - первые 100 запросов бесплатные, потом 1 цент за запрос.
Не, то, чтобы эта схема хорошо работает, но какой-то траффик, и что важнее feedback идет.
Так что кому нужны сгенерированные картинки, которые можно использовать для любых целей, включая коммерческие - берите и пользуйтесь. А я пойду писать приложение для телефона. Тут оно совсем сбоку, но тоже выглядит как хорошее упражнение.