summaryrefslogtreecommitdiff
path: root/lib/plugins/link/image.ex
blob: 2fb6862689d1d1e389d898690f7ca801e115c2f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
defmodule Nola.Plugins.Link.Image do
  require Logger
  @behaviour Nola.Plugins.Link

  @impl true
  def match(_, _), do: false

  @impl true
  def post_match(_url, "image/" <> _, _header, _opts) do
    {:body, nil}
  end

  def post_match(_, _, _, _), do: false

  @impl true
  def post_expand(_url, bytes, _, opts) do
    pil_process = Keyword.get(opts, :pil_process, {:pil, :"py@127.0.0.1"})
    clip_ask_process = Keyword.get(opts, :clip_ask_process, {:clip_ask, :"py@127.0.0.1"})

    img2txt_process =
      Keyword.get(opts, :img2txt_process, {:image_to_text_vit_gpt2, :"py@127.0.0.1"})

    tasks =
      [
        Task.async(fn ->
          {:ok, pil} = GenServer.call(pil_process, {:run, bytes})

          pil =
            pil
            |> Enum.map(fn {k, v} -> {String.to_atom(to_string(k)), v} end)

          pil
        end),
        Task.async(fn ->
          {:ok, descr} = GenServer.call(img2txt_process, {:run, bytes})
          {:img2txt, to_string(descr)}
        end),
        Task.async(fn ->
          {:ok, prompts} = GenServer.call(clip_ask_process, {:run, bytes})

          prompts =
            prompts
            |> Enum.sort_by(&elem(&1, 1), &>=/2)
            |> Enum.take(3)
            |> Enum.map(&to_string(elem(&1, 0)))
            |> Enum.join(", ")

          {:prompts, prompts}
        end)
      ]
      |> Task.yield_many(5000)
      |> Enum.map(fn {task, res} ->
        res || Task.shutdown(task, :brutal_kill)
      end)

    results = Enum.into(List.flatten(for({:ok, value} <- tasks, do: value)), Map.new())
    img2txt = Map.get(results, :img2txt)
    prompts = Map.get(results, :prompts)

    pil =
      if Map.get(results, :width) do
        animated = if Map.get(results, :animated), do: " animated", else: ""
        "#{Map.get(results, :width, 0)}x#{Map.get(results, :height, 0)}#{animated} — "
      else
        ""
      end

    descr =
      cond do
        img2txt && prompts ->
          "#{pil}#{prompts}#{img2txt}"

        img2txt ->
          "#{pil}#{img2txt}"

        prompts ->
          "#{pil}#{prompts}"

        pil != "" ->
          "#{pil}"

        true ->
          nil
      end

    if descr do
      {:ok, "image: #{descr}"}
    else
      :error
    end
  end
end