Skip to content

Commit

Permalink
Introduce config context for the app
Browse files Browse the repository at this point in the history
  • Loading branch information
tearingItUp786 committed Mar 8, 2024
1 parent 65f9407 commit f3a7a81
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 5 deletions.
120 changes: 120 additions & 0 deletions config/config-handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package config

import (
"context"
"embed"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"regexp"

"github.com/tearingItUp786/chatgpt-tui/util"
)

// Define a type for your context key to avoid collisions with other context keys
type contextKey string

// Define a constant for your config context key
const configKey contextKey = "config"

// WithConfig returns a new context with the provided config
func WithConfig(ctx context.Context, config *Config) context.Context {
return context.WithValue(ctx, configKey, config)
}

// FromContext extracts the config from the context, if available
func FromContext(ctx context.Context) (*Config, bool) {
config, ok := ctx.Value(configKey).(*Config)
return config, ok
}

type Config struct {
ChatGPTApiUrl string `json:"chatGPTAPiUrl"`
SystemMessage string `json:"systemMessage"`
}

//go:embed config.json
var configEmbed embed.FS

func createConfig() (string, error) {
appPath, err := util.GetAppDataPath()
if err != nil {
fmt.Println("Error getting app path:", err)
panic(err)
}

pathToPersistedFile := filepath.Join(appPath, "config.json")

if _, err := os.Stat(pathToPersistedFile); os.IsNotExist(err) {
// The database does not exist, extract from embedded
configFile, err := configEmbed.Open("config.json")
if err != nil {
return "", err
}
defer configFile.Close()

// Ensure the directory exists
if err := os.MkdirAll(filepath.Dir(pathToPersistedFile), 0755); err != nil {
return "", err
}

// Create the persistent file
outFile, err := os.Create(pathToPersistedFile)
if err != nil {
return "", err
}
defer outFile.Close()

// Copy the embedded database to the persistent file
if _, err := io.Copy(outFile, configFile); err != nil {
return "", err
}
} else if err != nil {
// An error occurred checking for the file, unrelated to file existence
return "", err
}

return pathToPersistedFile, nil
}

func validateConfig(config Config) bool {
// Validate the ChatAPIURL format (simple example)
match, _ := regexp.MatchString(`^https?://`, config.ChatGPTApiUrl)
if !match {
fmt.Println("ChatAPIURL must be a valid URL")
return false
}
// Add any other validation logic here
return true
}

