This commit is contained in:
lehel 2025-09-24 13:11:48 +02:00
parent 1a0bdce02d
commit 0e7d284f09
No known key found for this signature in database
GPG Key ID: 9C4F9D6111EE5CFA
3 changed files with 94 additions and 2 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

21
main.go
View File

@ -5,12 +5,12 @@ import (
"context"
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"text/template"
"time"
"github.com/gin-gonic/gin"
@ -230,6 +230,17 @@ func renderPrompt(tmplStr string, data any) (string, error) {
return buf.String(), nil
}
var uiTemplate *template.Template
func loadUITemplate(path string) error {
tmpl, err := template.ParseFiles(path)
if err != nil {
return err
}
uiTemplate = tmpl
return nil
}
func main() {
if err := loadConfig("config.yaml"); err != nil {
log.Fatalf("Failed to load config.yaml: %v", err)
@ -239,12 +250,18 @@ func main() {
log.Fatalf("Failed to load db.yaml: %v", err)
}
fmt.Printf("Loaded %d reasons from db.yaml\n", len(reasonsDB))
if err := loadUITemplate("ui.html"); err != nil {
log.Fatalf("Failed to load ui.html: %v", err)
}
llm := &LLMClient{
APIKey: os.Getenv("OPENAI_API_KEY"),
BaseURL: os.Getenv("OPENAI_BASE_URL"), // e.g. http://localhost:1234/v1/completions
}
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.Status(200)
uiTemplate.Execute(c.Writer, nil)
})
r.POST("/chat", func(c *gin.Context) {
var req ChatRequest
if err := c.ShouldBindJSON(&req); err != nil {

69
ui.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vet Clinic Chat Assistant</title>
<style>
body { font-family: sans-serif; margin: 2em; }
#chatbox { width: 100%; max-width: 600px; margin: 0 auto; }
#messages { border: 1px solid #ccc; min-height: 120px; padding: 1em; margin-bottom: 1em; background: #fafafa; }
.msg-user { color: #333; }
.msg-bot { color: #007a3d; margin-bottom: 1em; }
#input { width: 80%; padding: 0.5em; }
#send { padding: 0.5em 1em; }
</style>
</head>
<body>
<div id="chatbox">
<h2>Vet Clinic Chat Assistant</h2>
<div id="messages"></div>
<input id="input" type="text" placeholder="Type your message..." autofocus />
<button id="send">Send</button>
</div>
<script>
const messages = document.getElementById('messages');
const input = document.getElementById('input');
const send = document.getElementById('send');
function appendMsg(text, who) {
const div = document.createElement('div');
div.className = who === 'user' ? 'msg-user' : 'msg-bot';
div.textContent = text;
messages.appendChild(div);
messages.scrollTop = messages.scrollHeight;
}
send.onclick = async function() {
const msg = input.value.trim();
if (!msg) return;
appendMsg(msg, 'user');
input.value = '';
appendMsg('Thinking...', 'bot');
const resp = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: msg })
});
const data = await resp.json();
messages.lastChild.remove(); // remove 'Thinking...'
if (data.match) {
var txt = "Match: " + data.match + "\n";
if (data.procedures) {
txt += "Procedures:\n";
data.procedures.forEach(function(p) {
txt += "- " + p.name + ": " + p.price + " Ft, " + p.duration_minutes + " perc\n";
});
}
if (data.total_price) txt += "Total: " + data.total_price + " Ft\n";
if (data.total_duration) txt += "Total duration: " + data.total_duration + " perc\n";
if (data.notes) txt += "Notes: " + data.notes + "\n";
appendMsg(txt, 'bot');
} else {
appendMsg('Sorry, no match found. Your message will be sent to the vet.', 'bot');
}
};
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') send.onclick();
});
</script>
</body>
</html>