Packages
fnord
0.5.0
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/store/note.ex
defmodule Store.Note do
defstruct [
:project,
:store_path,
:id
]
@store_dir "notes"
# ----------------------------------------------------------------------------
# Instance functions
# ----------------------------------------------------------------------------
def new(project), do: new(project, UUID.uuid4())
def new(project, nil), do: new(project, UUID.uuid4())
def new(project, id) do
%__MODULE__{
project: project,
store_path: build_store_path(project, id),
id: id
}
end
def exists?(note) do
File.exists?(note.store_path)
end
def write(note, text) do
# Ensure the note's store path exists.
note.store_path
|> File.mkdir_p!()
# Has the note changed since the last save?
is_changed? =
with {:ok, orig} <- read_note(note) do
orig != text
else
_ -> true
end
if is_changed? do
# Write the note's text to the note's store path.
note.store_path
|> Path.join("note.md")
|> File.write!(text)
# Generate and save embeddings for the note.
embeddings_json =
text
|> generate_embeddings!()
|> Jason.encode!()
note.store_path
|> Path.join("embeddings.json")
|> File.write!(embeddings_json)
end
end
def read(note) do
with {:ok, text} <- read_note(note),
{:ok, embeddings} <- read_embeddings(note) do
{:ok,
%{
id: note.id,
text: text,
embeddings: embeddings
}}
end
end
def read_note(note) do
note.store_path
|> Path.join("note.md")
|> File.read()
end
def read_embeddings(note) do
note.store_path
|> Path.join("embeddings.json")
|> File.read()
|> case do
{:ok, json} -> Jason.decode(json)
error -> error
end
end
# ----------------------------------------------------------------------------
# Common functions
# ----------------------------------------------------------------------------
def list_notes(project) do
project.store_path
|> Path.join(@store_dir)
|> File.ls()
|> case do
{:ok, dirs} ->
dirs
|> Enum.sort()
|> Enum.map(&new(project, &1))
_ ->
[]
end
end
def search(project, query, max_results \\ 20) do
needle = generate_embeddings!(query)
list_notes(project)
|> Enum.reduce([], fn note, acc ->
with {:ok, embeddings} <- read_embeddings(note) do
score = AI.Util.cosine_similarity(needle, embeddings)
[{score, note} | acc]
else
_ -> acc
end
end)
|> Enum.sort(fn {a, _}, {b, _} -> a >= b end)
|> Enum.take(max_results)
end
def reset_project_notes(project) do
project
|> build_store_path()
|> File.rm_rf()
end
# ----------------------------------------------------------------------------
# Private functions
# ----------------------------------------------------------------------------
defp build_store_path(project) do
project.store_path
|> Path.join(@store_dir)
end
defp build_store_path(project, id) do
project
|> build_store_path()
|> Path.join(id)
end
defp generate_embeddings!(text) do
AI.new()
|> AI.get_embeddings(text)
|> case do
{:ok, embeddings} -> Enum.zip_with(embeddings, &Enum.max/1)
{:error, reason} -> raise "Failed to generate embeddings: #{inspect(reason)}"
end
end
end