func CreateAndValidateConfig() Config {
configFilePath, err := createConfig()
if err != nil {
fmt.Printf("Error finding config JSON: %s", err)
panic(err)
}

content, err := os.ReadFile(configFilePath)
if err != nil {
fmt.Printf("Error reading config JSON: %s", err)
panic(err)
}

var config Config

err = json.Unmarshal(content, &config)
if err != nil {
fmt.Printf("Error parsing config JSON: %s", err)
panic(err)
}

isValidConfig := validateConfig(config)
if !isValidConfig {
panic(fmt.Errorf("Invalid config"))
}

return config
}
4 changes: 4 additions & 0 deletions config/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"chatGPTAPiUrl": "https://api.openai.com/v1/chat/completions",
"systemMessage": ""
}
16 changes: 13 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"database/sql"
"fmt"
"log"
Expand All @@ -15,6 +16,7 @@ import (

"github.com/joho/godotenv"
"github.com/muesli/reflow/wrap"
"github.com/tearingItUp786/chatgpt-tui/config"
"github.com/tearingItUp786/chatgpt-tui/migrations"
"github.com/tearingItUp786/chatgpt-tui/sessions"
"github.com/tearingItUp786/chatgpt-tui/settings"
Expand All @@ -40,13 +42,13 @@ type model struct {
terminalHeight int
}

func initialModal(db *sql.DB) model {
func initialModal(db *sql.DB, ctx context.Context) model {
ti := textinput.New()
ti.Placeholder = "Ask ChatGPT a question!"
ti.PromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(util.ActiveTabBorderColor))

si := settings.New(db)
sm := sessions.New(db)
sm := sessions.New(db, ctx)

msgChan := make(chan sessions.ProcessResult)

Expand Down Expand Up @@ -374,6 +376,11 @@ func main() {
os.Exit(1)
}

// delete files if in dev mode
util.DeleteFilesIfDevMode()
// validate config
configToUse := config.CreateAndValidateConfig()

// run migrations for our database
db := util.InitDb()
err = util.MigrateFS(db, migrations.FS, ".")
Expand All @@ -383,8 +390,11 @@ func main() {
}
defer db.Close()

ctx := context.Background()
ctxWithConfig := config.WithConfig(ctx, &configToUse)

p := tea.NewProgram(
initialModal(db),
initialModal(db, ctxWithConfig),
tea.WithAltScreen(),
// tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
)
Expand Down
11 changes: 10 additions & 1 deletion sessions/message-stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,16 @@ func ConstructUserMessage(content string) MessageToSend {
}
}

func constructSystemMessage(content string) MessageToSend {
return MessageToSend{
Role: "system",
Content: content,
}
}

func (m Model) constructJsonBody() ([]byte, error) {
messages := []MessageToSend{}
messages = append(messages, constructSystemMessage(m.config.SystemMessage))
for _, singleMessage := range m.ArrayOfMessages {
messages = append(messages, singleMessage)
}
Expand Down Expand Up @@ -85,7 +93,8 @@ func (m *Model) CallChatGpt(resultChan chan ProcessResult) tea.Cmd {
// API endpoint to call -- should be an env variable
req, err := http.NewRequest(
"POST",
"https://api.openai.com/v1/chat/completions",
// get this url from the config
m.config.ChatGPTApiUrl,
bytes.NewBuffer(body),
)
if err != nil {
Expand Down
12 changes: 11 additions & 1 deletion sessions/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/lipgloss"
"github.com/tearingItUp786/chatgpt-tui/config"
"github.com/tearingItUp786/chatgpt-tui/settings"
"github.com/tearingItUp786/chatgpt-tui/user"
"github.com/tearingItUp786/chatgpt-tui/util"
"golang.org/x/net/context"
)

const (
Expand All @@ -31,6 +33,7 @@ type Model struct {
sessionService *SessionService
userService *user.UserService
settingsContainer lipgloss.Style
config config.Config

Settings settings.Settings
CurrentSessionID int
Expand All @@ -44,7 +47,7 @@ type Model struct {
ProcessingMode string
}

func New(db *sql.DB) Model {
func New(db *sql.DB, ctx context.Context) Model {
ss := NewSessionService(db)
us := user.NewUserService(db)

Expand All @@ -55,7 +58,14 @@ func New(db *sql.DB) Model {
Frequency: 0,
}

config, ok := config.FromContext(ctx)
if !ok {
fmt.Println("No config found")
panic("No config found in context")
}

return Model{
config: *config,
ArrayOfProcessResult: []ProcessResult{},
sessionService: ss,
userService: us,
Expand Down
38 changes: 38 additions & 0 deletions util/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,44 @@ func GetAppDataPath() (string, error) {
//go:embed chat.db
var dbEmbed embed.FS

func CheckIfFileExistsInAppPath(name string) {
appPath, err := GetAppDataPath()
if err != nil {
panic(err)
}

pathToPersistFile := filepath.Join(appPath, name)

if _, err := os.Stat(pathToPersistFile); os.IsNotExist(err) {
// The database does not exist, extract from embedded
dbFile, err := dbEmbed.Open(name)
if err != nil {
panic(err)
}
defer dbFile.Close()

// Ensure the directory exists
if err := os.MkdirAll(filepath.Dir(pathToPersistFile), 0755); err != nil {
panic(err)
}

// Create the persistent file
outFile, err := os.Create(pathToPersistFile)
if err != nil {
panic(err)
}
defer outFile.Close()

// Copy the embedded database to the persistent file
if _, err := io.Copy(outFile, dbFile); err != nil {
panic(err)
}
} else if err != nil {
// An error occurred checking for the file, unrelated to file existence
panic(err)
}
}

func InitDb() *sql.DB {
appPath, err := GetAppDataPath()
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions util/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package util

import (
"log"
"os"
"path/filepath"
)

func DeleteFilesIfDevMode() {
if os.Getenv("DEV_MODE") == "true" {
// Delete the database file
appPath, err := GetAppDataPath()
if err != nil {
panic(err)
}
pathToPersistDb := filepath.Join(appPath, "chat.db")
err = os.Remove(pathToPersistDb)
if err != nil {
log.Println("Error deleting database file:", err)
}
// Delete the config file
pathToPersistedFile := filepath.Join(appPath, "config.json")
err = os.Remove(pathToPersistedFile)
if err != nil {
log.Println("Error deleting config file:", err)
}
}
}

0 comments on commit f3a7a81

Please sign in to comment.