123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- // Package model implements the File and Name types for working with and
- // representing Modelfiles and model Names.
- //
- // The Name type should be used when working with model names, and the File
- // type should be used when working with Modelfiles.
- package model
- import (
- "bufio"
- "io"
- "iter"
- "strings"
- )
- type ParamPragma struct {
- Key string
- Value string
- }
- type MessagePragma struct {
- Role string
- Content string
- }
- type File struct {
- // From is a required pragma that specifies the source of the model,
- // either on disk, or by reference (see model.ParseName).
- From string
- // Optional
- Params []ParamPragma
- Template string
- System string
- Adapter string
- Messages []MessagePragma
- License string
- }
- type FileError struct {
- Pragma string
- Message string
- }
- func (e *FileError) Error() string {
- return e.Pragma + ": " + e.Message
- }
- // Pragma represents a single pragma in a Modelfile.
- type Pragma struct {
- // The pragma name
- Name string
- // Args contains the user-defined arguments for the pragma. If no
- // arguments were provided, it is nil.
- Args []string
- }
- func (p Pragma) Arg(i int) string {
- if i >= len(p.Args) {
- return ""
- }
- return p.Args[i]
- }
- func FilePragmas(r io.Reader) iter.Seq2[Pragma, error] {
- return func(yield func(Pragma, error) bool) {
- sc := bufio.NewScanner(r)
- for sc.Scan() {
- line := sc.Text()
- // TODO(bmizerany): set a max num fields/args to
- // prevent mem bloat
- args := strings.Fields(line)
- if len(args) == 0 {
- continue
- }
- p := Pragma{
- Name: strings.ToUpper(args[0]),
- }
- if p.Name == "MESSAGE" {
- // handle special case where message content
- // is space separated on the _rest_ of the
- // line like: `MESSAGE user Is Ontario in
- // Canada?`
- panic("TODO")
- }
- if len(args) > 1 {
- p.Args = args[1:]
- }
- if !yield(p, nil) {
- return
- }
- }
- if sc.Err() != nil {
- yield(Pragma{}, sc.Err())
- }
- }
- }
- func ParseFile(r io.Reader) (File, error) {
- var f File
- for p, err := range FilePragmas(r) {
- if err != nil {
- return File{}, err
- }
- switch p.Name {
- case "FROM":
- f.From = p.Arg(0)
- case "PARAMETER":
- f.Params = append(f.Params, ParamPragma{
- Key: strings.ToLower(p.Arg(0)),
- Value: p.Arg(1),
- })
- case "TEMPLATE":
- f.Template = p.Arg(0)
- case "SYSTEM":
- f.System = p.Arg(0)
- case "ADAPTER":
- f.Adapter = p.Arg(0)
- case "MESSAGE":
- f.Messages = append(f.Messages, MessagePragma{
- Role: p.Arg(0),
- Content: p.Arg(1),
- })
- case "LICENSE":
- f.License = p.Arg(0)
- }
- }
- return f, nil
- }
|