Packages
phoenix_kit
1.7.90
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/llm_text/file_storage.ex
defmodule PhoenixKit.Modules.LLMText.FileStorage do
@moduledoc """
File-based storage for LLM text files.
Stores files under the host app's `priv/static/llms/` directory:
priv/static/llms/llms.txt -> index file
priv/static/llms/page.md -> individual page file
priv/static/llms/posts/article.md -> nested page file
## Test Override
Set `Application.put_env(:phoenix_kit, :llm_text_test_storage_dir, "/tmp/...")` to
override the storage directory in tests.
"""
require Logger
@index_filename "llms.txt"
@doc """
Returns the root storage directory for LLM text files.
Uses test override if configured, otherwise resolves to the host app's
`priv/static/llms/` directory.
"""
@spec storage_dir() :: String.t()
def storage_dir do
case Application.get_env(:phoenix_kit, :llm_text_test_storage_dir) do
nil -> resolve_storage_dir()
dir -> dir
end
end
@doc """
Returns the path to the llms.txt index file.
"""
@spec index_path() :: String.t()
def index_path do
Path.join(storage_dir(), @index_filename)
end
@doc """
Returns the full path for a relative file path within the storage directory.
"""
@spec file_path(String.t()) :: String.t()
def file_path(relative_path) when is_binary(relative_path) do
Path.join(storage_dir(), relative_path)
end
@doc """
Writes content to a file at the given relative path, creating directories as needed.
"""
@spec write(String.t(), String.t()) :: :ok | {:error, term()}
def write(relative_path, content) when is_binary(relative_path) and is_binary(content) do
path = file_path(relative_path)
with :ok <- ensure_directory_exists(path),
:ok <- File.write(path, content) do
Logger.debug("LLMText.FileStorage: Wrote #{relative_path} (#{byte_size(content)} bytes)")
:ok
else
{:error, reason} = error ->
Logger.warning(
"LLMText.FileStorage: Failed to write #{relative_path}: #{inspect(reason)}"
)
error
end
end
@doc """
Writes the llms.txt index file.
"""
@spec write_index(String.t()) :: :ok | {:error, term()}
def write_index(content) when is_binary(content) do
path = index_path()
with :ok <- ensure_directory_exists(path),
:ok <- File.write(path, content) do
Logger.debug("LLMText.FileStorage: Wrote llms.txt (#{byte_size(content)} bytes)")
:ok
else
{:error, reason} = error ->
Logger.warning("LLMText.FileStorage: Failed to write llms.txt: #{inspect(reason)}")
error
end
end
@doc """
Deletes a file at the given relative path. Returns :ok if file does not exist.
"""
@spec delete(String.t()) :: :ok
def delete(relative_path) when is_binary(relative_path) do
path = file_path(relative_path)
case File.rm(path) do
:ok ->
Logger.debug("LLMText.FileStorage: Deleted #{relative_path}")
:ok
{:error, :enoent} ->
:ok
{:error, reason} ->
Logger.warning(
"LLMText.FileStorage: Failed to delete #{relative_path}: #{inspect(reason)}"
)
:ok
end
end
@doc """
Checks if a file at the given relative path exists.
"""
@spec exists?(String.t()) :: boolean()
def exists?(relative_path) when is_binary(relative_path) do
relative_path |> file_path() |> File.exists?()
end
@doc """
Deletes the entire storage directory and all its contents.
"""
@spec delete_all() :: :ok
def delete_all do
dir = storage_dir()
case File.rm_rf(dir) do
{:ok, _} ->
Logger.debug("LLMText.FileStorage: Deleted all files in #{dir}")
:ok
{:error, reason, _path} ->
Logger.warning("LLMText.FileStorage: Failed to delete storage dir: #{inspect(reason)}")
:ok
end
rescue
_ -> :ok
end
# Private helpers
defp resolve_storage_dir do
otp_app = PhoenixKit.Config.get(:otp_app, :phoenix_kit)
priv_dir =
case :code.priv_dir(otp_app) do
{:error, :bad_name} ->
case :code.priv_dir(:phoenix_kit) do
{:error, :bad_name} -> "priv"
dir -> to_string(dir)
end
dir ->
to_string(dir)
end
Path.join([priv_dir, "static", "llms"])
end
defp ensure_directory_exists(file_path) do
dir = Path.dirname(file_path)
case File.mkdir_p(dir) do
:ok -> :ok
{:error, reason} -> {:error, {:mkdir_failed, reason}}
end
end
end