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.
110 lines
2.3 KiB
Go
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])
|
|
}
|