Remove suggestions
This commit is contained in:
35
main.go
35
main.go
@@ -12,7 +12,6 @@ import (
|
||||
type PHandler struct {
|
||||
tmpl *template.Template
|
||||
pd *pdClient
|
||||
oai *oaiClient
|
||||
mux *http.ServeMux
|
||||
}
|
||||
|
||||
@@ -28,20 +27,13 @@ func NewPHandler(routingKey string) (*PHandler, error) {
|
||||
return nil, fmt.Errorf("static/index.html: %w", err)
|
||||
}
|
||||
|
||||
oai, err := newOAIClientFromEnv()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("newOAIClientFromEnv: %w", err)
|
||||
}
|
||||
|
||||
ph := &PHandler{
|
||||
tmpl: tmpl,
|
||||
pd: newPDClient(routingKey),
|
||||
oai: oai,
|
||||
mux: http.NewServeMux(),
|
||||
}
|
||||
|
||||
ph.mux.HandleFunc("/{$}", ph.serveRoot)
|
||||
ph.mux.HandleFunc("/suggest", ph.serveSuggest)
|
||||
|
||||
return ph, nil
|
||||
}
|
||||
@@ -78,33 +70,6 @@ func (ph *PHandler) serveRoot(w http.ResponseWriter, r *http.Request) {
|
||||
sendResponse(w, "Page sent")
|
||||
}
|
||||
|
||||
func (ph *PHandler) serveSuggest(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
sendError(w, http.StatusBadRequest, "Parse form: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%s %s %s", r.RemoteAddr, r.URL.Path, r.Form.Encode())
|
||||
|
||||
m := r.Form.Get("m")
|
||||
if m == "" {
|
||||
sendError(w, http.StatusBadRequest, "m= param required")
|
||||
return
|
||||
}
|
||||
|
||||
comp, err := ph.oai.completeChat(
|
||||
`You are an assistant helping users to write good text to include in an urgent page sent to a person. Good page text contains a very brief description of the problem (e.g. "down" or "slow"), the systems it affects (acronyms for system names are fine), the identity of the sender (first names are fine), and how to contact them (e.g. a phone number or incident Slack channel). The request will consist of just the user's proposed page text. Respond with just a very brief message suggesting improvements that the sender might make or saying "Looks good -- send it!". Remember that the user is likely in an urgent, stressful situation, so make your response brief and err on the side of assuming that the message is sufficient if the text might be OK. Assume that the recipient already knows the message is urgent so the sender doesn't have to specify urgency.`,
|
||||
m,
|
||||
)
|
||||
if err != nil {
|
||||
sendError(w, http.StatusInternalServerError, "OpenAI error: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
sendSuggestResponse(w, comp)
|
||||
}
|
||||
|
||||
var allowedEnvs = []string{
|
||||
"SHORT_NAME",
|
||||
"CONTACT_NAME",
|
||||
|
||||
94
openai.go
94
openai.go
@@ -1,94 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type oaiClient struct {
|
||||
c *http.Client
|
||||
apiKey string
|
||||
}
|
||||
|
||||
type oaiRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []oaiMessage `json:"messages"`
|
||||
}
|
||||
|
||||
type oaiMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type oaiResponse struct {
|
||||
Choices []oaiChoice `json:"choices"`
|
||||
}
|
||||
|
||||
type oaiChoice struct {
|
||||
Message oaiMessage `json:"message"`
|
||||
}
|
||||
|
||||
func newOAIClient(apiKey string) *oaiClient {
|
||||
return &oaiClient{
|
||||
c: &http.Client{},
|
||||
apiKey: apiKey,
|
||||
}
|
||||
}
|
||||
|
||||
func newOAIClientFromEnv() (*oaiClient, error) {
|
||||
apiKey := os.Getenv("OPENAI_API_KEY")
|
||||
if apiKey == "" {
|
||||
return nil, fmt.Errorf("OPENAI_API_KEY is not set")
|
||||
}
|
||||
|
||||
return newOAIClient(apiKey), nil
|
||||
}
|
||||
|
||||
func (oai *oaiClient) completeChat(system, user string) (string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
err := json.NewEncoder(buf).Encode(&oaiRequest{
|
||||
Model: "gpt-4o",
|
||||
Messages: []oaiMessage{
|
||||
{Role: "system", Content: system},
|
||||
{Role: "user", Content: user},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", oai.apiKey))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := oai.c.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return "", fmt.Errorf("%s", string(body))
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
var res oaiResponse
|
||||
|
||||
err = dec.Decode(&res)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res.Choices[0].Message.Content, nil
|
||||
}
|
||||
@@ -57,11 +57,7 @@ sl-copy-button {
|
||||
/>
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/shoelace-autoloader.js"></script>
|
||||
<script>
|
||||
let suggestTimer = null;
|
||||
let lastSuggestMessage = null;
|
||||
|
||||
function clearAlerts() {
|
||||
document.getElementById('suggest').hide();
|
||||
document.getElementById('sent').hide();
|
||||
document.getElementById('err').hide();
|
||||
}
|
||||
@@ -108,63 +104,10 @@ async function page() {
|
||||
document.getElementById('sent').show();
|
||||
}
|
||||
|
||||
async function suggestLater() {
|
||||
if (suggestTimer) {
|
||||
clearTimeout(suggestTimer);
|
||||
}
|
||||
|
||||
suggestTimer = setTimeout(suggestNow, 2000);
|
||||
}
|
||||
|
||||
async function suggestNow() {
|
||||
if (suggestTimer) {
|
||||
clearTimeout(suggestTimer);
|
||||
suggestTimer = null;
|
||||
}
|
||||
|
||||
const m = document.getElementById('message').value;
|
||||
|
||||
if (m == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m == lastSuggestMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastSuggestMessage = m;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
m: m,
|
||||
});
|
||||
|
||||
const resp = await fetch('/suggest?' + params.toString());
|
||||
|
||||
if (!resp.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.getElementById('message').value != m) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('suggest-msg').innerText = (await resp.json()).message;
|
||||
document.getElementById('suggest').show();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
var msg = document.getElementById('message');
|
||||
|
||||
msg.focus();
|
||||
|
||||
msg.addEventListener('sl-input', () => {
|
||||
clearAlerts();
|
||||
suggestLater();
|
||||
});
|
||||
|
||||
msg.addEventListener('sl-blur', () => {
|
||||
suggestNow();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
@@ -181,10 +124,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
<sl-button type="submit" variant="danger" onclick="page()">Page {{.SHORT_NAME}}</sl-button>
|
||||
</div>
|
||||
<br />
|
||||
<sl-alert id="suggest" variant="primary">
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
<span id="suggest-msg"></span>
|
||||
</sl-alert>
|
||||
<sl-alert id="err" variant="danger">
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong id="err1"></strong><br />
|
||||
|
||||
Reference in New Issue
Block a user