🎉 Initial Commit
Some checks failed
release-nightly / build-docker (push) Has been cancelled
Some checks failed
release-nightly / build-docker (push) Has been cancelled
This commit is contained in:
24
pkg/internal/cache/store.go
vendored
Normal file
24
pkg/internal/cache/store.go
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/eko/gocache/lib/v4/store"
|
||||
ristrettoCache "github.com/eko/gocache/store/ristretto/v4"
|
||||
)
|
||||
|
||||
var S store.StoreInterface
|
||||
|
||||
func NewStore() error {
|
||||
ristretto, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1000,
|
||||
MaxCost: 100,
|
||||
BufferItems: 64,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
S = ristrettoCache.NewRistretto(ristretto)
|
||||
|
||||
return nil
|
||||
}
|
17
pkg/internal/database/migrator.go
Normal file
17
pkg/internal/database/migrator.go
Normal file
@ -0,0 +1,17 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var AutoMaintainRange = []any{}
|
||||
|
||||
func RunMigration(source *gorm.DB) error {
|
||||
if err := source.AutoMigrate(
|
||||
AutoMaintainRange...,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
27
pkg/internal/database/source.go
Normal file
27
pkg/internal/database/source.go
Normal file
@ -0,0 +1,27 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex/cruda"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/gap"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var C *gorm.DB
|
||||
|
||||
func NewGorm() error {
|
||||
var err error
|
||||
|
||||
dsn, err := cruda.NewCrudaConn(gap.Nx).AllocDatabase("insight")
|
||||
C, err = gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.New(&log.Logger, logger.Config{
|
||||
Colorful: true,
|
||||
IgnoreRecordNotFoundError: true,
|
||||
LogLevel: lo.Ternary(viper.GetBool("debug.database"), logger.Info, logger.Silent),
|
||||
})})
|
||||
|
||||
return err
|
||||
}
|
44
pkg/internal/gap/server.go
Normal file
44
pkg/internal/gap/server.go
Normal file
@ -0,0 +1,44 @@
|
||||
package gap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/proto"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var Nx *nex.Conn
|
||||
|
||||
func InitializeToNexus() error {
|
||||
grpcBind := strings.SplitN(viper.GetString("grpc_bind"), ":", 2)
|
||||
httpBind := strings.SplitN(viper.GetString("bind"), ":", 2)
|
||||
|
||||
outboundIp, _ := nex.GetOutboundIP()
|
||||
|
||||
grpcOutbound := fmt.Sprintf("%s:%s", outboundIp, grpcBind[1])
|
||||
httpOutbound := fmt.Sprintf("%s:%s", outboundIp, httpBind[1])
|
||||
|
||||
var err error
|
||||
Nx, err = nex.NewNexusConn(viper.GetString("nexus_addr"), &proto.ServiceInfo{
|
||||
Id: viper.GetString("id"),
|
||||
Type: "wa",
|
||||
Label: "Insight",
|
||||
GrpcAddr: grpcOutbound,
|
||||
HttpAddr: lo.ToPtr("http://" + httpOutbound + "/api"),
|
||||
})
|
||||
if err == nil {
|
||||
go func() {
|
||||
err := Nx.RunRegistering()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("An error occurred while registering service...")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
26
pkg/internal/grpc/health.go
Normal file
26
pkg/internal/grpc/health.go
Normal file
@ -0,0 +1,26 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
health "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (v *Server) Check(ctx context.Context, request *health.HealthCheckRequest) (*health.HealthCheckResponse, error) {
|
||||
return &health.HealthCheckResponse{
|
||||
Status: health.HealthCheckResponse_SERVING,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) Watch(request *health.HealthCheckRequest, server health.Health_WatchServer) error {
|
||||
for {
|
||||
if server.Send(&health.HealthCheckResponse{
|
||||
Status: health.HealthCheckResponse_SERVING,
|
||||
}) != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
25
pkg/internal/grpc/insight.go
Normal file
25
pkg/internal/grpc/insight.go
Normal file
@ -0,0 +1,25 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/services"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/proto"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (v *Server) GenerateInsight(ctx context.Context, request *proto.InsightRequest) (*proto.InsightResponse, error) {
|
||||
input := request.GetSource()
|
||||
if err := services.PlaceOrder(uint(request.GetUserId()), len(input)); err != nil {
|
||||
return nil, status.Errorf(codes.ResourceExhausted, fmt.Sprintf("failed to place order: %v", err))
|
||||
}
|
||||
|
||||
out, err := services.GenerateInsights(input)
|
||||
if err != nil {
|
||||
_ = services.MakeRefund(uint(request.GetUserId()), len(input))
|
||||
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to generate insight: %v", err))
|
||||
}
|
||||
|
||||
return &proto.InsightResponse{Response: out}, nil
|
||||
}
|
43
pkg/internal/grpc/server.go
Normal file
43
pkg/internal/grpc/server.go
Normal file
@ -0,0 +1,43 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
iproto "git.solsynth.dev/hypernet/insight/pkg/proto"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/proto"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
health "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
proto.UnimplementedDirectoryServiceServer
|
||||
iproto.UnimplementedInsightServiceServer
|
||||
health.UnimplementedHealthServer
|
||||
|
||||
srv *grpc.Server
|
||||
}
|
||||
|
||||
func NewGrpc() *Server {
|
||||
server := &Server{
|
||||
srv: grpc.NewServer(),
|
||||
}
|
||||
|
||||
proto.RegisterDirectoryServiceServer(server.srv, server)
|
||||
iproto.RegisterInsightServiceServer(server.srv, server)
|
||||
health.RegisterHealthServer(server.srv, server)
|
||||
|
||||
reflection.Register(server.srv)
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func (v *Server) Listen() error {
|
||||
listener, err := net.Listen("tcp", viper.GetString("grpc_bind"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return v.srv.Serve(listener)
|
||||
}
|
42
pkg/internal/grpc/services.go
Normal file
42
pkg/internal/grpc/services.go
Normal file
@ -0,0 +1,42 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex"
|
||||
"strconv"
|
||||
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/proto"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/database"
|
||||
)
|
||||
|
||||
func (v *Server) BroadcastEvent(ctx context.Context, in *proto.EventInfo) (*proto.EventResponse, error) {
|
||||
switch in.GetEvent() {
|
||||
case "deletion":
|
||||
data := nex.DecodeMap(in.GetData())
|
||||
resType, ok := data["type"].(string)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
switch resType {
|
||||
case "account":
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
numericId, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
tx := database.C.Begin()
|
||||
for _, model := range database.AutoMaintainRange {
|
||||
switch model.(type) {
|
||||
default:
|
||||
tx.Delete(model, "account_id = ?", numericId)
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
}
|
||||
}
|
||||
|
||||
return &proto.EventResponse{}, nil
|
||||
}
|
5
pkg/internal/meta.go
Normal file
5
pkg/internal/meta.go
Normal file
@ -0,0 +1,5 @@
|
||||
package pkg
|
||||
|
||||
const (
|
||||
AppVersion = "1.0.0"
|
||||
)
|
19
pkg/internal/server/api/index.go
Normal file
19
pkg/internal/server/api/index.go
Normal file
@ -0,0 +1,19 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/services"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func MapAPIs(app *fiber.App, baseURL string) {
|
||||
api := app.Group(baseURL).Name("API")
|
||||
{
|
||||
api.Get("/status", func(c *fiber.Ctx) error {
|
||||
err := services.PingOllama()
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusServiceUnavailable, err.Error())
|
||||
}
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
}
|
||||
}
|
18
pkg/internal/server/exts/utils.go
Normal file
18
pkg/internal/server/exts/utils.go
Normal file
@ -0,0 +1,18 @@
|
||||
package exts
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
var validation = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
func BindAndValidate(c *fiber.Ctx, out any) error {
|
||||
if err := c.BodyParser(out); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
} else if err := validation.Struct(out); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
71
pkg/internal/server/server.go
Normal file
71
pkg/internal/server/server.go
Normal file
@ -0,0 +1,71 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex/sec"
|
||||
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/server/api"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/idempotency"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var IReader *sec.InternalTokenReader
|
||||
|
||||
type App struct {
|
||||
app *fiber.App
|
||||
}
|
||||
|
||||
func NewServer() *App {
|
||||
app := fiber.New(fiber.Config{
|
||||
DisableStartupMessage: true,
|
||||
EnableIPValidation: true,
|
||||
ServerHeader: "Hypernet.Insight",
|
||||
AppName: "Hypernet.Insight",
|
||||
ProxyHeader: fiber.HeaderXForwardedFor,
|
||||
JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal,
|
||||
JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal,
|
||||
BodyLimit: 512 * 1024 * 1024 * 1024, // 512 TiB
|
||||
EnablePrintRoutes: viper.GetBool("debug.print_routes"),
|
||||
})
|
||||
|
||||
app.Use(idempotency.New())
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowCredentials: true,
|
||||
AllowMethods: strings.Join([]string{
|
||||
fiber.MethodGet,
|
||||
fiber.MethodPost,
|
||||
fiber.MethodHead,
|
||||
fiber.MethodOptions,
|
||||
fiber.MethodPut,
|
||||
fiber.MethodDelete,
|
||||
fiber.MethodPatch,
|
||||
}, ","),
|
||||
AllowOriginsFunc: func(origin string) bool {
|
||||
return true
|
||||
},
|
||||
}))
|
||||
|
||||
app.Use(logger.New(logger.Config{
|
||||
Format: "${status} | ${latency} | ${method} ${path}\n",
|
||||
Output: log.Logger,
|
||||
}))
|
||||
|
||||
app.Use(sec.ContextMiddleware(IReader))
|
||||
|
||||
api.MapAPIs(app, "/api")
|
||||
|
||||
return &App{app}
|
||||
}
|
||||
|
||||
func (v *App) Listen() {
|
||||
if err := v.app.Listen(viper.GetString("bind")); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when starting server...")
|
||||
}
|
||||
}
|
24
pkg/internal/services/cleaner.go
Normal file
24
pkg/internal/services/cleaner.go
Normal file
@ -0,0 +1,24 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
database2 "git.solsynth.dev/hypernet/insight/pkg/internal/database"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func DoAutoDatabaseCleanup() {
|
||||
deadline := time.Now().Add(60 * time.Minute)
|
||||
log.Debug().Time("deadline", deadline).Msg("Now cleaning up entire database...")
|
||||
|
||||
var count int64
|
||||
for _, model := range database2.AutoMaintainRange {
|
||||
tx := database2.C.Unscoped().Delete(model, "deleted_at >= ?", deadline)
|
||||
if tx.Error != nil {
|
||||
log.Error().Err(tx.Error).Msg("An error occurred when running auth context cleanup...")
|
||||
}
|
||||
count += tx.RowsAffected
|
||||
}
|
||||
|
||||
log.Debug().Int64("affected", count).Msg("Clean up entire database accomplished.")
|
||||
}
|
59
pkg/internal/services/ollama.go
Normal file
59
pkg/internal/services/ollama.go
Normal file
@ -0,0 +1,59 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
"github.com/tmc/langchaingo/llms/ollama"
|
||||
"github.com/tmc/langchaingo/prompts"
|
||||
)
|
||||
|
||||
func PingOllama() error {
|
||||
host := viper.GetString("ollama.url")
|
||||
resp, err := http.Get(host + "/api/version")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to ping ollama: %v", err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("ollama returned status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var LargeModel *ollama.LLM
|
||||
|
||||
func ConnectOllama() error {
|
||||
model := viper.GetString("ollama.model")
|
||||
llm, err := ollama.New(ollama.WithModel(model))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
LargeModel = llm
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenerateInsights(source string) (string, error) {
|
||||
prompt := prompts.NewPromptTemplate(
|
||||
"Summerize this post on Solar Network below: {{.content}}",
|
||||
[]string{"content"},
|
||||
)
|
||||
inPrompt, err := prompt.Format(map[string]any{
|
||||
"content": source,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to format prompt: %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
|
||||
defer cancel()
|
||||
completion, err := LargeModel.Call(ctx, inPrompt,
|
||||
llms.WithTemperature(0.8),
|
||||
)
|
||||
|
||||
return completion, err
|
||||
}
|
69
pkg/internal/services/payment.go
Normal file
69
pkg/internal/services/payment.go
Normal file
@ -0,0 +1,69 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/gap"
|
||||
wproto "git.solsynth.dev/hypernet/wallet/pkg/proto"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// PlaceOrder create a transaction if needed for user
|
||||
// Pricing is 128 words input cost 10 source points, round up.
|
||||
func PlaceOrder(user uint, inputLength int) error {
|
||||
amount := float64(inputLength+128-1) / 128
|
||||
|
||||
conn, err := gap.Nx.GetClientGrpcConn("wa")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect wallet: %v", err)
|
||||
}
|
||||
|
||||
wc := wproto.NewPaymentServiceClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
resp, err := wc.MakeTransactionWithAccount(ctx, &wproto.MakeTransactionWithAccountRequest{
|
||||
PayerAccountId: lo.ToPtr(uint64(user)),
|
||||
Amount: amount,
|
||||
Remark: "Insight Thinking Fee",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Uint64("transaction", resp.Id).Float64("amount", amount).
|
||||
Msg("Order placed for charge insight thinking fee...")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeRefund to user who got error in generating insight
|
||||
func MakeRefund(user uint, inputLength int) error {
|
||||
amount := float64(inputLength+128-1) / 128
|
||||
|
||||
conn, err := gap.Nx.GetClientGrpcConn("wa")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect wallet: %v", err)
|
||||
}
|
||||
|
||||
wc := wproto.NewPaymentServiceClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
resp, err := wc.MakeTransactionWithAccount(ctx, &wproto.MakeTransactionWithAccountRequest{
|
||||
PayeeAccountId: lo.ToPtr(uint64(user)),
|
||||
Amount: amount,
|
||||
Remark: "Insight Thinking Failed - Refund",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Uint64("transaction", resp.Id).Float64("amount", amount).
|
||||
Msg("Refund placed for insight thinking fee...")
|
||||
|
||||
return nil
|
||||
}
|
97
pkg/main.go
Normal file
97
pkg/main.go
Normal file
@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
pkg "git.solsynth.dev/hypernet/insight/pkg/internal"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/gap"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex/sec"
|
||||
"github.com/fatih/color"
|
||||
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/cache"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/database"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/grpc"
|
||||
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/server"
|
||||
"git.solsynth.dev/hypernet/insight/pkg/internal/services"
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout})
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Booting screen
|
||||
fmt.Println(color.YellowString(" ___ _ _ _\n|_ _|_ __ ___(_) __ _| |__ | |_\n | || '_ \\/ __| |/ _` | '_ \\| __|\n | || | | \\__ \\ | (_| | | | | |_\n|___|_| |_|___/_|\\__, |_| |_|\\__|\n |___/"))
|
||||
fmt.Printf("%s v%s\n", color.New(color.FgHiYellow).Add(color.Bold).Sprintf("Hypernet.Insight"), pkg.AppVersion)
|
||||
fmt.Printf("The A-word in Hypernet.\n")
|
||||
color.HiBlack("=====================================================\n")
|
||||
|
||||
// Configure settings
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("..")
|
||||
viper.SetConfigName("settings")
|
||||
viper.SetConfigType("toml")
|
||||
|
||||
// Load settings
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Panic().Err(err).Msg("An error occurred when loading settings.")
|
||||
}
|
||||
|
||||
// Connect to nexus
|
||||
if err := gap.InitializeToNexus(); err != nil {
|
||||
log.Error().Err(err).Msg("An error occurred when registering service to nexus...")
|
||||
}
|
||||
|
||||
// Load keypair
|
||||
if reader, err := sec.NewInternalTokenReader(viper.GetString("security.internal_public_key")); err != nil {
|
||||
log.Error().Err(err).Msg("An error occurred when reading internal public key for jwt. Authentication related features will be disabled.")
|
||||
} else {
|
||||
server.IReader = reader
|
||||
log.Info().Msg("Internal jwt public key loaded.")
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
if err := database.NewGorm(); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when connect to database.")
|
||||
} else if err := database.RunMigration(database.C); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when running database auto migration.")
|
||||
}
|
||||
|
||||
// Connect to ollama
|
||||
if err := services.ConnectOllama(); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when connecting to ollama.")
|
||||
}
|
||||
|
||||
// Initialize cache
|
||||
if err := cache.NewStore(); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when initializing cache.")
|
||||
}
|
||||
|
||||
// Configure timed tasks
|
||||
quartz := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(&log.Logger)))
|
||||
quartz.AddFunc("@every 60m", services.DoAutoDatabaseCleanup)
|
||||
quartz.Start()
|
||||
|
||||
// Server
|
||||
go server.NewServer().Listen()
|
||||
|
||||
// Grpc Server
|
||||
go grpc.NewGrpc().Listen()
|
||||
|
||||
// Messages
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
quartz.Stop()
|
||||
}
|
192
pkg/proto/insight.pb.go
Normal file
192
pkg/proto/insight.pb.go
Normal file
@ -0,0 +1,192 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc v5.28.3
|
||||
// source: insight.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type InsightRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"`
|
||||
UserId uint64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *InsightRequest) Reset() {
|
||||
*x = InsightRequest{}
|
||||
mi := &file_insight_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *InsightRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*InsightRequest) ProtoMessage() {}
|
||||
|
||||
func (x *InsightRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_insight_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use InsightRequest.ProtoReflect.Descriptor instead.
|
||||
func (*InsightRequest) Descriptor() ([]byte, []int) {
|
||||
return file_insight_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *InsightRequest) GetSource() string {
|
||||
if x != nil {
|
||||
return x.Source
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *InsightRequest) GetUserId() uint64 {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type InsightResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Response string `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"`
|
||||
}
|
||||
|
||||
func (x *InsightResponse) Reset() {
|
||||
*x = InsightResponse{}
|
||||
mi := &file_insight_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *InsightResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*InsightResponse) ProtoMessage() {}
|
||||
|
||||
func (x *InsightResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_insight_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use InsightResponse.ProtoReflect.Descriptor instead.
|
||||
func (*InsightResponse) Descriptor() ([]byte, []int) {
|
||||
return file_insight_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *InsightResponse) GetResponse() string {
|
||||
if x != nil {
|
||||
return x.Response
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_insight_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_insight_proto_rawDesc = []byte{
|
||||
0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x2d, 0x0a, 0x0f, 0x49, 0x6e, 0x73,
|
||||
0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x54, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x69,
|
||||
0x67, 0x68, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x0a, 0x0f, 0x47, 0x65,
|
||||
0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x12, 0x15, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x73,
|
||||
0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09,
|
||||
0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_insight_proto_rawDescOnce sync.Once
|
||||
file_insight_proto_rawDescData = file_insight_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_insight_proto_rawDescGZIP() []byte {
|
||||
file_insight_proto_rawDescOnce.Do(func() {
|
||||
file_insight_proto_rawDescData = protoimpl.X.CompressGZIP(file_insight_proto_rawDescData)
|
||||
})
|
||||
return file_insight_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_insight_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_insight_proto_goTypes = []any{
|
||||
(*InsightRequest)(nil), // 0: proto.InsightRequest
|
||||
(*InsightResponse)(nil), // 1: proto.InsightResponse
|
||||
}
|
||||
var file_insight_proto_depIdxs = []int32{
|
||||
0, // 0: proto.InsightService.GenerateInsight:input_type -> proto.InsightRequest
|
||||
1, // 1: proto.InsightService.GenerateInsight:output_type -> proto.InsightResponse
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_insight_proto_init() }
|
||||
func file_insight_proto_init() {
|
||||
if File_insight_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_insight_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_insight_proto_goTypes,
|
||||
DependencyIndexes: file_insight_proto_depIdxs,
|
||||
MessageInfos: file_insight_proto_msgTypes,
|
||||
}.Build()
|
||||
File_insight_proto = out.File
|
||||
file_insight_proto_rawDesc = nil
|
||||
file_insight_proto_goTypes = nil
|
||||
file_insight_proto_depIdxs = nil
|
||||
}
|
18
pkg/proto/insight.proto
Normal file
18
pkg/proto/insight.proto
Normal file
@ -0,0 +1,18 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = ".;proto";
|
||||
|
||||
package proto;
|
||||
|
||||
service InsightService {
|
||||
rpc GenerateInsight(InsightRequest) returns (InsightResponse) {}
|
||||
}
|
||||
|
||||
message InsightRequest {
|
||||
string source = 1;
|
||||
uint64 user_id = 2;
|
||||
}
|
||||
|
||||
message InsightResponse {
|
||||
string response = 1;
|
||||
}
|
121
pkg/proto/insight_grpc.pb.go
Normal file
121
pkg/proto/insight_grpc.pb.go
Normal file
@ -0,0 +1,121 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.28.3
|
||||
// source: insight.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
InsightService_GenerateInsight_FullMethodName = "/proto.InsightService/GenerateInsight"
|
||||
)
|
||||
|
||||
// InsightServiceClient is the client API for InsightService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type InsightServiceClient interface {
|
||||
GenerateInsight(ctx context.Context, in *InsightRequest, opts ...grpc.CallOption) (*InsightResponse, error)
|
||||
}
|
||||
|
||||
type insightServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewInsightServiceClient(cc grpc.ClientConnInterface) InsightServiceClient {
|
||||
return &insightServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *insightServiceClient) GenerateInsight(ctx context.Context, in *InsightRequest, opts ...grpc.CallOption) (*InsightResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(InsightResponse)
|
||||
err := c.cc.Invoke(ctx, InsightService_GenerateInsight_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// InsightServiceServer is the server API for InsightService service.
|
||||
// All implementations must embed UnimplementedInsightServiceServer
|
||||
// for forward compatibility.
|
||||
type InsightServiceServer interface {
|
||||
GenerateInsight(context.Context, *InsightRequest) (*InsightResponse, error)
|
||||
mustEmbedUnimplementedInsightServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedInsightServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedInsightServiceServer struct{}
|
||||
|
||||
func (UnimplementedInsightServiceServer) GenerateInsight(context.Context, *InsightRequest) (*InsightResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GenerateInsight not implemented")
|
||||
}
|
||||
func (UnimplementedInsightServiceServer) mustEmbedUnimplementedInsightServiceServer() {}
|
||||
func (UnimplementedInsightServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeInsightServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to InsightServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeInsightServiceServer interface {
|
||||
mustEmbedUnimplementedInsightServiceServer()
|
||||
}
|
||||
|
||||
func RegisterInsightServiceServer(s grpc.ServiceRegistrar, srv InsightServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedInsightServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&InsightService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _InsightService_GenerateInsight_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(InsightRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InsightServiceServer).GenerateInsight(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InsightService_GenerateInsight_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InsightServiceServer).GenerateInsight(ctx, req.(*InsightRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// InsightService_ServiceDesc is the grpc.ServiceDesc for InsightService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var InsightService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.InsightService",
|
||||
HandlerType: (*InsightServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GenerateInsight",
|
||||
Handler: _InsightService_GenerateInsight_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "insight.proto",
|
||||
}
|
Reference in New Issue
Block a user