Короткая версия:

  • Сделал 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 тысяч скачиваний в день.

Следуюдий незакрытый гештальт - сделать продукт, который приносит деньги.

Картина про монетизацию у меня в голове выглядит так:

  1. Если вы строите бесплатный продукт, но планируете продавать рекламу или данные юзеров, тогда не надо пытаться просить деньги - качайте базу юзеров. Примеры: Google, Facebook

  2. Если продукт имеет очевидные Network Effects, тогда тоже имеет смысл качать число юзеров, даже в убыток. Удачный пример: PayPal. Неудачный: Uber, Lyft

  3. Если планируете раскачать базу пользователей и продать кому-то еще, чтобы другая компания ломала голову с монетизацией, то тоже не надо давить рост базы пользователей попытками выдоить копеечку. Пример: PayPal, Kaggle. Есть мысль, что это кривая дорожка и на нее встают от безысходности.

  4. Если планируете в будущем снимать деньги с пользователей, то просить денег надо уже сейчас. Да, платить никто не будет, и смотреть каждый день на строчку Revenue = 0 - это боль. Но это необходимая боль, которая будет заставляет думать в нужную сторону.

И так как Network effects не просматриваются - идем по 4 варианту.

Так что любой запрос к серверу с GPU, которые обрабатывает запросы на похожие картинки должен что-то давать. Либо маркетинг, либо деньги.

  • Поиск на сайте и скачивание картинок - бесплатные.

  • Использование Chrome Extension, которое позволяет по картинкам и тексту искать у меня в базе данных - бесплатные.

  • API - 1 цент за удачный запрос.

  • Telegram bot - первые 100 запросов бесплатные, потом 1 цент за запрос.

Не, то, чтобы эта схема хорошо работает, но какой-то траффик, и что важнее feedback идет.

Так что кому нужны сгенерированные картинки, которые можно использовать для любых целей, включая коммерческие - берите и пользуйтесь. А я пойду писать приложение для телефона. Тут оно совсем сбоку, но тоже выглядит как хорошее упражнение.

https://www.ternaus.com/search/?text=Asian+woman+cyberpunk
https://www.ternaus.com/search/?text=Asian+woman+cyberpunk

