Add reset, some minor UX tweaks
This commit is contained in:
3
Makefile
3
Makefile
@@ -4,6 +4,9 @@ IMAGE_NAME?=webui
|
|||||||
tests:
|
tests:
|
||||||
$(GOCMD) run github.com/onsi/ginkgo/v2/ginkgo --fail-fast -v -r ./...
|
$(GOCMD) run github.com/onsi/ginkgo/v2/ginkgo --fail-fast -v -r ./...
|
||||||
|
|
||||||
|
webui-nokb:
|
||||||
|
$(MAKE) webui KBDISABLEINDEX=true
|
||||||
|
|
||||||
webui:
|
webui:
|
||||||
cd example/webui && $(GOCMD) run ./
|
cd example/webui && $(GOCMD) run ./
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Agent struct {
|
|||||||
|
|
||||||
type RAGDB interface {
|
type RAGDB interface {
|
||||||
Store(s string) error
|
Store(s string) error
|
||||||
|
Reset() error
|
||||||
Search(s string, similarEntries int) ([]string, error)
|
Search(s string, similarEntries int) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (a *App) KnowledgeBaseReset(db *InMemoryDatabase) func(c *fiber.Ctx) error {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
db.Reset()
|
||||||
|
return c.Redirect("/knowledgebase")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) KnowledgeBaseFile(db *InMemoryDatabase) func(c *fiber.Ctx) error {
|
func (a *App) KnowledgeBaseFile(db *InMemoryDatabase) func(c *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
// https://golang.withcodeexample.com/blog/file-upload-handling-golang-fiber-guide/
|
// https://golang.withcodeexample.com/blog/file-upload-handling-golang-fiber-guide/
|
||||||
|
|||||||
@@ -74,6 +74,17 @@ func (db *InMemoryDatabase) SaveToStore() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *InMemoryDatabase) Reset() error {
|
||||||
|
db.Lock()
|
||||||
|
db.Database = []string{}
|
||||||
|
db.Unlock()
|
||||||
|
if err := db.rag.Reset(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return db.SaveDB()
|
||||||
|
}
|
||||||
|
|
||||||
func (db *InMemoryDatabase) AddEntry(entry string) error {
|
func (db *InMemoryDatabase) AddEntry(entry string) error {
|
||||||
db.Lock()
|
db.Lock()
|
||||||
defer db.Unlock()
|
defer db.Unlock()
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ func RegisterRoutes(webapp *fiber.App, pool *AgentPool, db *InMemoryDatabase, ap
|
|||||||
webapp.Post("/chat/:name", app.Chat(pool))
|
webapp.Post("/chat/:name", app.Chat(pool))
|
||||||
webapp.Post("/create", app.Create(pool))
|
webapp.Post("/create", app.Create(pool))
|
||||||
webapp.Get("/delete/:name", app.Delete(pool))
|
webapp.Get("/delete/:name", app.Delete(pool))
|
||||||
|
|
||||||
webapp.Post("/knowledgebase", app.KnowledgeBase(db))
|
webapp.Post("/knowledgebase", app.KnowledgeBase(db))
|
||||||
webapp.Post("/knowledgebase/upload", app.KnowledgeBaseFile(db))
|
webapp.Post("/knowledgebase/upload", app.KnowledgeBaseFile(db))
|
||||||
|
webapp.Delete("/knowledgebase/reset", app.KnowledgeBaseReset(db))
|
||||||
|
|
||||||
webapp.Get("/talk/:name", func(c *fiber.Ctx) error {
|
webapp.Get("/talk/:name", func(c *fiber.Ctx) error {
|
||||||
return c.Render("views/chat", fiber.Map{
|
return c.Render("views/chat", fiber.Map{
|
||||||
|
|||||||
@@ -3,24 +3,70 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Smart Assistant Dashboard</title>
|
<title>Smart Assistant Dashboard</title>
|
||||||
{{template "views/partials/header"}}
|
{{template "views/partials/header"}}
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.card-link {
|
||||||
|
text-decoration: none; /* Removes underline from links */
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px auto;
|
||||||
|
text-align: left;
|
||||||
|
width: 90%;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease; /* Smooth transition for hover effects */
|
||||||
|
display: block; /* Ensures the link fills the card */
|
||||||
|
}
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px); /* Slight lift effect */
|
||||||
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); /* Shadow for depth */
|
||||||
|
}
|
||||||
|
.card h2 {
|
||||||
|
font-size: 1.5em; /* Larger and more prominent */
|
||||||
|
font-weight: bold; /* Ensures boldness */
|
||||||
|
color: white; /* Ensures visibility against the card's background */
|
||||||
|
margin-bottom: 0.5em; /* Space below the heading */
|
||||||
|
}
|
||||||
|
.card a,
|
||||||
|
.card p {
|
||||||
|
color: white; /* Ensures text color is consistent */
|
||||||
|
}
|
||||||
|
.card p {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.image-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-900 p-4 text-white font-sans">
|
<body class="bg-gray-900 p-4 text-white font-sans">
|
||||||
{{template "views/partials/menu"}}
|
{{template "views/partials/menu"}}
|
||||||
<div class="max-w-4xl mx-auto">
|
<div class="container">
|
||||||
<header class="text-center mb-8">
|
<div class="image-container">
|
||||||
<h1 class="text-3xl md:text-5xl font-bold">Smart Agent Dashboard</h1>
|
<img src="/public/logo_1.png" width="250" alt="Company Logo">
|
||||||
</header>
|
</div>
|
||||||
<div class="flex flex-col items-center space-y-4">
|
<!-- Card for Agent List Page -->
|
||||||
<img class="flex" src="/public/logo_1.png" width="250">
|
<a href="/agents" class="card-link">
|
||||||
<!-- Button to Agent List Page -->
|
<div class="card">
|
||||||
<a href="/agents" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
<h2>Agent List</h2>
|
||||||
Agent List
|
<p>View and manage your list of agents, including detailed profiles and statistics.</p>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<!-- Button to Knowledgebase Management Page -->
|
<!-- Card for Knowledgebase Management Page -->
|
||||||
<a href="/knowledgebase" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
|
<a href="/knowledgebase" class="card-link">
|
||||||
Manage Knowledgebase
|
<div class="card">
|
||||||
|
<h2>Manage Knowledgebase</h2>
|
||||||
|
<p>Access and update your knowledgebase to improve agent responses and efficiency.</p>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,55 +6,86 @@
|
|||||||
<script src="https://unpkg.com/htmx.org"></script>
|
<script src="https://unpkg.com/htmx.org"></script>
|
||||||
<script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script>
|
<script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script>
|
||||||
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
|
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
|
||||||
|
<style>
|
||||||
|
.section-box {
|
||||||
|
background-color: #2a2a2a; /* Darker background for the form */
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #1a1a1a; /* Lighter overall background */
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"], input[type="file"] {
|
||||||
|
background-color: #333333;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #4a76a8; /* Blue color for buttons */
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #5a86b8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-900 p-4 text-white font-sans">
|
<body>
|
||||||
{{template "views/partials/menu"}}
|
{{template "views/partials/menu"}}
|
||||||
<header class="text-center mb-8">
|
<header class="text-center mb-8">
|
||||||
<h1 class="text-3xl md:text-5xl font-bold">Knowledgebase (items: {{.KnowledgebaseItemsCount}})</h1>
|
<h1 class="text-3xl md:text-5xl font-bold">Knowledgebase (items: {{.KnowledgebaseItemsCount}})</h1>
|
||||||
</header>
|
</header>
|
||||||
<div class="max-w-2xl mx-auto my-12 bg-gray-800 p-8 rounded-lg shadow-lg">
|
<div class="max-w-4xl mx-auto">
|
||||||
<form action="/knowledgebase" method="POST" class="space-y-6">
|
<!-- Add Site Form -->
|
||||||
Add sites to KB
|
<div class="section-box">
|
||||||
<div class="mb-6">
|
<form action="/knowledgebase" method="POST">
|
||||||
<label for="url" class="block text-lg font-medium text-gray-400">URL</label>
|
<h2>Add sites to KB</h2>
|
||||||
<input type="text" name="url" id="url" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md bg-gray-700 text-white" placeholder="Name">
|
<label for="url">URL:</label>
|
||||||
</div>
|
<input type="text" name="url" id="url" placeholder="Enter URL here">
|
||||||
<div class="mb-6">
|
<label for="chunk_size">Chunk size:</label>
|
||||||
<label for="chunk_size" class="block text-lg font-medium text-gray-400">Chunk size</label>
|
<input type="text" name="chunk_size" id="chunk_size" placeholder="Enter chunk size here">
|
||||||
<input type="text" name="chunk_size" id="chunk_size" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md bg-gray-700 text-white" placeholder="380">
|
<button type="submit">Add Site</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- File Upload Form -->
|
||||||
|
<div class="section-box">
|
||||||
|
<form id='form' hx-encoding='multipart/form-data' hx-post='/knowledgebase/upload'>
|
||||||
|
<h2>Upload File</h2>
|
||||||
|
<label for="file">File:</label>
|
||||||
|
<input type='file' name='file' id='file'>
|
||||||
|
<label for="chunk_size">Chunk size:</label>
|
||||||
|
<input type="text" name="chunk_size" id="chunk_size" placeholder="Enter chunk size here">
|
||||||
|
<button type="submit">Upload File</button>
|
||||||
|
<progress id='progress' value='0' max='100'></progress>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<!-- Reset Knowledge Base -->
|
||||||
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-500 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
<div class="section-box">
|
||||||
Add Site
|
<button hx-swap="none" hx-trigger="click" hx-delete="/knowledgebase/reset">Reset Knowledge Base</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
<form id='form' hx-encoding='multipart/form-data' hx-post='/knowledgebase/upload'>
|
|
||||||
<div class="mb-6">
|
|
||||||
<label for="file" class="block text-lg font-medium text-gray-400">File</label>
|
|
||||||
<input type='file' name='file' id='file' class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md bg-gray-700 text-white">
|
|
||||||
</div>
|
|
||||||
<div class="mb-6">
|
|
||||||
<label for="chunk_size" class="block text-lg font-medium text-gray-400">Chunk size</label>
|
|
||||||
<input type="text" name="chunk_size" id="chunk_size" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md bg-gray-700 text-white" placeholder="380">
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-500 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
|
||||||
Upload file
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="mb-6">
|
|
||||||
<progress id='progress' value='0' max='100'></progress>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<script>
|
<script>
|
||||||
htmx.on('#form', 'htmx:xhr:progress', function(evt) {
|
htmx.on('#form', 'htmx:xhr:progress', function(evt) {
|
||||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
|
htmx.find('#progress').setAttribute('value', evt.detail.loaded / evt.detail.total * 100);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,9 +2,14 @@
|
|||||||
<div class="px-4 sm:px-6 lg:px-8">
|
<div class="px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex justify-between h-16">
|
<div class="flex justify-between h-16">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
|
<!-- Logo container -->
|
||||||
<div class="flex-shrink-0 flex items-center">
|
<div class="flex-shrink-0 flex items-center">
|
||||||
|
<!-- Replace 'logo.png' with the actual path to your logo image -->
|
||||||
|
<a href="/" >
|
||||||
|
<img src="/public/logo_1.png" alt="Logo" class="h-8 w-auto mr-3">
|
||||||
|
</a>
|
||||||
<a href="/" class="px-3 py-2 rounded-md text-sm font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">
|
<a href="/" class="px-3 py-2 rounded-md text-sm font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">
|
||||||
<i class="fas fa-home"></i> Home
|
<i class="fas fa-home"></i> LocalAgent
|
||||||
</a>
|
</a>
|
||||||
<a href="/agents" class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">
|
<a href="/agents" class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">
|
||||||
<i class="fas fa-users"></i> Agent list
|
<i class="fas fa-users"></i> Agent list
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ type ChromemDB struct {
|
|||||||
collectionName string
|
collectionName string
|
||||||
collection *chromem.Collection
|
collection *chromem.Collection
|
||||||
index int
|
index int
|
||||||
|
client *openai.Client
|
||||||
|
db *chromem.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChromemDB(collection, path string, openaiClient *openai.Client) (*ChromemDB, error) {
|
func NewChromemDB(collection, path string, openaiClient *openai.Client) (*ChromemDB, error) {
|
||||||
@@ -22,9 +24,39 @@ func NewChromemDB(collection, path string, openaiClient *openai.Client) (*Chrome
|
|||||||
// }
|
// }
|
||||||
db := chromem.NewDB()
|
db := chromem.NewDB()
|
||||||
|
|
||||||
embeddingFunc := chromem.EmbeddingFunc(
|
chromem := &ChromemDB{
|
||||||
|
collectionName: collection,
|
||||||
|
index: 1,
|
||||||
|
db: db,
|
||||||
|
client: openaiClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := db.GetOrCreateCollection(collection, nil, chromem.embedding())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
chromem.collection = c
|
||||||
|
|
||||||
|
return chromem, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChromemDB) Reset() error {
|
||||||
|
if err := c.db.DeleteCollection(c.collectionName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
collection, err := c.db.GetOrCreateCollection(c.collectionName, nil, c.embedding())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.collection = collection
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChromemDB) embedding() chromem.EmbeddingFunc {
|
||||||
|
return chromem.EmbeddingFunc(
|
||||||
func(ctx context.Context, text string) ([]float32, error) {
|
func(ctx context.Context, text string) ([]float32, error) {
|
||||||
resp, err := openaiClient.CreateEmbeddings(ctx,
|
resp, err := c.client.CreateEmbeddings(ctx,
|
||||||
openai.EmbeddingRequestStrings{
|
openai.EmbeddingRequestStrings{
|
||||||
Input: []string{text},
|
Input: []string{text},
|
||||||
Model: openai.AdaEmbeddingV2,
|
Model: openai.AdaEmbeddingV2,
|
||||||
@@ -43,17 +75,6 @@ func NewChromemDB(collection, path string, openaiClient *openai.Client) (*Chrome
|
|||||||
return embedding, nil
|
return embedding, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
c, err := db.GetOrCreateCollection(collection, nil, embeddingFunc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ChromemDB{
|
|
||||||
collectionName: collection,
|
|
||||||
collection: c,
|
|
||||||
index: 1,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChromemDB) Store(s string) error {
|
func (c *ChromemDB) Store(s string) error {
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ func NewLocalAIRAGDB(storeClient *StoreClient, openaiClient *openai.Client) *Loc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *LocalAIRAGDB) Reset() error {
|
||||||
|
return fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (db *LocalAIRAGDB) Store(s string) error {
|
func (db *LocalAIRAGDB) Store(s string) error {
|
||||||
resp, err := db.openaiClient.CreateEmbeddings(context.TODO(),
|
resp, err := db.openaiClient.CreateEmbeddings(context.TODO(),
|
||||||
openai.EmbeddingRequestStrings{
|
openai.EmbeddingRequestStrings{
|
||||||
|
|||||||
Reference in New Issue
Block a user