359 lines
9.3 KiB
Elixir
359 lines
9.3 KiB
Elixir
```elixir title="Elixir"
|
|
# Unregister individual plugins from the registry
|
|
|
|
defmodule MyApp.Plugins.UnregisterExample do
|
|
@moduledoc """
|
|
Example plugins to demonstrate selective unregistration.
|
|
"""
|
|
|
|
# Email processor post-processor
|
|
defmodule EmailPostProcessor do
|
|
@behaviour Kreuzberg.Plugin.PostProcessor
|
|
|
|
@impl true
|
|
def name, do: "email_processor"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def processing_stage, do: :middle
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def process(result, _config) do
|
|
# Extract emails from content
|
|
emails =
|
|
result
|
|
|> Map.get("content", "")
|
|
|> String.scan(~r/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/)
|
|
|> Enum.map(&List.first/1)
|
|
|> Enum.uniq()
|
|
|
|
Map.put(result, "extracted_emails", emails)
|
|
end
|
|
end
|
|
|
|
# Phone number processor post-processor
|
|
defmodule PhonePostProcessor do
|
|
@behaviour Kreuzberg.Plugin.PostProcessor
|
|
|
|
@impl true
|
|
def name, do: "phone_processor"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def processing_stage, do: :middle
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def process(result, _config) do
|
|
# Extract phone numbers from content
|
|
phones =
|
|
result
|
|
|> Map.get("content", "")
|
|
|> String.scan(~r/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/)
|
|
|> Enum.map(&List.first/1)
|
|
|> Enum.uniq()
|
|
|
|
Map.put(result, "extracted_phones", phones)
|
|
end
|
|
end
|
|
|
|
# URL processor post-processor
|
|
defmodule URLPostProcessor do
|
|
@behaviour Kreuzberg.Plugin.PostProcessor
|
|
|
|
@impl true
|
|
def name, do: "url_processor"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def processing_stage, do: :middle
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def process(result, _config) do
|
|
# Extract URLs from content
|
|
urls =
|
|
result
|
|
|> Map.get("content", "")
|
|
|> String.scan(~r/https?:\/\/\S+/)
|
|
|> Enum.map(&List.first/1)
|
|
|> Enum.uniq()
|
|
|
|
Map.put(result, "extracted_urls", urls)
|
|
end
|
|
end
|
|
|
|
# Strict length validator
|
|
defmodule StrictLengthValidator do
|
|
@behaviour Kreuzberg.Plugin.Validator
|
|
|
|
@impl true
|
|
def name, do: "strict_length_validator"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def priority, do: 100
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def should_validate?(%{"content" => content}) do
|
|
is_binary(content)
|
|
end
|
|
|
|
def should_validate?(_), do: false
|
|
|
|
@impl true
|
|
def validate(%{"content" => content}) do
|
|
min_length = 10
|
|
max_length = 10000
|
|
|
|
cond do
|
|
byte_size(content) < min_length ->
|
|
{:error, "Content too short (minimum #{min_length} bytes)"}
|
|
|
|
byte_size(content) > max_length ->
|
|
{:error, "Content too long (maximum #{max_length} bytes)"}
|
|
|
|
true ->
|
|
:ok
|
|
end
|
|
end
|
|
|
|
def validate(_), do: {:error, "Missing content field"}
|
|
end
|
|
|
|
# Encoding validator
|
|
defmodule EncodingValidator do
|
|
@behaviour Kreuzberg.Plugin.Validator
|
|
|
|
@impl true
|
|
def name, do: "encoding_validator"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def priority, do: 50
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def should_validate?(%{"content" => content}) do
|
|
is_binary(content)
|
|
end
|
|
|
|
def should_validate?(_), do: false
|
|
|
|
@impl true
|
|
def validate(%{"content" => content}) do
|
|
if String.valid?(content) do
|
|
:ok
|
|
else
|
|
{:error, "Content contains invalid UTF-8 encoding"}
|
|
end
|
|
end
|
|
|
|
def validate(_), do: {:error, "Missing content field"}
|
|
end
|
|
|
|
# Basic OCR backend
|
|
defmodule BasicOCR do
|
|
@behaviour Kreuzberg.Plugin.OcrBackend
|
|
|
|
@impl true
|
|
def name, do: "basic_ocr"
|
|
|
|
@impl true
|
|
def version, do: "1.0.0"
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def supported_languages, do: ["eng", "fra"]
|
|
|
|
@impl true
|
|
def process_image(_image_data, language) do
|
|
if language in supported_languages() do
|
|
{:ok, "Extracted text"}
|
|
else
|
|
{:error, "Unsupported language"}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def process_file(_path, language) do
|
|
if language in supported_languages() do
|
|
{:ok, "Extracted file text"}
|
|
else
|
|
{:error, "Unsupported language"}
|
|
end
|
|
end
|
|
end
|
|
|
|
# Advanced OCR backend
|
|
defmodule AdvancedOCR do
|
|
@behaviour Kreuzberg.Plugin.OcrBackend
|
|
|
|
@impl true
|
|
def name, do: "advanced_ocr"
|
|
|
|
@impl true
|
|
def version, do: "2.0.0"
|
|
|
|
@impl true
|
|
def initialize, do: :ok
|
|
|
|
@impl true
|
|
def shutdown, do: :ok
|
|
|
|
@impl true
|
|
def supported_languages do
|
|
[
|
|
"eng",
|
|
"fra",
|
|
"deu",
|
|
"spa",
|
|
"ita",
|
|
"jpn",
|
|
"chi",
|
|
"chi_tra",
|
|
"kor"
|
|
]
|
|
end
|
|
|
|
@impl true
|
|
def process_image(_image_data, language) do
|
|
if language in supported_languages() do
|
|
{:ok, "Advanced extracted text"}
|
|
else
|
|
{:error, "Unsupported language"}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def process_file(_path, language) do
|
|
if language in supported_languages() do
|
|
{:ok, "Advanced extracted file text"}
|
|
else
|
|
{:error, "Unsupported language"}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
IO.puts("=== Plugin Unregistration Example ===\n")
|
|
|
|
# Register multiple plugins of each type
|
|
IO.puts("Registering plugins...")
|
|
:ok = Kreuzberg.Plugin.register_post_processor(:emails, MyApp.Plugins.UnregisterExample.EmailPostProcessor)
|
|
:ok = Kreuzberg.Plugin.register_post_processor(:phones, MyApp.Plugins.UnregisterExample.PhonePostProcessor)
|
|
:ok = Kreuzberg.Plugin.register_post_processor(:urls, MyApp.Plugins.UnregisterExample.URLPostProcessor)
|
|
|
|
:ok = Kreuzberg.Plugin.register_validator(MyApp.Plugins.UnregisterExample.StrictLengthValidator)
|
|
:ok = Kreuzberg.Plugin.register_validator(MyApp.Plugins.UnregisterExample.EncodingValidator)
|
|
|
|
:ok = Kreuzberg.Plugin.register_ocr_backend(MyApp.Plugins.UnregisterExample.BasicOCR)
|
|
:ok = Kreuzberg.Plugin.register_ocr_backend(MyApp.Plugins.UnregisterExample.AdvancedOCR)
|
|
|
|
# List all registered plugins
|
|
{:ok, procs} = Kreuzberg.Plugin.list_post_processors()
|
|
{:ok, vals} = Kreuzberg.Plugin.list_validators()
|
|
{:ok, backends} = Kreuzberg.Plugin.list_ocr_backends()
|
|
|
|
IO.puts("Initial registration:")
|
|
IO.puts(" Post-processors: #{length(procs)} - #{inspect(Enum.map(procs, &elem(&1, 0)))}")
|
|
IO.puts(" Validators: #{length(vals)} - #{inspect(Enum.map(vals, &(elem(&1, :__struct__) || &1.name())))}")
|
|
IO.puts(" OCR backends: #{length(backends)} - #{inspect(Enum.map(backends, &(elem(&1, :__struct__) || &1.name())))}\n")
|
|
|
|
# Unregister individual post-processor
|
|
IO.puts("Unregistering post-processor ':phones'...")
|
|
:ok = Kreuzberg.Plugin.unregister_post_processor(:phones)
|
|
{:ok, procs_after1} = Kreuzberg.Plugin.list_post_processors()
|
|
IO.puts("Post-processors: #{length(procs_after1)} - #{inspect(Enum.map(procs_after1, &elem(&1, 0)))}\n")
|
|
|
|
# Unregister another post-processor
|
|
IO.puts("Unregistering post-processor ':urls'...")
|
|
:ok = Kreuzberg.Plugin.unregister_post_processor(:urls)
|
|
{:ok, procs_after2} = Kreuzberg.Plugin.list_post_processors()
|
|
IO.puts("Post-processors: #{length(procs_after2)} - #{inspect(Enum.map(procs_after2, &elem(&1, 0)))}\n")
|
|
|
|
# Unregister a validator
|
|
IO.puts("Unregistering validator 'EncodingValidator'...")
|
|
:ok = Kreuzberg.Plugin.unregister_validator(MyApp.Plugins.UnregisterExample.EncodingValidator)
|
|
{:ok, vals_after} = Kreuzberg.Plugin.list_validators()
|
|
IO.puts("Validators: #{length(vals_after)}\n")
|
|
|
|
# Unregister an OCR backend
|
|
IO.puts("Unregistering OCR backend 'BasicOCR'...")
|
|
:ok = Kreuzberg.Plugin.unregister_ocr_backend(MyApp.Plugins.UnregisterExample.BasicOCR)
|
|
{:ok, backends_after} = Kreuzberg.Plugin.list_ocr_backends()
|
|
IO.puts("OCR backends: #{length(backends_after)}\n")
|
|
|
|
# Idempotent unregistration - unregistering non-existent plugin
|
|
IO.puts("Unregistering already-unregistered plugin ':phones' (idempotent)...")
|
|
:ok = Kreuzberg.Plugin.unregister_post_processor(:phones)
|
|
IO.puts("Still returns :ok\n")
|
|
|
|
# Final state
|
|
IO.puts("=== Final State ===")
|
|
{:ok, final_procs} = Kreuzberg.Plugin.list_post_processors()
|
|
{:ok, final_vals} = Kreuzberg.Plugin.list_validators()
|
|
{:ok, final_backends} = Kreuzberg.Plugin.list_ocr_backends()
|
|
|
|
IO.puts("Remaining post-processors: #{length(final_procs)}")
|
|
IO.puts("Remaining validators: #{length(final_vals)}")
|
|
IO.puts("Remaining OCR backends: #{length(final_backends)}\n")
|
|
|
|
# Cleanup - unregister remaining plugins
|
|
IO.puts("=== Cleanup ===")
|
|
:ok = Kreuzberg.Plugin.unregister_post_processor(:emails)
|
|
:ok = Kreuzberg.Plugin.unregister_validator(MyApp.Plugins.UnregisterExample.StrictLengthValidator)
|
|
:ok = Kreuzberg.Plugin.unregister_ocr_backend(MyApp.Plugins.UnregisterExample.AdvancedOCR)
|
|
|
|
{:ok, final_clean_procs} = Kreuzberg.Plugin.list_post_processors()
|
|
{:ok, final_clean_vals} = Kreuzberg.Plugin.list_validators()
|
|
{:ok, final_clean_backends} = Kreuzberg.Plugin.list_ocr_backends()
|
|
|
|
IO.puts("After cleanup:")
|
|
IO.puts(" Post-processors: #{length(final_clean_procs)}")
|
|
IO.puts(" Validators: #{length(final_clean_vals)}")
|
|
IO.puts(" OCR backends: #{length(final_clean_backends)}")
|
|
```
|