-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
放弃在 save_it bot 添加 notes 功能,保持 save_it 简单 #22
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# 2024-10-25 | ||
|
||
## Req call typesense API alway :timeout, but typesense was updated. | ||
|
||
```elixir | ||
** (MatchError) no match of right hand side value: {:error, %Req.TransportError{reason: :timeout}} | ||
(save_it 0.2.0-rc.1) lib/migration/typesense.ex:11: Migration.Typesense.create_collection!/1 | ||
priv/typesense/reset.exs:3: (file) | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Typesense | ||
|
||
## Typesense API Errors | ||
|
||
``` | ||
# 400 Bad Request - The request could not be understood due to malformed syntax. | ||
# 401 Unauthorized - Your API key is wrong. | ||
# 404 Not Found - The requested resource is not found. | ||
# 409 Conflict - When a resource already exists. | ||
# 422 Unprocessable Entity - Request is well-formed, but cannot be processed. | ||
# 503 Service Unavailable - We’re temporarily offline. Please try again later. | ||
``` | ||
|
||
docs: https://typesense.org/docs/27.1/api/api-errors.html#api-errors |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,42 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defmodule Migration.Typesense do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def create_collection!(schema) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req = build_request("/collections") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{:ok, res} = Req.post(req, json: schema) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def delete_collection!(collection_name) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req = build_request("/collections/#{collection_name}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{:ok, res} = Req.delete(req) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def list_collections() do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req = build_request("/collections") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{:ok, res} = Req.get(req) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defp get_env() do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
url = Application.fetch_env!(:save_it, :typesense_url) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
api_key = Application.fetch_env!(:save_it, :typesense_api_key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{url, api_key} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+23
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider safer environment variable handling. The Consider using defp get_env() do
- url = Application.fetch_env!(:save_it, :typesense_url)
- api_key = Application.fetch_env!(:save_it, :typesense_api_key)
-
- {url, api_key}
+ with {:ok, url} <- get_config(:typesense_url),
+ {:ok, api_key} <- get_config(:typesense_api_key) do
+ {:ok, {url, api_key}}
+ end
end
+ defp get_config(key) do
+ case Application.get_env(:save_it, key) do
+ nil -> {:error, "Missing configuration: #{key}"}
+ value when byte_size(value) > 0 -> {:ok, value}
+ _ -> {:error, "Invalid configuration: #{key}"}
+ end
+ end
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defp build_request(path) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{url, api_key} = get_env() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Req.new( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
base_url: url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
url: path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
headers: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{"Content-Type", "application/json"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{"X-TYPESENSE-API-KEY", api_key} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+30
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add request timeout configuration and consider making headers configurable. The request configuration could be improved with timeout settings and more flexible header configuration. Consider these improvements: defp build_request(path) do
- {url, api_key} = get_env()
+ with {:ok, {url, api_key}} <- get_env() do
+ Req.new(
+ base_url: url,
+ url: path,
+ headers: build_headers(api_key),
+ connect_options: [timeout: get_timeout()],
+ retry: :transient
+ )
+ end
end
+ defp build_headers(api_key) do
+ [
+ {"Content-Type", "application/json"},
+ {"X-TYPESENSE-API-KEY", api_key}
+ ]
+ end
+ defp get_timeout do
+ Application.get_env(:save_it, :typesense_timeout, 5000)
+ end 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
defmodule Migration.Typesense.Note do | ||
alias Migration.Typesense | ||
|
||
@notes_schema %{ | ||
"name" => "notes", | ||
"fields" => [ | ||
# TODO: 第一步先实现文本,今后再考虑图片 | ||
%{"name" => "content", "type" => "string"}, | ||
# references photos.id | ||
# note: 抉择:这个 app 核心是给予图片的视觉笔记,暂时不考虑单独 text 的笔记 | ||
# %{"name" => "photo_id", "type" => "string"}, | ||
# note: 既然不能实现 RDB reference,那么就直接存储 file_id | ||
%{"name" => "message_id", "type" => "string"}, | ||
%{"name" => "file_id", "type" => "string"}, | ||
%{"name" => "belongs_to_id", "type" => "string"}, | ||
%{"name" => "inserted_at", "type" => "int64"}, | ||
%{"name" => "updated_at", "type" => "int64"} | ||
], | ||
"default_sorting_field" => "inserted_at" | ||
} | ||
|
||
def create_collection!() do | ||
Typesense.create_collection!(@notes_schema) | ||
end | ||
|
||
def reset!() do | ||
Typesense.delete_collection!(@notes_schema["name"]) | ||
Typesense.create_collection!(@notes_schema) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,35 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defmodule Migration.Typesense.Photo do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
alias Migration.Typesense | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@photos_schema %{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"name" => "photos", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"fields" => [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# image: base64 encoded string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{"name" => "image", "type" => "image", "store" => false}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"name" => "image_embedding", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"type" => "float[]", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"embed" => %{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"from" => ["image"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"model_config" => %{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"model_name" => "ts/clip-vit-b-p32" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{"name" => "caption", "type" => "string", "optional" => true, "facet" => false}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{"name" => "file_id", "type" => "string"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{"name" => "belongs_to_id", "type" => "string"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%{"name" => "inserted_at", "type" => "int64"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"default_sorting_field" => "inserted_at" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def create_collection!() do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Typesense.create_collection!(@photos_schema) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def reset!() do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Typesense.delete_collection!(@photos_schema["name"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Typesense.create_collection!(@photos_schema) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+27
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add documentation and error handling. The public functions need:
Consider this improvement: + @doc """
+ Creates a new photos collection in Typesense.
+
+ Returns `:ok` on success, or raises an error if the collection already exists
+ or if there's a connection issue.
+ """
+ @spec create_collection!() :: :ok | no_return()
def create_collection!() do
- Typesense.create_collection!(@photos_schema)
+ case Typesense.create_collection!(@photos_schema) do
+ {:ok, _} -> :ok
+ {:error, %{"message" => message}} -> raise "Failed to create collection: #{message}"
+ end
end
+ @doc """
+ Resets the photos collection by deleting and recreating it.
+
+ Returns `:ok` on success, or raises an error if the operations fail.
+ """
+ @spec reset!() :: :ok | no_return()
def reset!() do
- Typesense.delete_collection!(@photos_schema["name"])
- Typesense.create_collection!(@photos_schema)
+ with :ok <- Typesense.delete_collection!(@photos_schema["name"]),
+ :ok <- create_collection!() do
+ :ok
+ end
end 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add proper error handling and documentation for public functions.
The public API functions have several areas for improvement:
{:ok, res}
), but network issues or API errors could occur.@doc
and@spec
annotations.Here's a suggested improvement:
Add these private validation functions:
Also applies to: 9-14, 16-21