diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 535c45f..3ed2087 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ on: - "**.md" env: - GO_VERSION: "1.21.4" # https://go.dev/dl/ - GOLANGCI_LINT_VERSION: "v1.55.2" # https://github.com/golangci/golangci-lint/releases + GO_VERSION: "1.22.5" # https://go.dev/dl/ + GOLANGCI_LINT_VERSION: "v1.59.1" # https://github.com/golangci/golangci-lint/releases jobs: lint: diff --git a/ai/boilerplate/docker-compose.yml b/ai/boilerplate/docker-compose.yml deleted file mode 100644 index 8e6e1a2..0000000 --- a/ai/boilerplate/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3.8' - -services: - postgres: - image: postgres:latest - environment: - POSTGRES_DB: yourdbname - POSTGRES_USER: youruser - POSTGRES_PASSWORD: yourpassword - ports: - - "5432:5432" - volumes: - - postgres-data:/var/lib/postgresql/data - - qdrant: - image: qdrant/qdrant - ports: - - "6333:6333" - volumes: - - qdrant-data:/qdrant/storage - -volumes: - postgres-data: - qdrant-data: \ No newline at end of file diff --git a/ai/boilerplate/goapp/.env b/ai/boilerplate/goapp/.env deleted file mode 100644 index fe3953b..0000000 --- a/ai/boilerplate/goapp/.env +++ /dev/null @@ -1,7 +0,0 @@ -POSTGRES_HOST=localhost -POSTGRES_PORT=5432 -POSTGRES_USER=youruser -POSTGRES_PASSWORD=yourpassword -POSTGRES_DB=yourdbname -QDRANT_HOST=localhost -QDRANT_PORT=6333 \ No newline at end of file diff --git a/ai/boilerplate/goapp/go.mod b/ai/boilerplate/goapp/go.mod deleted file mode 100644 index 523dede..0000000 --- a/ai/boilerplate/goapp/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module goapp - -go 1.22.3 - -require ( - github.com/joho/godotenv v1.5.1 - github.com/lib/pq v1.10.9 -) diff --git a/ai/boilerplate/goapp/go.sum b/ai/boilerplate/goapp/go.sum deleted file mode 100644 index ecb9035..0000000 --- a/ai/boilerplate/goapp/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/ai/boilerplate/goapp/main.go b/ai/boilerplate/goapp/main.go deleted file mode 100644 index 5b28abc..0000000 --- a/ai/boilerplate/goapp/main.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - "log" - "net/http" - "os" - - "github.com/joho/godotenv" - _ "github.com/lib/pq" -) - -func main() { - // Load .env file - err := godotenv.Load() - if err != nil { - log.Fatalf("Error loading .env file: %v", err) - } - - // Connect to PostgreSQL - pgConnStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", - os.Getenv("POSTGRES_HOST"), os.Getenv("POSTGRES_PORT"), os.Getenv("POSTGRES_USER"), os.Getenv("POSTGRES_PASSWORD"), os.Getenv("POSTGRES_DB")) - db, err := sql.Open("postgres", pgConnStr) - if err != nil { - log.Fatalf("Error connecting to PostgreSQL: %v", err) - } - defer db.Close() - - // Connect to Qdrant - qdrantURL := fmt.Sprintf("http://%s:%s", os.Getenv("QDRANT_HOST"), os.Getenv("QDRANT_PORT")) - resp, err := http.Get(qdrantURL + "/v1/collections") - if err != nil { - log.Fatalf("Error connecting to Qdrant: %v", err) - } - defer resp.Body.Close() - - // Simple HTTP server - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Connected to PostgreSQL and Qdrant successfully!") - }) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/ai/chats.json b/ai/chats.json deleted file mode 100644 index 2e6016f..0000000 --- a/ai/chats.json +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:20f82c13ec0d446b79a3035932aeb2da6d55bb484e8642204f1327864da6a879 -size 59219437 diff --git a/ai/readme.md b/ai/readme.md deleted file mode 100644 index aa5c913..0000000 --- a/ai/readme.md +++ /dev/null @@ -1,59 +0,0 @@ -# AI Challenge - -This challenge is part of the AI hiring process at Heart Hands. - -## Why this challenge? - -Heart Hands is operating with a small team of dedicated & talented people. We are looking for seasoned engineers with deep technical knowledge, a strong understanding of their technical stack, and excellent product intuitions to join our team. - -This exercise has been designed to give a glimpse of what it is like to build an AI chief of staff app and the kind of technical challenges we face and care about. We are expecting you to spend between 4 and 6 hours on this challenge. - -## Instructions - -You are tasked with implementing a retrieval system for a messaging app. It must expose API endpoints that enable users to query their conversation history using natural language. You are free to implement the API in any way you feel the most comfortable with. You can find a dataset of chat conversations between several users [here](https://github.com/hearthandsinc/challenges/blob/main/ai/chats.json). - -We enforce no technical constraints: you are free to choose the language, data layer, network protocol, and design your API as you see fit. You are purposefully being given a lot of freedom here, and you will not be judged on these decisions alone, but we will challenge the understanding of the trade-offs you make. - -You can find a simple boilerplate for a Go/PGSQL/Qdrant app [here](https://github.com/hearthandsinc/challenges/tree/main/ai/boilterplate), but again, you are free to use any technology you want. - -Functional requirements: - -- [ ] Users can search through their chat history using natural language. To evaluate the solution, we'll be asking questions from Matthias, Aymeric and David's point of view: -- Matthias' id is: `018f2685-a936-44a9-8ff4-9ef0c98289b8` -- Aymeric's id is: `82247543-5c2d-46d9-9a0d-fe25482922b5` -- David's id is: `2d614bef-2b01-4021-b63a-9d04658536f3` -- Example of the questions we will be asking: - - "What did Aymeric and I discuss last week?" - - "Where does Aymeric live?" - - "What did David tell me about the roadmap?" -- [ ] Your solution is multitenant. Users can only search their own history using their user ID. -- [ ] Users can query their chat history through an API endpoint. - - - -## Bonus - -Some topics that we find interesting to dig into: - -- [ ] Ability to target a specific date. -E.g.: - - "Can you recap last Thursday's chat activity?" - - "Can you summarize our discussion with David from March 12th?" -- [ ] Ability to count occurrences. -E.g.: - - "How many messages did Aymeric and I exchange so far?" -- [ ] The assistant chat keeps track of one request to the next. -E.g.: - 1. "What are Aymeric's requirements for buying a new home?" - 2. "What are David's?" - -## Challenge Review - -We know you only have a limited time allotted to deliver this challenge, and thus will have to prioritize what you work on. A few things that are important for us and that will be considered during the review: - -- **documentation**: is the README clear? are important parts of the code documented? -- **impact**: which features did you prioritize? -- **maintainability**: is the code well-structured and easy to read/evolve? -- **robustness**: are edge cases considered? - -Good luck, and enjoy! diff --git a/ios/server/go.mod b/ios/server/go.mod index 2ee7061..31fe95e 100644 --- a/ios/server/go.mod +++ b/ios/server/go.mod @@ -1,16 +1,16 @@ module github.com/hearthands/challenges/ios/server -go 1.21.4 +go 1.22.5 require ( - github.com/go-chi/chi/v5 v5.0.10 + github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/render v1.0.3 github.com/r3labs/sse/v2 v2.10.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 ) require ( github.com/ajg/form v1.5.1 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.27.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect ) diff --git a/ios/server/go.sum b/ios/server/go.sum index f20900c..3df15b6 100644 --- a/ios/server/go.sum +++ b/ios/server/go.sum @@ -2,8 +2,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -14,14 +14,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/net v0.0.0-20191116160921-f9c825593386 h1:ktbWvQrW08Txdxno1PiDpSxPXG6ndGsfnJjRRtkM0LQ= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= diff --git a/ios/server/main.go b/ios/server/main.go index 7457c45..44feffb 100644 --- a/ios/server/main.go +++ b/ios/server/main.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "math/rand" + "net" "net/http" "os" "strconv" @@ -21,9 +22,14 @@ import ( ) var ( - hostname = envOrDefault("HTTP_HOST", "localhost") // hostname used by the server - port = envOrDefault("PORT", "3000") // port used by the server - limit = 100 // maximum number of entities returned in a single request + // hostname used by the server + hostname = envOrDefault("HTTP_HOST", "localhost") + + // port used by the server + port = envOrDefault("PORT", "3000") + + // maximum number of entities returned in a single request + limit = 100 ) //go:embed data.json @@ -49,8 +55,12 @@ func main() { r.Post("/chats/{chatID}/messages", app.PostMessages) }) - addr := fmt.Sprintf("%s:%s", hostname, port) - fmt.Printf("Starting server on %s\n", addr) + r.Get("/livez", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + addr := net.JoinHostPort(hostname, port) + fmt.Printf("Starting server on http://%s\n", addr) if err := http.ListenAndServe(addr, r); err != nil { panic(fmt.Errorf("failed to start server on %s: %w", addr, err)) } diff --git a/readme.md b/readme.md index 0b2b5f5..6789894 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ # Challenges [![ci status](https://github.com/hearthandsinc/challenges/actions/workflows/ci.yml/badge.svg)](https://github.com/hearthandsinc/challenges/actions/workflows/ci.yml) This repository contains the [Heart Hands](https://hearthands.tech/) engineering -challenges for [iOS](./ios), [backend](./backend), and [AI](./aillm) positions. +challenges for [iOS](./ios) and [backend](./backend) positions. ## Feedbacks