nidus-sync/llm/openai.go
Eli Ribble b8e7b9b7fd
Working LLM responses and Twilio status tracking
The responses aren't good, but they do exist.
2026-01-27 14:29:55 +00:00

101 lines
3.4 KiB
Go

package llm
import (
"context"
"fmt"
"strings"
"github.com/maruel/genai"
"github.com/maruel/genai/adapters"
"github.com/maruel/genai/providers/openaichat"
"github.com/rs/zerolog/log"
)
func CreateOpenAIClient(ctx context.Context) error {
logger := createLogger()
opts := genai.ProviderOptions{
Model: genai.ModelCheap,
}
c, err := openaichat.New(ctx, &opts, nil)
if err != nil {
return fmt.Errorf("Failed to create genai client: %v", err)
}
client = &openAIClient{
client: c,
conversations: make(map[string][]genai.Message),
log: logger,
}
return nil
}
type openAIClient struct {
client *openaichat.Client
conversations map[string][]genai.Message
log *Logger
}
type QueryReportStatusInput struct {
ReportID string `json:"report_id"`
}
var client *openAIClient
func (c *openAIClient) continueConversation(ctx context.Context, history []Message, customer_phone string) (Message, error) {
opts := genai.OptionsTools{
Tools: []genai.ToolDef{
{
Name: "query_report_status",
Description: "This is used to answer any questions about the current state of the mosquito nuisance report.",
Callback: func(ctx2 context.Context, input *QueryReportStatusInput) (string, error) {
return c.queryReportStatus(ctx2, customer_phone)
},
},
},
}
msg := c.convertHistory(history)
res, _, err := adapters.GenSyncWithToolCallLoop(ctx, c.client, genai.Messages{msg}, &opts)
if err != nil {
return Message{}, fmt.Errorf("Failed to continue conversation: %v", err)
}
for _, m := range res {
// Empty responses are tool call related.
if m.String() == "" {
log.Debug().Msg("Tool called")
} else {
var toSay string = m.String()
toSay = strings.Replace(toSay, "report-mosquitoes-online: ", "", 1)
return Message{
Content: toSay,
IsFromCustomer: false,
}, nil
}
}
return Message{}, nil
}
func (c *openAIClient) convertHistory(history []Message) genai.Message {
var sb strings.Builder
sb.WriteString(
`This is a text chat conversation between a customer that's a member of the public and a mosquito abatement district.
The customer has reported a mosquito nuisance or mosquito breeding through the website report.mosquitoes.online.
Messages from the customer are prefixed with 'customer:' and reponses from the service agent servicing the request are prefixed with 'agent:'.
The agent wants to provide clear, confident, and succint information about the state of the customer's request. The agent also provides general information about how members of the public can help with controlling mosquitoes. For complex or highly specific requests, the agent will need to defer to the mosquito abatement district. This will take some time because contacting the district may take a few hours to get a response. When the agent needs to contact the district, the agent should tell the customer they are reaching out to the district and to expect a delay.
Transcript starts:`,
)
for _, h := range history {
if h.IsFromCustomer {
sb.WriteString(fmt.Sprintf("\n\ncustomer (%s): %s\n", h.Content))
} else {
sb.WriteString(fmt.Sprintf("\n\nagent (%s): %s\n", h.Content))
}
}
return genai.NewTextMessage(sb.String())
}
func (c *openAIClient) queryReportStatus(ctx context.Context, customer_phone string) (string, error) {
return "Report is scheduled for work in 3 days at 2:00pm by the district", nil
}