Compare commits
17 Commits
main
...
jpd-add-pa
Author | SHA1 | Date | |
---|---|---|---|
1818f0aa5c | |||
ad42565cbc | |||
82ace08303 | |||
f4e4181785 | |||
61e9ae73bd | |||
1b0f9a338a | |||
1c56398e21 | |||
adc39dc755 | |||
e76aaf999e | |||
a2d356dd3c | |||
0266a7ec35 | |||
50a2822eeb | |||
|
acbfc3e45c | ||
|
8c69de4529 | ||
|
1b96d3aebc | ||
|
d355f46856 | ||
|
e1ceef6409 |
22
.editorconfig
Normal file
22
.editorconfig
Normal file
@ -0,0 +1,22 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{css,html,js,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{ex,exs}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -96,3 +96,6 @@ erl_crash.dump
|
||||
*.beam
|
||||
config/*.secret.exs
|
||||
elixir_ls/
|
||||
|
||||
# ---> Project
|
||||
config/data/addresses.csv
|
||||
|
@ -1,5 +1,5 @@
|
||||
erlang 26.2.1
|
||||
elixir 1.16.0-otp-26
|
||||
poetry 1.7.1
|
||||
python 3.12.1
|
||||
go 1.21.6
|
||||
erlang 27.0.1
|
||||
elixir 1.17.2-otp-27
|
||||
poetry 1.8.3
|
||||
python 3.12.5
|
||||
go 1.22.6
|
||||
|
28
Dockerfile
28
Dockerfile
@ -1,4 +1,4 @@
|
||||
FROM debian:bookworm-20240110-slim AS builder
|
||||
FROM debian:bookworm-20240722-slim AS builder
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
autoconf \
|
||||
@ -10,14 +10,18 @@ RUN apt-get update \
|
||||
pkg-config \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /opt/src
|
||||
RUN git clone https://github.com/openvenues/libpostal.git \
|
||||
RUN git config --global http.version HTTP/1.1 \
|
||||
&& git config --global http.postBuffer 524288000 \
|
||||
&& git config --global http.lowSpeedLimit 0 \
|
||||
&& git config --global http.lowSpeedTime 999999 \
|
||||
&& git clone https://github.com/openvenues/libpostal.git \
|
||||
&& cd libpostal \
|
||||
&& ./bootstrap.sh \
|
||||
&& ./configure --datadir=/usr/local/share \
|
||||
&& make -j4 \
|
||||
&& make install
|
||||
|
||||
FROM hexpm/elixir:1.16.0-erlang-26.2.1-debian-bookworm-20231009-slim AS elixir
|
||||
FROM hexpm/elixir:1.17.2-erlang-27.0.1-debian-bookworm-20240722-slim AS elixir
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
@ -31,13 +35,14 @@ COPY --from=builder /usr/local/lib/pkgconfig/libpostal.pc /usr/local/lib/pkgconf
|
||||
COPY --from=builder /usr/local/share/libpostal /usr/local/share/libpostal
|
||||
COPY --from=builder /usr/local/bin/libpostal_data /usr/local/bin/libpostal_data
|
||||
RUN ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so.1 \
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so \
|
||||
&& ldconfig
|
||||
WORKDIR /opt/src/app
|
||||
VOLUME ["/opt/src/app/_build", "/opt/src/app/deps"]
|
||||
COPY ./ex .
|
||||
RUN mix do deps.get, deps.compile
|
||||
|
||||
FROM python:3.12.1-slim-bookworm AS python
|
||||
FROM python:3.12.5-slim-bookworm AS python
|
||||
ENV PATH /root/.local/bin:${PATH}
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
@ -53,14 +58,15 @@ COPY --from=builder /usr/local/lib/pkgconfig/libpostal.pc /usr/local/lib/pkgconf
|
||||
COPY --from=builder /usr/local/share/libpostal /usr/local/share/libpostal
|
||||
COPY --from=builder /usr/local/bin/libpostal_data /usr/local/bin/libpostal_data
|
||||
RUN ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so.1 \
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so \
|
||||
&& ldconfig
|
||||
WORKDIR /opt/src/app
|
||||
COPY ./py/pyproject.toml .
|
||||
COPY ./py/poetry.lock .
|
||||
RUN poetry install
|
||||
COPY ./py .
|
||||
|
||||
FROM golang:1.21.6-bookworm AS go
|
||||
FROM golang:1.22.6-bookworm AS go
|
||||
COPY --from=builder /usr/local/include/libpostal /usr/local/include/libpostal
|
||||
COPY --from=builder /usr/local/lib/libpostal.a /usr/local/lib/
|
||||
COPY --from=builder /usr/local/lib/libpostal.la /usr/local/lib/
|
||||
@ -69,7 +75,11 @@ COPY --from=builder /usr/local/lib/pkgconfig/libpostal.pc /usr/local/lib/pkgconf
|
||||
COPY --from=builder /usr/local/share/libpostal /usr/local/share/libpostal
|
||||
COPY --from=builder /usr/local/bin/libpostal_data /usr/local/bin/libpostal_data
|
||||
RUN ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so.1 \
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so
|
||||
&& ln -s /usr/local/lib/libpostal.so.1.0.1 /usr/local/lib/libpostal.so \
|
||||
&& ldconfig
|
||||
WORKDIR /opt/src/config/data
|
||||
COPY ./config/data/addresses.csv ./
|
||||
WORKDIR /opt/src/app
|
||||
COPY ./go .
|
||||
RUN go get ...
|
||||
RUN go mod download \
|
||||
&& go build
|
||||
|
BIN
config/data/addresses.csv.age
Normal file
BIN
config/data/addresses.csv.age
Normal file
Binary file not shown.
30
config/meili/mapping/addressex.json
Normal file
30
config/meili/mapping/addressex.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"displayedAttributes": [
|
||||
"country",
|
||||
"state",
|
||||
"city",
|
||||
"neighborhood",
|
||||
"road",
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code"
|
||||
],
|
||||
"filterableAttributes": [
|
||||
"country",
|
||||
"state",
|
||||
"city",
|
||||
"neighborhood",
|
||||
"road",
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code"
|
||||
],
|
||||
"searchableAttributes": [
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code"
|
||||
],
|
||||
}
|
@ -6,23 +6,60 @@ services:
|
||||
image: 'joaodubas/addressex:builder'
|
||||
profiles:
|
||||
- build
|
||||
hostname: libpostal
|
||||
init: true
|
||||
restart: unless-stopped
|
||||
entrypoint: sleep
|
||||
command: infinity
|
||||
search:
|
||||
image: 'getmeili/meilisearch:v1.9.0'
|
||||
hostname: meili
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MEILI_ENV: development
|
||||
MEILI_MASTER_KEY: &meili_master_key ${ADDRESSEX_MEILI_KEY:-59EDmQofBp8vGT8kMvJJADPHRWHEAsWzZjCCqBFpVeuBmC2kWgCiBEgG7vfZ3ArY}
|
||||
volumes:
|
||||
- 'meili_data:/meili_data'
|
||||
ports:
|
||||
- '${ADDRESSEX_MEILI_PORT:-7700}:7700'
|
||||
search_ui:
|
||||
image: 'riccoxie/meilisearch-ui:v0.6.16'
|
||||
hostname: search-ui
|
||||
init: true
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '${ADDRESSEX_MEILI_UI_PORT:-24900}:24900'
|
||||
ex:
|
||||
build:
|
||||
target: elixir
|
||||
image: 'joaodubas/addressex:elixir'
|
||||
hostname: ex
|
||||
init: true
|
||||
restart: unless-stopped
|
||||
entrypoint: sleep
|
||||
command: infinity
|
||||
py:
|
||||
build:
|
||||
target: python
|
||||
image: 'joaodubas/addressex:python'
|
||||
hostname: py
|
||||
init: true
|
||||
restart: unless-stopped
|
||||
entrypoint: sleep
|
||||
command: infinity
|
||||
go:
|
||||
build:
|
||||
target: go
|
||||
image: 'joaodubas/addressex:go'
|
||||
hostname: go
|
||||
init: true
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MEILI_MASTER_KEY: *meili_master_key
|
||||
ports:
|
||||
- '9000:9000'
|
||||
entrypoint: sleep
|
||||
command: infinity
|
||||
|
||||
volumes:
|
||||
meili_data: {}
|
||||
|
83
go/addresses.go
Normal file
83
go/addresses.go
Normal file
@ -0,0 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
parser "github.com/openvenues/gopostal/parser"
|
||||
)
|
||||
|
||||
type Address struct {
|
||||
ID string `json:"id"`
|
||||
Country string `json:"country"`
|
||||
State string `json:"state"`
|
||||
City string `json:"city"`
|
||||
Neighborhood string `json:"neighborhood"`
|
||||
Road string `json:"road"`
|
||||
HouseNumber string `json:"house_number"`
|
||||
House string `json:"house"`
|
||||
Unit string `json:"unit"`
|
||||
PostalCode string `json:"postal_code"`
|
||||
Raw string `json:"raw_address"`
|
||||
}
|
||||
|
||||
func (a Address) String() string {
|
||||
return fmt.Sprintf(
|
||||
"%s, %s, %s %s. %s, %s, %s, %s.",
|
||||
a.Road,
|
||||
a.HouseNumber,
|
||||
a.Unit,
|
||||
a.House,
|
||||
a.Neighborhood,
|
||||
a.City,
|
||||
a.State,
|
||||
a.PostalCode,
|
||||
)
|
||||
}
|
||||
|
||||
func (a Address) id() string {
|
||||
hasher := sha1.New()
|
||||
hasher.Write([]byte(a.String()))
|
||||
return hex.EncodeToString(hasher.Sum(nil))
|
||||
}
|
||||
|
||||
func parseAddress(address string) Address {
|
||||
// log.Printf("Address to parse: %s", address)
|
||||
components := parser.ParseAddress(address)
|
||||
// log.Printf("Address components: %s", components)
|
||||
return newFromComponents(address, components)
|
||||
}
|
||||
|
||||
func newFromComponents(raw string, components []parser.ParsedComponent) Address {
|
||||
address := Address{Raw: raw}
|
||||
for _, component := range components {
|
||||
switch component.Label {
|
||||
case "house":
|
||||
address.House = component.Value
|
||||
case "house_number":
|
||||
address.HouseNumber = component.Value
|
||||
case "road":
|
||||
address.Road = component.Value
|
||||
case "unit":
|
||||
address.Unit = component.Value
|
||||
case "postcode":
|
||||
address.PostalCode = component.Value
|
||||
case "suburb":
|
||||
address.Neighborhood = component.Value
|
||||
case "city_district":
|
||||
address.Neighborhood = component.Value
|
||||
case "city":
|
||||
address.City = component.Value
|
||||
case "state_district":
|
||||
address.Neighborhood = component.Value
|
||||
case "state":
|
||||
address.State = component.Value
|
||||
case "country":
|
||||
address.Country = component.Value
|
||||
}
|
||||
}
|
||||
address.ID = address.id()
|
||||
// log.Printf("Address parsed: %s", address)
|
||||
return address
|
||||
}
|
16
go/go.mod
16
go/go.mod
@ -2,4 +2,18 @@ module joaodubas.dev/addressex
|
||||
|
||||
go 1.21.6
|
||||
|
||||
require github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d // indirect
|
||||
require (
|
||||
github.com/meilisearch/meilisearch-go v0.26.1
|
||||
github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
)
|
||||
|
51
go/go.sum
51
go/go.sum
@ -1,2 +1,53 @@
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E=
|
||||
github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/meilisearch/meilisearch-go v0.26.1 h1:3bmo2uLijX7kvBmiZ9LupVfC95TFcRJDgrRTzbOoE4A=
|
||||
github.com/meilisearch/meilisearch-go v0.26.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
|
||||
github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d h1:KJ+N55d9zLN8fTg3NchLdmmAmPieXC5E6UNJ8zFFttU=
|
||||
github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d/go.mod h1:Ycrd7XnwQdumHzpB/6WEa85B4WNdbLC6Wz4FAQNkaV0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
23
go/main.go
23
go/main.go
@ -1,12 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
parser "github.com/openvenues/gopostal/parser"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addressComponents := parser.ParseAddress("rua pedroso xavier 277, apto 51 torre 2. vila albertina, 02732-020, são paulo, sp, brasil")
|
||||
fmt.Println(addressComponents)
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl := template.Must(template.ParseFiles("./templates/index.html"))
|
||||
tmpl.Execute(w, nil)
|
||||
})
|
||||
|
||||
http.HandleFunc("/parse", func(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl := template.Must(template.ParseFiles("./templates/fragments/results.html"))
|
||||
data := map[string]Address{"Result": parseAddress(r.URL.Query().Get("address"))}
|
||||
tmpl.Execute(w, data)
|
||||
})
|
||||
|
||||
log.Println("App running on 9000...")
|
||||
log.Fatal(http.ListenAndServe(":9000", nil))
|
||||
}
|
||||
|
128
go/meilisearch.go
Normal file
128
go/meilisearch.go
Normal file
@ -0,0 +1,128 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/meilisearch/meilisearch-go"
|
||||
)
|
||||
|
||||
func search() {
|
||||
// client := newClient()
|
||||
// _, err := client.Index("addressex").UpdateIndex()
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
}
|
||||
|
||||
func init() {
|
||||
// TODO: (jpd) move this logic to their own endopints
|
||||
createIndex()
|
||||
updateIndex()
|
||||
loadAddresses()
|
||||
}
|
||||
|
||||
func createIndex() {
|
||||
indexConfig := &meilisearch.IndexConfig{Uid: "addressex", PrimaryKey: "id"}
|
||||
client := newClient()
|
||||
_, err := client.CreateIndex(indexConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func updateIndex() {
|
||||
index := newClientIndex()
|
||||
_, err := index.UpdateSettings(&meilisearch.Settings{
|
||||
DisplayedAttributes: []string{
|
||||
"id",
|
||||
"country",
|
||||
"state",
|
||||
"city",
|
||||
"neighborhood",
|
||||
"road",
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code",
|
||||
"raw_address",
|
||||
},
|
||||
FilterableAttributes: []string{
|
||||
"country",
|
||||
"state",
|
||||
"city",
|
||||
"neighborhood",
|
||||
"road",
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code",
|
||||
},
|
||||
SearchableAttributes: []string{
|
||||
"house_number",
|
||||
"house",
|
||||
"unit",
|
||||
"postal_code",
|
||||
},
|
||||
Synonyms: map[string][]string{
|
||||
"apartamento": []string{"apto", "apt", "ap"},
|
||||
"bloco": []string{"bl", "b"},
|
||||
"torre": []string{"tr", "t"},
|
||||
"conjunto": []string{"conj", "cj"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func loadAddresses() {
|
||||
// TODO: (jpd) use env var to set address file
|
||||
f, err := os.Open("/opt/src/config/data/addresses.csv")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
index := newClientIndex()
|
||||
|
||||
rows := csv.NewReader(f)
|
||||
data := []Address{}
|
||||
for {
|
||||
row, err := rows.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rawAddress := row[0]
|
||||
data = append(data, parseAddress(rawAddress))
|
||||
if len(data) == 1000 {
|
||||
log.Printf("Recorded %d addresses", len(data))
|
||||
_, err := index.AddDocuments(data, "id")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = []Address{}
|
||||
}
|
||||
}
|
||||
log.Printf("Recorded %d addresses", len(data))
|
||||
_, err = index.AddDocuments(data, "id")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newClientIndex() *meilisearch.Index {
|
||||
client := newClient()
|
||||
return client.Index("addressex")
|
||||
}
|
||||
|
||||
func newClient() *meilisearch.Client {
|
||||
return meilisearch.NewClient(meilisearch.ClientConfig{
|
||||
Host: "http://meili:7700",
|
||||
APIKey: os.Getenv("MEILI_MASTER_KEY"),
|
||||
})
|
||||
}
|
100
go/static/css/index.css
Normal file
100
go/static/css/index.css
Normal file
@ -0,0 +1,100 @@
|
||||
:root {
|
||||
--bg-color: #131415;
|
||||
--primary-color: #9575CD;
|
||||
--margin: 40px;
|
||||
--margin-sm: 20px;
|
||||
--radius: 6px;
|
||||
--text-color: #FFF;
|
||||
--header-height: 100px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
header {
|
||||
background: #24292d;
|
||||
height: var(--header-height);
|
||||
}
|
||||
|
||||
header ul {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
header ul li {
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 var(--margin-sm);
|
||||
}
|
||||
|
||||
header ul li h5 {
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header ul li h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 100;
|
||||
margin: 5px 0 0;
|
||||
}
|
||||
|
||||
header ul li h5 strong {
|
||||
color: #81c784;
|
||||
}
|
||||
|
||||
section {
|
||||
height: calc(100vh - var(--header-height));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
section input {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
background: transparent;
|
||||
border: 2px solid var(--primary-color);
|
||||
border-radius: var(--radius);
|
||||
color: var(--text-color);
|
||||
font-size: 20px;
|
||||
outline: none !important;
|
||||
padding: 0 20px;
|
||||
width: 300px;
|
||||
margin-top: var(--margin);
|
||||
}
|
||||
|
||||
#search-results ul li {
|
||||
color: #FFF;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#search-results ul li button {
|
||||
align-self: center;
|
||||
height: 34px;
|
||||
padding: 0 15px;
|
||||
border: 0;
|
||||
border-radius: var( --radius);
|
||||
margin-left: var(--margin-sm);
|
||||
background: var(--primary-color);
|
||||
color: #FFF;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#spinner {
|
||||
display: none;
|
||||
}
|
18
go/templates/fragments/results.html
Normal file
18
go/templates/fragments/results.html
Normal file
@ -0,0 +1,18 @@
|
||||
<dl>
|
||||
<dt>Logradouro</dt>
|
||||
<dd>{{ .Result.Road }}</dd>
|
||||
<dt>Número</dt>
|
||||
<dd>{{ .Result.HouseNumber }}</dd>
|
||||
<dt>Unidade</dt>
|
||||
<dd>{{ .Result.Unit }}</dd>
|
||||
<dt>Torre</dt>
|
||||
<dd>{{ .Result.House }}</dd>
|
||||
<dt>Bairro</dt>
|
||||
<dd>{{ .Result.Neighborhood }}</dd>
|
||||
<dt>Cidade</dt>
|
||||
<dd>{{ .Result.City }}</dd>
|
||||
<dt>Estado</dt>
|
||||
<dd>{{ .Result.State }}</dd>
|
||||
<dt><abbr title="Código de Endereçamento Postal">CEP</abbr></dt>
|
||||
<dd>{{ .Result.PostalCode }}</dd>
|
||||
</dl>
|
27
go/templates/index.html
Normal file
27
go/templates/index.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Parser de Endereço</title>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
||||
<link rel="stylesheet" href="/static/css/index.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section>
|
||||
<div>
|
||||
<input
|
||||
type="search"
|
||||
name="address"
|
||||
placeholder="Endereço: Rua, Número, Complement. Bairro - Cidade/Estado. CEP"
|
||||
hx-get="/parse"
|
||||
hx-trigger="keyup changed delay:500ms"
|
||||
hx-target="#address" />
|
||||
</div>
|
||||
|
||||
<div id="address"></div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user