rewrite to using new method

This commit is contained in:
2024-06-16 18:21:06 -05:00
parent f07bd666fb
commit 790c8c969a
19 changed files with 388 additions and 395 deletions

View File

@@ -1,4 +1,4 @@
start: start:
sudo docker run --name postgres-db -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres sudo podman run --name postgres-db -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres
stop: stop:
sudo docker rm postgres-db -f sudo podman rm postgres-db -f

View File

@@ -3,18 +3,42 @@ package controller
import ( import (
"fmt" "fmt"
"log" "log"
"net/http"
"github.com/caarlos0/env/v6" "github.com/caarlos0/env/v6"
"github.com/joho/godotenv" "github.com/joho/godotenv"
httpSwagger "github.com/swaggo/http-swagger"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gitlab.com/DeveloperDurp/DurpAPI/model" "gitlab.com/DeveloperDurp/DurpAPI/middleware"
"gitlab.com/DeveloperDurp/DurpAPI/storage" "gitlab.com/DeveloperDurp/DurpAPI/services/dadjoke"
"gitlab.com/DeveloperDurp/DurpAPI/services/health"
"gitlab.com/DeveloperDurp/DurpAPI/services/openai"
"gitlab.com/developerdurp/stdmodels"
) )
type Controller struct { type Controller struct {
Cfg model.Config Cfg Config
Dbcfg model.DBConfig Dbcfg DBConfig
Db model.Repository Db *gorm.DB
}
type Config struct {
Host string `env:"host"`
Version string `env:"version"`
Groupsenv string `env:"groupsenv"`
JwksURL string `env:"jwksurl"`
LlamaURL string `env:"llamaurl"`
}
type DBConfig struct {
Host string `env:"db_host"`
Port string `env:"db_port"`
Password string `env:"db_pass"`
User string `env:"db_user"`
DBName string `env:"db_name"`
SSLMode string `env:"db_sslmode"`
} }
func NewController() *Controller { func NewController() *Controller {
@@ -24,8 +48,8 @@ func NewController() *Controller {
} }
controller := &Controller{ controller := &Controller{
Cfg: model.Config{}, Cfg: Config{},
Dbcfg: model.DBConfig{}, Dbcfg: DBConfig{},
} }
err = env.Parse(&controller.Cfg) err = env.Parse(&controller.Cfg)
@@ -37,11 +61,77 @@ func NewController() *Controller {
log.Fatalf("unable to parse database variables: %e", err) log.Fatalf("unable to parse database variables: %e", err)
} }
Db, err := storage.Connect(controller.Dbcfg) Db, err := connectDB(controller.Dbcfg)
if err != nil { if err != nil {
panic("Failed to connect to database") panic("Failed to connect to database")
} }
controller.Db = *Db controller.Db = Db
return controller return controller
} }
func (c *Controller) Run() error {
router := http.NewServeMux()
err := c.loadAll(router)
if err != nil {
return err
}
stack := middleware.CreateStack(
middleware.Logging,
middleware.Headers,
)
server := http.Server{
Addr: ":8080",
Handler: stack(router),
}
fmt.Println("Server listening on port :8080")
return server.ListenAndServe()
}
func (c *Controller) loadAll(router *http.ServeMux) error {
// adminRouter := http.NewServeMux()
// router.Handle("/", middleware.EnsureAdmin(adminRouter))
router.HandleFunc("/", defaultHandler)
router.HandleFunc("/swagger/*", httpSwagger.Handler())
health, err := health.NewHandler()
router.HandleFunc("GET /api/health/gethealth", health.Get)
dadjoke, err := dadjoke.NewHandler(c.Db)
router.HandleFunc("GET /api/jokes/dadjoke", dadjoke.Get)
router.HandleFunc("POST /api/jokes/dadjoke", dadjoke.Post)
router.HandleFunc("DELETE /api/jokes/dadjoke", dadjoke.Delete)
openai, err := openai.NewHandler(c.Cfg.LlamaURL)
router.HandleFunc("GET /api/openai/general", openai.GeneralOpenAI)
router.HandleFunc("GET /api/openai/travelagent", openai.TravelAgentOpenAI)
if err != nil {
return err
}
return nil
}
func defaultHandler(w http.ResponseWriter, r *http.Request) {
stdmodels.FailureReponse("Page Does not exist", w, http.StatusNotFound, []string{"Page is not found"})
}
func connectDB(config DBConfig) (*gorm.DB, error) {
dsn := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
config.Host, config.Port, config.User, config.Password, config.DBName, config.SSLMode,
)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
return db, nil
}