Комментарии (23)


  1. cry_san
    06.12.2022 03:12

    А разве не будет проще использовать запросы с браузера? Не используя их API.

    Так будет по крайней мере бесплатно.


    1. ternaus Автор
      06.12.2022 03:22

      Что сайт, что API, что бот - все в моем исполнении, поэтому бота тоже можно бесплатным.

      Как я в тексте отметил, с каждого запроса хочется что-то получать. Либо деньги, либо маркетинг.

      Можно, конечно, в телеграмме возвращать не просто картинки, а картинки с водяными знаками с названием сайта и сделать все бесплатным, но, такое ощущение, что это не в ту сторону.

      Хочется чтобы кому надо мог эти картинки куда надо вставлять, не заморачиваясь выводом знаков и лого с картинок.

      1 цент за запрос - это с одной стороны не много, а с другой в бесконечность раз больше, чем бесплатно.

      Опять же, кому хочется совсем бесплатно, то можно на сайте.


      1. cry_san
        06.12.2022 03:24

        Извините, просто пропустил, что где-то отмечено авторство сайта. Поэтому и предложил данный метод.

        Но еще раз повторю, спокойно можно парсить с сайта, причем не заплатив за это ни копейки.

        Таким образом, возможно, скоро сделают бесплатный телеграм-бот.


        1. ternaus Автор
          06.12.2022 03:34
          +1

          Конечно можно. Запрос на сайт + распарсить вывод и вот тебе список URL. Более того, в телеграмме можно не больше 10 картинок, а на сайте возвращаются 50.

          Тут, наверное, так. Эту дырку можно закрыть, но прямо сейчас больших проблем с того, что запросы идут не через API, а через парсинг сайта я не вижу. Да, я с этого не получаю ни денег, ни маркетинга, но не конец мира. Пока пропускной способности хватает с запасом.

          Еще у меня есть мысль, что "на поиграться" человеку должно хватить и 100 бесплатных.

          Самому было бы очень интересно пообщаться с кем-то, кому понадобится больше, ибо это уже какой-то конкретный use case.


          1. cry_san
            06.12.2022 03:38
            +1

            -Да, я с этого не получаю ни денег, ни маркетинга, но не конец мира.

            Хорошая и правильная философия. Спасибо!

            -Еще у меня есть мысль, что "на поиграться" человеку должно хватить и 100 бесплатных.

            Для себя занимаюсь игровым дизайном. В день собираю с pinterest.com около 14000 изображений для выборки вдохновения. Поэтому 100 бесплатных в этом контексте - ничто.


            1. ternaus Автор
              06.12.2022 03:44
              +1

              Сразу много вопросов :)

              [1] А чем сайт неудобен, что позволяет TelegramBot?

              Еще, я когда Extension делал, как раз был мысль позволять людям по картинкам на Pinterest искать картинки на Ternaus.

              [2] 1 цент за запрос я с потолка взял. Просто хочется отделить платных пользователей от бесплатных через PayWall. Как говорят старшие товарищи - feedback и хотелки от тех, кто платит в 10000 раз ценнее, чем от тех, кто нет. 14000 в день по центу и правда много. Как насчет $30 в месяц и лимит 20,000 запросов в день? Это больше похоже на правду?


              1. cry_san
                06.12.2022 03:50
                +1

                На правду похоже. Но лично для меня, из этих 14000 удается для себя выловить около 10 нужных мне. У каждого ведь свое понимание красоты. Платить $30 за 10 картинок, я не потяну. Поэтому и сижу на бесплатном контенте.

                Но вам искренне радуюсь, что сделали сервис для людей и выпустили его в свет, а не просто отложили на полку в дальний угол.


                1. ternaus Автор
                  06.12.2022 03:58
                  +1

                  А тогда другой вопрос.

                  А как это выглядит?

                  Вы ищете изображения на PinTerest и смотрите на них глазами и когда что-то зацепило сохраняете, или же сохраняете все подряд, а фильтрация проходит уже потом?


                  1. cry_san
                    06.12.2022 04:06
                    +1

                    Выбираю по запросу доски пользователей. Скачиваю все нужные доски. Вручную перебираю.


                    1. ternaus Автор
                      06.12.2022 04:16
                      +1

                      Но все делается через сайт или используется какая-то обертка в виде бота или тулзы какой?


                1. ternaus Автор
                  06.12.2022 06:56
                  +1

                  Математика чуть другая.

                  $30 - в месяц. Это $1 в день.

                  То есть просмотр 10k+ картинок в день для получения тех самых 10 в день, то есть 300 в месяц.


  1. SergeyDeryabin
    06.12.2022 03:39
    +2

    Хабраэффект у бота?


    1. SergeyDeryabin
      06.12.2022 04:01
      +1

      А, просто из Клинта когда открываешь, только одна кнопка - старт и по ней нет никакого ответа и описания нет. И текст в меню выводить не надо наверное, команда отправляется пустая сразу


      1. ternaus Автор
        06.12.2022 04:16

        Не, и правда не работает. Через час дома буду поправлю. Хостинг на Heroku неустойчивый какой-то.

        Вообще я пытался на AWS Lambda задеплоить, но прямоты рук не хватило. Тупо названия Secret Token у телеграмма и Lambda по разному называются, а прослойку написать, которая подменяет одно на другое прямоты рук не хватило.


    1. ternaus Автор
      06.12.2022 06:46

      Работает, можно тыкать.


      1. sunnybear
        06.12.2022 08:11

        Не работает. Видимо, нужно ещё технических навыков подкачать :)


        1. ternaus Автор
          06.12.2022 08:17

          Проверил, все работает.

          /text TEXT_QUERY

          или просто загрузить картинку.

          Но пару багов я и правда нашел. :)


  1. Grynder
    06.12.2022 13:48

    https://www.ternaus.com/search/?text=санкт-петербург+метро

    Ерунду какую-то показывает :)

    Hidden text


    1. ternaus Автор
      07.12.2022 02:07

      Тут две проблемы:

      1. Модель, которая извлекает эмбединги, из текста не поддерживает русский.

      2. В базе данных картинки связянные с Россией, да и вообще восточной Европой представлены плохо.

      Обе проблемы решаемые, но не очень приоритетные.

      Хотя я записываю, что люди текстами ищут, на зимних, возможно нагенерирую картинок в базу данных по этим запросам.

      Хотя, чаще всего идут запросы на обнаженных девушек и их части тела, а их генерировать сложнее.


    1. nikolay_karelin
      08.12.2022 17:50
      +1

      На английском сносный результат ;)

      И почему-то на запрос Minsk metro вылазят Джокер и Байден... ИИ явно что-то знает


      1. ternaus Автор
        09.12.2022 00:02

        Идея добавить поддержку других языков не такая и плохая.

        Сделаю.


  1. skiffin
    07.12.2022 02:02

    Жаль что кусок про деньги вырезан. Было бы интересно посмотреть как это настраивается


    1. ternaus Автор
      07.12.2022 02:04

      Если руки дойдут, то выложу всего бота на GitHub.

      Там не очень сложно. Интеграция через Stripe на попоплнение.

      MongoDb для подсчета запросов.

      И немного логики в самом боте, чтобы проверять число доступных запросов и увеличивать счетчик.

      Stripe имеет ограниченное хождение в мире - это минус, но раз и так никто не платит - пусть будет пока только Stripe.