answer/pkg/answer/extractor.go
Steve Dudenhoeffer 20bcaefaa2 Refactor search and answer logic to improve modularity
Extracted article handling and text evaluation functions to a new `extractor` module to enhance separation of concerns. Updated the search logic to incorporate result picking using LLM and adjusted the `Answer` function to return structured responses, ensuring better maintainability and extensibility.
2025-03-18 01:34:15 -04:00

110 lines
2.3 KiB
Go

package answer
import (
"context"
"fmt"
"net/url"
gollm "gitea.stevedudenhoeffer.com/steve/go-llm"
"gitea.stevedudenhoeffer.com/steve/answer/pkg/cache"
"gitea.stevedudenhoeffer.com/steve/answer/pkg/extractor"
)
func extractArticle(ctx context.Context, c cache.Cache, u *url.URL) (res article, err error) {
defer func() {
e := recover()
if e != nil {
if e, ok := e.(error); ok {
err = fmt.Errorf("panic: %w", e)
} else {
err = fmt.Errorf("panic: %v", e)
}
}
}()
extractors := extractor.MultiExtractor(
extractor.CacheExtractor{
Cache: c,
Tag: "goose",
Extractor: extractor.GooseExtractor{},
},
extractor.CacheExtractor{
Cache: c,
Tag: "playwright",
Extractor: extractor.PlaywrightExtractor{},
},
)
a, err := extractors.Extract(ctx, u.String())
if err != nil {
return article{
URL: "",
Title: "",
Body: "",
}, err
}
return article{
URL: a.URL,
Title: a.Title,
Body: a.Body,
}, nil
}
func doesTextAnswerQuestion(ctx *gollm.Context, q Question, text string) (string, error) {
fnAnswer := gollm.NewFunction(
"answer",
"The answer from the given text that answers the question.",
func(ctx *gollm.Context, args struct {
Answer string `description:"the answer to the question, the answer should come from the text"`
}) (string, error) {
return args.Answer, nil
})
fnNoAnswer := gollm.NewFunction(
"no_answer",
"Indicate that the text does not answer the question.",
func(ctx *gollm.Context, args struct {
Ignored string `description:"ignored, just here to make sure the function is called. Fill with anything."`
}) (string, error) {
return "", nil
})
req := gollm.Request{
Messages: []gollm.Message{
{
Role: gollm.RoleSystem,
Text: "Evaluate the given text to see if it answers the question from the user. The text is as follows:",
},
{
Role: gollm.RoleSystem,
Text: text,
},
{
Role: gollm.RoleUser,
Text: q.Question,
},
},
Toolbox: gollm.NewToolBox(fnAnswer, fnNoAnswer),
}
res, err := q.Model.ChatComplete(ctx, req)
if err != nil {
return "", err
}
if len(res.Choices) == 0 {
return "", nil
}
if len(res.Choices[0].Calls) == 0 {
return "", nil
}
return req.Toolbox.Execute(ctx, res.Choices[0].Calls[0])
}