View File

@@ -1,154 +0,0 @@
package controller
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"gitlab.com/DeveloperDurp/DurpAPI/model"
)
type ChatRequest struct {
Message string `json:"message"`
}
// Response struct to unmarshal the JSON response
type Response struct {
Response string `json:"response"`
}
// GeneralOpenAI godoc
//
// @Summary Gerneral ChatGPT
// @Description Ask ChatGPT a general question
// @Tags openai
// @Accept json
// @Produce application/json
// @Param message query string true "Ask ChatGPT a general question"
// @Success 200 {object} model.Message "response"
//
// @failure 400 {object} model.Message "error"
//
// @Security Authorization
//
// @Router /openai/general [get]
func (c *Controller) GeneralOpenAI(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
var req ChatRequest
if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
return
}
} else {
queryParams := r.URL.Query()
req.Message = queryParams.Get("message")
}
result, err := c.createChatCompletion(req.Message, "mistral:instruct")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
return
}
message := model.Message{
Message: result,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(message)
}
// TravelAgentOpenAI godoc
//
// @Summary Travel Agent ChatGPT
// @Description Ask ChatGPT for suggestions as if it was a travel agent
// @Tags openai
// @Accept json
// @Produce application/json
// @Param message query string true "Ask ChatGPT for suggestions as a travel agent"
// @Success 200 {object} model.Message "response"
// @failure 400 {object} model.Message "error"
//
// @Security Authorization
//
// @Router /openai/travelagent [get]
func (c *Controller) TravelAgentOpenAI(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
var req ChatRequest
if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
return
}
} else {
queryParams := r.URL.Query()
req.Message = queryParams.Get("message")
}
req.Message = "I want you to act as a travel guide. I will give you my location and you will give me suggestions. " + req.Message
result, err := c.createChatCompletion(req.Message, "mistral:instruct")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
return
}
message := model.Message{
Message: result,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(message)
}
func (c *Controller) createChatCompletion(message string, model string) (string, error) {
// Define the request body
requestBody := map[string]interface{}{
"model": model,
"prompt": message,
"stream": false,
}
// Convert the request body to JSON
requestBodyBytes, err := json.Marshal(requestBody)
if err != nil {
return "", fmt.Errorf("error encoding request body: %v", err)
}
// Send a POST request to the specified URL with the request body
response, err := http.Post(
"http://"+c.Cfg.LlamaURL+"/api/generate",
"application/json",
bytes.NewBuffer(requestBodyBytes),
)
if err != nil {
return "", fmt.Errorf("error sending POST request: %v", err)
}
defer response.Body.Close()
// Read the response body
responseBody, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("error reading response body: %v", err)
}
// Unmarshal the JSON response
var resp Response
if err := json.Unmarshal(responseBody, &resp); err != nil {
return "", fmt.Errorf("error decoding response body: %v", err)
}
// Return the response
return resp.Response, nil
}

View File

