Packages

fnord

0.5.1

AI code archaeology

Current section

Files

Jump to
fnord lib store project note.ex
Raw

lib/store/project/note.ex

defmodule Store.Project.Note do
defstruct [
:project,
:store_path,
:id
]
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: Path.join(project.notes_dir, id),
id: id
}
end
def exists?(note) do
File.exists?(note.store_path)
end
def write(note, text) do
if is_valid_format?(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
|> AI.Util.generate_embeddings!()
|> Jason.encode!()
note.store_path
|> Path.join("embeddings.json")
|> File.write(embeddings_json)
end
else
{:error, :invalid_format}
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
def is_valid_format?(note_text) do
note_text
|> parse_string()
|> case do
{:ok, _parsed} -> true
{:error, :invalid_format} -> false
end
end
def parse(note) do
with {:ok, text} <- read_note(note) do
parse_string(text)
end
end
def parse_string(note_text) do
try do
{:ok, parse_topic(note_text)}
rescue
_ -> {:error, :invalid_format}
end
end
defp parse_topic(input_str) do
[topic, rest] =
input_str
|> String.trim()
|> String.trim_leading("{")
|> String.trim_trailing("}")
|> String.trim()
|> String.trim_leading("topic ")
|> String.split("{", parts: 2)
|> Enum.map(&String.trim/1)
facts = parse_facts("{#{rest}")
{topic, facts}
end
defp parse_facts(input_str) do
input_str
|> String.trim()
|> String.trim_leading("{")
|> String.trim_trailing("}")
|> String.split("} {")
|> Enum.map(&parse_fact/1)
end
defp parse_fact(input_str) do
input_str
|> String.trim()
|> String.trim_leading("fact ")
|> String.trim()
end
end