Add output schema registry and public contract docs
This commit is contained in:
72
internal/core/outputschema/registry.go
Normal file
72
internal/core/outputschema/registry.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package outputschema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/internal/core/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
SchemaBareSegments = "bare-segments"
|
||||
SchemaAuditaV1 = "audita-v1"
|
||||
)
|
||||
|
||||
type Encoder func(*schema.Transcript) ([]byte, error)
|
||||
|
||||
type Definition struct {
|
||||
Key string
|
||||
Encoder Encoder
|
||||
}
|
||||
|
||||
var definitions = map[string]Definition{
|
||||
SchemaBareSegments: {
|
||||
Key: SchemaBareSegments,
|
||||
Encoder: schema.TranscriptToJSON,
|
||||
},
|
||||
SchemaAuditaV1: {
|
||||
Key: SchemaAuditaV1,
|
||||
Encoder: encodeAuditaV1,
|
||||
},
|
||||
}
|
||||
|
||||
func Resolve(key string) (Definition, error) {
|
||||
normalized := strings.TrimSpace(key)
|
||||
if normalized == "" {
|
||||
return Definition{}, fmt.Errorf("output schema must not be empty")
|
||||
}
|
||||
def, ok := definitions[normalized]
|
||||
if !ok {
|
||||
return Definition{}, fmt.Errorf("unsupported output schema %q", normalized)
|
||||
}
|
||||
return def, nil
|
||||
}
|
||||
|
||||
func encodeAuditaV1(transcript *schema.Transcript) ([]byte, error) {
|
||||
if transcript == nil {
|
||||
transcript = &schema.Transcript{}
|
||||
}
|
||||
payload := map[string]any{
|
||||
"schema": "audita-v1",
|
||||
"version": "v1",
|
||||
"segments": func() []map[string]any {
|
||||
out := make([]map[string]any, len(transcript.Segments))
|
||||
for i, s := range transcript.Segments {
|
||||
item := map[string]any{
|
||||
"id": s.ID,
|
||||
"speaker": s.Speaker,
|
||||
"start": s.Start,
|
||||
"end": s.End,
|
||||
"text": s.Text,
|
||||
}
|
||||
if len(s.Categories) > 0 {
|
||||
item["categories"] = s.Categories
|
||||
}
|
||||
out[i] = item
|
||||
}
|
||||
return out
|
||||
}(),
|
||||
}
|
||||
return json.MarshalIndent(payload, "", " ")
|
||||
}
|
||||
58
internal/core/outputschema/registry_test.go
Normal file
58
internal/core/outputschema/registry_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package outputschema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/internal/core/schema"
|
||||
)
|
||||
|
||||
func tinyTranscript() *schema.Transcript {
|
||||
return &schema.Transcript{Segments: []schema.Segment{
|
||||
{ID: 1, Speaker: "A", Start: 0, End: 1, Text: "hello"},
|
||||
}}
|
||||
}
|
||||
|
||||
func TestResolveBareSegments(t *testing.T) {
|
||||
def, err := Resolve(SchemaBareSegments)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve error: %v", err)
|
||||
}
|
||||
raw, err := def.Encoder(tinyTranscript())
|
||||
if err != nil {
|
||||
t.Fatalf("encode error: %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(strings.TrimSpace(string(raw)), "[") {
|
||||
t.Fatalf("expected bare-segments array output, got %s", string(raw))
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveAuditaV1(t *testing.T) {
|
||||
def, err := Resolve(SchemaAuditaV1)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve error: %v", err)
|
||||
}
|
||||
raw, err := def.Encoder(tinyTranscript())
|
||||
if err != nil {
|
||||
t.Fatalf("encode error: %v", err)
|
||||
}
|
||||
var out struct {
|
||||
Schema string `json:"schema"`
|
||||
Version string `json:"version"`
|
||||
Segments []map[string]any `json:"segments"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &out); err != nil {
|
||||
t.Fatalf("unmarshal error: %v", err)
|
||||
}
|
||||
if out.Schema != "audita-v1" || out.Version != "v1" || len(out.Segments) != 1 {
|
||||
t.Fatalf("unexpected audita-v1 output: %+v", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveUnknown(t *testing.T) {
|
||||
_, err := Resolve("seriatim-intermediate")
|
||||
if err == nil || !strings.Contains(err.Error(), "unsupported output schema") {
|
||||
t.Fatalf("expected unsupported output schema error, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user