@@ -46,13 +46,13 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -80,7 +80,7 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -121,7 +121,7 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -162,7 +162,7 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -205,13 +205,13 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"400": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -248,13 +248,13 @@ const docTemplate = `{
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"400": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -262,15 +262,6 @@ const docTemplate = `{
} }
}, },
"definitions": { "definitions": {
"model.Message": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "message"
}
}
},
"stdmodels.StandardError": { "stdmodels.StandardError": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -287,6 +278,14 @@ const docTemplate = `{
"type": "integer" "type": "integer"
} }
} }
},
"stdmodels.StandardMessage": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {

View File

@@ -38,13 +38,13 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -72,7 +72,7 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -113,7 +113,7 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -154,7 +154,7 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"500": { "500": {
@@ -197,13 +197,13 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"400": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -240,13 +240,13 @@
"200": { "200": {
"description": "response", "description": "response",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardMessage"
} }
}, },
"400": { "500": {
"description": "error", "description": "error",
"schema": { "schema": {
"$ref": "#/definitions/model.Message" "$ref": "#/definitions/stdmodels.StandardError"
} }
} }
} }
@@ -254,15 +254,6 @@
} }
}, },
"definitions": { "definitions": {
"model.Message": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "message"
}
}
},
"stdmodels.StandardError": { "stdmodels.StandardError": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -279,6 +270,14 @@
"type": "integer" "type": "integer"
} }
} }
},
"stdmodels.StandardMessage": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {

View File

@@ -1,11 +1,5 @@
basePath: / basePath: /
definitions: definitions:
model.Message:
properties:
message:
example: message
type: string
type: object
stdmodels.StandardError: stdmodels.StandardError:
properties: properties:
description: description:
@@ -17,6 +11,11 @@ definitions:
status: status:
type: integer type: integer
type: object type: object
stdmodels.StandardMessage:
properties:
message:
type: string
type: object
info: info:
contact: contact:
email: developerdurp@durp.info email: developerdurp@durp.info
@@ -40,11 +39,11 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"500": "500":
description: error description: error
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardError'
security: security:
- Authorization: [] - Authorization: []
summary: Generate Health status summary: Generate Health status
@@ -67,7 +66,7 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"500": "500":
description: error description: error
schema: schema:
@@ -87,7 +86,7 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"500": "500":
description: error description: error
schema: schema:
@@ -113,7 +112,7 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"500": "500":
description: error description: error
schema: schema:
@@ -140,11 +139,11 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"400": "500":
description: error description: error
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardError'
security: security:
- Authorization: [] - Authorization: []
summary: Gerneral ChatGPT summary: Gerneral ChatGPT
@@ -167,11 +166,11 @@ paths:
"200": "200":
description: response description: response
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardMessage'
"400": "500":
description: error description: error
schema: schema:
$ref: '#/definitions/model.Message' $ref: '#/definitions/stdmodels.StandardError'
security: security:
- Authorization: [] - Authorization: []
summary: Travel Agent ChatGPT summary: Travel Agent ChatGPT

31
main.go
View File

@@ -1,14 +1,10 @@
package main package main
import ( import (
"fmt" "log"
"net/http"
"github.com/swaggo/http-swagger"
"gitlab.com/DeveloperDurp/DurpAPI/controller" "gitlab.com/DeveloperDurp/DurpAPI/controller"
"gitlab.com/DeveloperDurp/DurpAPI/docs" "gitlab.com/DeveloperDurp/DurpAPI/docs"
"gitlab.com/DeveloperDurp/DurpAPI/middleware"
) )
// @title DurpAPI // @title DurpAPI
@@ -33,30 +29,11 @@ func main() {
docs.SwaggerInfo.Host = c.Cfg.Host docs.SwaggerInfo.Host = c.Cfg.Host
docs.SwaggerInfo.Version = c.Cfg.Version docs.SwaggerInfo.Version = c.Cfg.Version
router := http.NewServeMux() if err := c.Run(); err != nil {
router.HandleFunc("/swagger/*", httpSwagger.Handler()) log.Fatal(err)
}
router.HandleFunc("GET /api/health/gethealth", c.GetHealth)
router.HandleFunc("GET /api/jokes/dadjoke", c.GetDadJoke)
router.HandleFunc("POST /api/jokes/dadjoke", c.PostDadJoke)
router.HandleFunc("DELETE /api/jokes/dadjoke", c.DeleteDadJoke)
router.HandleFunc("GET /api/openai/general", c.GeneralOpenAI)
router.HandleFunc("GET /api/openai/travelagent", c.TravelAgentOpenAI)
// adminRouter := http.NewServeMux() // adminRouter := http.NewServeMux()
// router.Handle("/", middleware.EnsureAdmin(adminRouter)) // router.Handle("/", middleware.EnsureAdmin(adminRouter))
stack := middleware.CreateStack(
middleware.Logging,
)
server := http.Server{
Addr: ":8080",
Handler: stack(router),
}
fmt.Println("Server listening on port :8080")
server.ListenAndServe()
} }

View File

@@ -1,17 +0,0 @@
package middleware
import (
"net/http"
"strings"
)
func EnsureAdmin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Authorization"), "Admin") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(http.StatusText(http.StatusUnauthorized)))
return
}
next.ServeHTTP(w, r)
})
}

12
middleware/headers.go Normal file
View File

@@ -0,0 +1,12 @@
package middleware
import "net/http"
func Headers(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
})
}

View File

@@ -1,7 +1,7 @@
package middleware package middleware
import ( import (
"log/slog" "log"
"net/http" "net/http"
"time" "time"
) )
@@ -27,13 +27,13 @@ func Logging(next http.Handler) http.Handler {
next.ServeHTTP(wrapped, r) next.ServeHTTP(wrapped, r)
slog.Info( //slog.Info(
"Health Check", // "Health Check",
slog.Int("Method", wrapped.statusCode), // slog.Int("Method", wrapped.statusCode),
r.Method, // r.Method,
r.URL.Path, // r.URL.Path,
slog.String("time", time.Since(start).String()), // slog.String("time", time.Since(start).String()),
) //)
// log.Println("INFO", wrapped.statusCode, r.Method, r.URL.Path, time.Since(start)) log.Println("INFO", wrapped.statusCode, r.Method, r.URL.Path, time.Since(start))
}) })
} }

View File

@@ -1,26 +0,0 @@
package model
import (
"gorm.io/gorm"
)
type Config struct {
Host string `env:"host"`
Version string `env:"version"`
Groupsenv string `env:"groupsenv"`
JwksURL string `env:"jwksurl"`
LlamaURL string `env:"llamaurl"`
}
type DBConfig struct {
Host string `env:"db_host"`
Port string `env:"db_port"`
Password string `env:"db_pass"`
User string `env:"db_user"`
DBName string `env:"db_name"`
SSLMode string `env:"db_sslmode"`
}
type Repository struct {
DB *gorm.DB
}

View File

@@ -1,5 +0,0 @@
package model
type DadJoke struct {
JOKE string `json:"joke"`
}

View File

@@ -1,5 +0,0 @@
package model
type Message struct {
Message string `json:"message" example:"message"`
}

View File

@@ -1,15 +1,30 @@
package controller package dadjoke
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"gitlab.com/DeveloperDurp/DurpAPI/model"
"gitlab.com/DeveloperDurp/DurpAPI/service"
"gitlab.com/developerdurp/logger" "gitlab.com/developerdurp/logger"
"gitlab.com/developerdurp/stdmodels" "gitlab.com/developerdurp/stdmodels"
"gorm.io/gorm"
) )
type Handler struct {
db *gorm.DB
}
type DadJoke struct {
JOKE string `json:"joke"`
}
func NewHandler(db *gorm.DB) (*Handler, error) {
err := db.AutoMigrate(&DadJoke{})
if err != nil {
return nil, err
}
return &Handler{db: db}, nil
}
// GetDadJoke godoc // GetDadJoke godoc
// //
// @Summary Get dadjoke // @Summary Get dadjoke
@@ -17,23 +32,21 @@ import (
// @Tags DadJoke // @Tags DadJoke
// @Accept json // @Accept json
// @Produce application/json // @Produce application/json
// @Success 200 {object} model.Message "response" // @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} stdmodels.StandardError"error" // @failure 500 {object} stdmodels.StandardError"error"
// //
// @Security Authorization // @Security Authorization
// //
// @Router /jokes/dadjoke [get] // @Router /jokes/dadjoke [get]
func (c *Controller) GetDadJoke(w http.ResponseWriter, r *http.Request) { func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") joke, err := h.GetRandomDadJoke()
joke, err := service.GetRandomDadJoke(c.Db.DB)
if err != nil { if err != nil {
stdmodels.FailureReponse("Failed to get Joke", w, http.StatusInternalServerError, []string{err.Error()}) stdmodels.FailureReponse("Failed to get Joke", w, http.StatusInternalServerError, []string{err.Error()})
return return
} }
message := model.Message{ message := stdmodels.StandardMessage{
Message: joke, Message: joke,
} }
@@ -48,15 +61,15 @@ func (c *Controller) GetDadJoke(w http.ResponseWriter, r *http.Request) {
// @Accept json // @Accept json
// @Produce application/json // @Produce application/json
// @Param joke query string true "Dad Joke you wish to enter into database" // @Param joke query string true "Dad Joke you wish to enter into database"
// @Success 200 {object} model.Message "response" // @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} stdmodels.StandardError"error" // @failure 500 {object} stdmodels.StandardError"error"
// //
// @Security Authorization // @Security Authorization
// //
// @Router /jokes/dadjoke [post] // @Router /jokes/dadjoke [post]
func (c *Controller) PostDadJoke(w http.ResponseWriter, r *http.Request) { func (h *Handler) Post(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type") contentType := r.Header.Get("Content-Type")
var req model.DadJoke var req DadJoke
if contentType == "application/json" { if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req) err := json.NewDecoder(r.Body).Decode(&req)
@@ -69,7 +82,7 @@ func (c *Controller) PostDadJoke(w http.ResponseWriter, r *http.Request) {
req.JOKE = queryParams.Get("joke") req.JOKE = queryParams.Get("joke")
} }
err := service.PostDadJoke(c.Db.DB, req) err := h.PostDadJoke(req)
if err != nil { if err != nil {
stdmodels.FailureReponse("Failed to add joke", w, http.StatusInternalServerError, []string{err.Error()}) stdmodels.FailureReponse("Failed to add joke", w, http.StatusInternalServerError, []string{err.Error()})
return return
@@ -86,15 +99,15 @@ func (c *Controller) PostDadJoke(w http.ResponseWriter, r *http.Request) {
// @Accept json // @Accept json
// @Produce application/json // @Produce application/json
// @Param joke query string true "Dad joke you wish to delete from the database" // @Param joke query string true "Dad joke you wish to delete from the database"
// @Success 200 {object} model.Message "response" // @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} stdmodels.StandardError"error" // @failure 500 {object} stdmodels.StandardError"error"
// //
// @Security Authorization // @Security Authorization
// //
// @Router /jokes/dadjoke [delete] // @Router /jokes/dadjoke [delete]
func (c *Controller) DeleteDadJoke(w http.ResponseWriter, r *http.Request) { func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type") contentType := r.Header.Get("Content-Type")
var req model.DadJoke var req DadJoke
if contentType == "application/json" { if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req) err := json.NewDecoder(r.Body).Decode(&req)
@@ -108,17 +121,11 @@ func (c *Controller) DeleteDadJoke(w http.ResponseWriter, r *http.Request) {
req.JOKE = queryParams.Get("joke") req.JOKE = queryParams.Get("joke")
} }
err := service.DeleteDadJoke(c.Db.DB, req) err := h.DeleteDadJoke(req)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) stdmodels.FailureReponse("Failed to delete joke", w, http.StatusInternalServerError, []string{err.Error()})
w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
return return
} }
message := model.Message{ stdmodels.SuccessResponse("OK", w, http.StatusOK)
Message: "OK",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(message)
} }

View File

@@ -1,16 +1,12 @@
package service package dadjoke
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"gorm.io/gorm"
"gitlab.com/DeveloperDurp/DurpAPI/model"
) )
func GetRandomDadJoke(db *gorm.DB) (string, error) { func (h *Handler) GetRandomDadJoke() (string, error) {
jokes, err := getDadJokes(db) jokes, err := h.getDadJokes()
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -22,8 +18,8 @@ func GetRandomDadJoke(db *gorm.DB) (string, error) {
return randomElement.JOKE, err return randomElement.JOKE, err
} }
func PostDadJoke(db *gorm.DB, joke model.DadJoke) error { func (h *Handler) PostDadJoke(joke DadJoke) error {
jokes, err := getDadJokes(db) jokes, err := h.getDadJokes()
if err != nil { if err != nil {
return err return err
} }
@@ -39,7 +35,7 @@ func PostDadJoke(db *gorm.DB, joke model.DadJoke) error {
if found { if found {
return errors.New("Joke is already in database") return errors.New("Joke is already in database")
} else { } else {
err = db.Create(&joke).Error err = h.db.Create(&joke).Error
if err != nil { if err != nil {
return err return err
} }
@@ -47,24 +43,24 @@ func PostDadJoke(db *gorm.DB, joke model.DadJoke) error {
} }
} }
func DeleteDadJoke(db *gorm.DB, joke model.DadJoke) error { func (h *Handler) DeleteDadJoke(joke DadJoke) error {
check := &model.DadJoke{} check := &DadJoke{}
db.Where("joke = ?", joke.JOKE).First(check) h.db.Where("joke = ?", joke.JOKE).First(check)
if check.JOKE == "" { if check.JOKE == "" {
return errors.New("Joke does not exist") return errors.New("Joke does not exist")
} }
err := db.Where("joke = ?", joke.JOKE).Delete(joke).Error err := h.db.Where("joke = ?", joke.JOKE).Delete(joke).Error
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func getDadJokes(db *gorm.DB) ([]model.DadJoke, error) { func (h *Handler) getDadJokes() ([]DadJoke, error) {
req := []model.DadJoke{} req := []DadJoke{}
err := db.Find(&req).Error err := h.db.Find(&req).Error
return req, err return req, err
} }

View File

@@ -1,12 +1,17 @@
package controller package health
import ( import (
"net/http" "net/http"
"gitlab.com/developerdurp/logger"
"gitlab.com/developerdurp/stdmodels" "gitlab.com/developerdurp/stdmodels"
) )
type Handler struct{}
func NewHandler() (*Handler, error) {
return &Handler{}, nil
}
// getHealth godoc // getHealth godoc
// //
// @Summary Generate Health status // @Summary Generate Health status
@@ -14,13 +19,12 @@ import (
// @Tags health // @Tags health
// @Accept json // @Accept json
// @Produce application/json // @Produce application/json
// @Success 200 {object} model.Message "response" // @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} model.Message "error" // @failure 500 {object} stdmodels.StandardError"error"
// //
// @Security Authorization // @Security Authorization
// //
// @Router /health/gethealth [get] // @Router /health/gethealth [get]
func (c *Controller) GetHealth(w http.ResponseWriter, r *http.Request) { func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
logger.LogInfo("Health Check")
stdmodels.SuccessResponse("OK", w, http.StatusOK) stdmodels.SuccessResponse("OK", w, http.StatusOK)
} }

103
services/openai/handler.go Normal file
View File

@@ -0,0 +1,103 @@
package openai
import (
"encoding/json"
"net/http"
"gitlab.com/developerdurp/stdmodels"
)
type Handler struct {
LlamaURL string
}
func NewHandler(LlamaURL string) (*Handler, error) {
return &Handler{LlamaURL: LlamaURL}, nil
}
type ChatRequest struct {
Message string `json:"message"`
}
// Response struct to unmarshal the JSON response
type Response struct {
Response string `json:"response"`
}
// GeneralOpenAI godoc
//
// @Summary Gerneral ChatGPT
// @Description Ask ChatGPT a general question
// @Tags openai
// @Accept json
// @Produce application/json
// @Param message query string true "Ask ChatGPT a general question"
// @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} stdmodels.StandardError"error"
//
// @Security Authorization
//
// @Router /openai/general [get]
func (h *Handler) GeneralOpenAI(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
var req ChatRequest
if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
stdmodels.FailureReponse("Failed To decode content", w, http.StatusInternalServerError, []string{err.Error()})
return
}
} else {
queryParams := r.URL.Query()
req.Message = queryParams.Get("message")
}
result, err := h.createChatCompletion(req.Message, "mistral:instruct")
if err != nil {
stdmodels.FailureReponse("Failed to Send Message", w, http.StatusInternalServerError, []string{err.Error()})
return
}
stdmodels.SuccessResponse(result, w, http.StatusOK)
}
// TravelAgentOpenAI godoc
//
// @Summary Travel Agent ChatGPT
// @Description Ask ChatGPT for suggestions as if it was a travel agent
// @Tags openai
// @Accept json
// @Produce application/json
// @Param message query string true "Ask ChatGPT for suggestions as a travel agent"
// @Success 200 {object} stdmodels.StandardMessage "response"
// @failure 500 {object} stdmodels.StandardError"error"
//
// @Security Authorization
//
// @Router /openai/travelagent [get]
func (h *Handler) TravelAgentOpenAI(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
var req ChatRequest
if contentType == "application/json" {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
stdmodels.FailureReponse("Failed To decode content", w, http.StatusInternalServerError, []string{err.Error()})
return
}
} else {
queryParams := r.URL.Query()
req.Message = queryParams.Get("message")
}
req.Message = "I want you to act as a travel guide. I will give you my location and you will give me suggestions. " + req.Message
result, err := h.createChatCompletion(req.Message, "mistral:instruct")
if err != nil {
stdmodels.FailureReponse("Failed to Send Message", w, http.StatusInternalServerError, []string{err.Error()})
return
}
stdmodels.SuccessResponse(result, w, http.StatusOK)
}

View File

@@ -0,0 +1,50 @@
package openai
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func (h *Handler) createChatCompletion(message string, model string) (string, error) {
// Define the request body
requestBody := map[string]interface{}{
"model": model,
"prompt": message,
"stream": false,
}
// Convert the request body to JSON
requestBodyBytes, err := json.Marshal(requestBody)
if err != nil {
return "", fmt.Errorf("error encoding request body: %v", err)
}
// Send a POST request to the specified URL with the request body
response, err := http.Post(
"http://"+h.LlamaURL+"/api/generate",
"application/json",
bytes.NewBuffer(requestBodyBytes),
)
if err != nil {
return "", fmt.Errorf("error sending POST request: %v", err)
}
defer response.Body.Close()
// Read the response body
responseBody, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("error reading response body: %v", err)
}
// Unmarshal the JSON response
var resp Response
if err := json.Unmarshal(responseBody, &resp); err != nil {
return "", fmt.Errorf("error decoding response body: %v", err)
}
// Return the response
return resp.Response, nil
}

View File

@@ -1,36 +0,0 @@
package storage
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gitlab.com/DeveloperDurp/DurpAPI/model"
)
func Connect(config model.DBConfig) (*model.Repository, error) {
dsn := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
config.Host, config.Port, config.User, config.Password, config.DBName, config.SSLMode,
)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
err = runMigrations(db)
if err != nil {
return nil, err
}
return &model.Repository{
DB: db,
}, nil
}
func runMigrations(db *gorm.DB) error {
err := db.AutoMigrate(&model.DadJoke{})
if err != nil {
return err
}
return nil
}