110 lines
3.3 KiB
Go
110 lines
3.3 KiB
Go
package scenes
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/promptassets"
|
|
)
|
|
|
|
const scriptoriumPromptRoot = "assets/scriptorium/prompts"
|
|
|
|
func RegisterPromptAssets(registry *llm.AssetRegistry) error {
|
|
if err := registry.RegisterPromptFS(embeddedAssets, scriptoriumPromptRoot); err != nil {
|
|
return err
|
|
}
|
|
return registry.RegisterSchemaFS(embeddedAssets, "assets/schemas")
|
|
}
|
|
|
|
func promptInputs(req contracts.ChunkRequest) contracts.LLMInputSet {
|
|
return contracts.LLMInputSet{
|
|
"transcript": transcriptPromptInput(req.SourceInput),
|
|
"roster": referencePromptMaterial("roster", req.References.Slots["roster"]),
|
|
"glossary": referencePromptMaterial("glossary", req.References.Slots["glossary"]),
|
|
}
|
|
}
|
|
|
|
func transcriptPromptInput(material contracts.LLMInputMaterial) contracts.LLMInputMaterial {
|
|
out := material.Clone()
|
|
out.Name = "transcript"
|
|
return out
|
|
}
|
|
|
|
func referencePromptMaterial(name string, slot contracts.ResolvedReferenceSlot) contracts.LLMInputMaterial {
|
|
body := referencePromptInput(slot)
|
|
digest := ""
|
|
originURI := ""
|
|
if len(slot.Items) == 1 {
|
|
digest = slot.Items[0].Digest
|
|
originURI = slot.Items[0].Origin.URI
|
|
}
|
|
return contracts.NewLLMInputMaterial(name, "text/plain", body, digest, originURI)
|
|
}
|
|
|
|
func scriptoriumPromptMetadata() (string, error) {
|
|
scriptoriumPromptHashOnce.Do(func() {
|
|
parts := append([]llm.AssetHashPart{
|
|
{FS: embeddedAssets, Path: "assets/scriptorium/prompts/dnd.scenes.yaml"},
|
|
{FS: embeddedAssets, Path: "assets/scriptorium/prompts/dnd/scenes/task.md"},
|
|
{FS: embeddedAssets, Path: "assets/scriptorium/prompts/dnd/scenes/instructions.md"},
|
|
}, append(promptassets.CommonHashParts(), promptassets.ReferenceHashParts()...)...)
|
|
scriptoriumPromptHash, scriptoriumPromptHashErr = llm.HashAssets(parts)
|
|
})
|
|
return scriptoriumPromptHash, scriptoriumPromptHashErr
|
|
}
|
|
|
|
func referencePromptInput(slot contracts.ResolvedReferenceSlot) []byte {
|
|
if len(slot.Items) == 0 {
|
|
return []byte(" ")
|
|
}
|
|
items := append([]contracts.ReferenceItem(nil), slot.Items...)
|
|
sort.SliceStable(items, func(i, j int) bool {
|
|
if items[i].Origin.URI != items[j].Origin.URI {
|
|
return items[i].Origin.URI < items[j].Origin.URI
|
|
}
|
|
if items[i].Digest != items[j].Digest {
|
|
return items[i].Digest < items[j].Digest
|
|
}
|
|
return string(items[i].Content) < string(items[j].Content)
|
|
})
|
|
if len(items) == 1 {
|
|
return append([]byte(nil), items[0].Content...)
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
for i, item := range items {
|
|
if i > 0 {
|
|
b.WriteString("\n\n")
|
|
}
|
|
fmt.Fprintf(&b, "Reference %d\n", i+1)
|
|
if item.Origin.Type != "" {
|
|
fmt.Fprintf(&b, "Origin-Type: %s\n", item.Origin.Type)
|
|
}
|
|
if item.Origin.URI != "" {
|
|
fmt.Fprintf(&b, "Origin-URI: %s\n", item.Origin.URI)
|
|
}
|
|
if item.Digest != "" {
|
|
fmt.Fprintf(&b, "Digest: %s\n", item.Digest)
|
|
}
|
|
if item.MediaType != "" {
|
|
fmt.Fprintf(&b, "Media-Type: %s\n", item.MediaType)
|
|
}
|
|
if item.SizeBytes > 0 {
|
|
fmt.Fprintf(&b, "Size-Bytes: %d\n", item.SizeBytes)
|
|
}
|
|
b.WriteString("\n")
|
|
b.Write(item.Content)
|
|
}
|
|
return b.Bytes()
|
|
}
|
|
|
|
var (
|
|
scriptoriumPromptHashOnce sync.Once
|
|
scriptoriumPromptHash string
|
|
scriptoriumPromptHashErr error
|
|
)
|