defmodule AlgoraWeb.COSSGPTOGLive do use AlgoraWeb, :live_view alias Algora.{Library, ML, Cache, Util} @impl true def render(assigns) do ~H"""

COSSgpt

Suggestions
<.link navigate={video_url(video, Enum.at(segments, 0))} class="w-full shrink-0 max-w-[40rem]" > <.video_thumbnail video={video} class="w-full rounded-2xl" />
<.link navigate={video_url(video, Enum.at(segments, 0))} class="text-lg font-bold line-clamp-2" > <%= video.title %>

<%= Timex.from_now(video.inserted_at) %>

<.link navigate={"/#{video.channel_handle}"} class="mt-2 flex items-center gap-2"> {video.channel_name} <%= video.channel_name %>
<.link :for={segment <- segments} class="space-x-2" navigate={video_url(video, segment)} >

<%= Library.to_hhmmss(segment.start) %>

String.split(~r/\s/)} class={[matches_query?(@query_words, word) && "text-green-300 font-medium"]} > <%= word %>

""" end defp video_url(video, segment) do params = case segment do nil -> "" s -> "?t=#{trunc(s.start)}" end "/#{video.channel_handle}/#{video.id}#{params}" end @impl true def mount(_params, _session, socket) do {:ok, socket} end @impl true def handle_params(params, _url, socket) do {:noreply, socket |> apply_action(socket.assigns.live_action, params)} end @impl true def handle_event("search", %{"query" => query}, socket) do {:noreply, socket |> push_patch(to: ~p"/og/cossgpt?#{%{query: query}}")} end @impl true def handle_info({ref, result}, socket) when socket.assigns.task.ref == ref do {:noreply, assign(socket, task: nil, results: result)} end def handle_info(_, socket) do {:noreply, socket} end defp apply_action(socket, :index, params) do socket = case params["query"] || "" do "" -> socket |> assign( query: nil, query_words: nil, task: nil, results: nil ) query -> socket |> assign( query: query, query_words: query |> String.split(~r/\s/) |> Enum.map(&normalize_word/1), task: Task.async(fn -> fetch_results(query) end), results: nil ) end socket |> assign(:page_title, "COSSgpt") end defp fetch_results(query) do [%{"embedding" => embedding}] = Cache.fetch("embeddings/#{Slug.slugify(query)}", fn -> ML.create_embedding(query) end) index = ML.load_index!() segments = ML.get_relevant_chunks(index, embedding) to_result = fn video -> %{ video: video, segments: segments |> Enum.filter(fn s -> s.video_id == video.id end) } end segments |> Enum.map(fn %Library.Segment{video_id: video_id} -> video_id end) |> Enum.uniq() |> Library.list_videos_by_ids() |> Enum.map(to_result) end defp normalize_word(s) do s |> String.replace(~r/[^A-Za-z0-9]/, "") |> String.downcase() end defp matches_query?(query_words, s) do query_words |> Enum.any?(fn s2 -> s1 = normalize_word(s) String.length(s1) >= 3 and String.length(s2) >= 3 and (String.contains?(s1, s2) or String.contains?(s2, s1)) and !Util.common_word?(s1) and !Util.common_word?(s2) end) end end