dcdmaker

package module
v0.2.5-3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 13 Imported by: 0

README

dcdmaker

AI-powered DCD template generator. Parses source documents (DOCX) and generates reusable .dcd templates using Gemini, OpenAI, or any OpenAI-compatible API.

Installation

go get github.com/rachmanzz/dcdmaker

Library Usage

package main

import "github.com/rachmanzz/dcdmaker"

func main() {
    maker := dcdmaker.NewMaker(
        dcdmaker.Gemini(
            dcdmaker.WithModel("gemini-2.5-flash"),
            dcdmaker.WithTemperature(0.3),
        ),
        dcdmaker.Gemini(
            dcdmaker.WithModel("gemini-2.5-pro-exp-03-25"),
        ),
        dcdmaker.OpenAI(
            dcdmaker.WithOpenAIModel("gpt-4o"),
        ),
    )

    maker.
        Source("invoice.docx").
        OptionalPrompt("Create invoice template with number, date, customer, items, total").
        Run("templates/invoice.dcd")

    // Or get raw string (no file write)
    dcd, err := maker.Generate()
}
PredictableKeys

Control variable names and structure — AI forced to use exact keys:

maker.
    Source("invoice.docx").
    PredictableKeys(
        dcdmaker.Object("info", "invoice_no", "date", "customer", "due_date"),
        dcdmaker.Array("items", "name", "qty", "unit_price", "total"),
        dcdmaker.Object("summary", "subtotal", "tax", "grand_total"),
    ).
    Run("templates/invoice.dcd")
  • Object(name, fields...) — singleton object, accessed as {{name.field}}
  • Array(name, fields...) — array of objects for <loop>, accessed as {{x.field}}
  • Keys(fields...) — flat keys, no object prefix, accessed as {{field}} directly
  • KeysEx(fields...) — flat keys with typed fields via Field()
  • ObjectEx(name, fields...) — object with typed fields via Field() (type, optional format)
  • ArrayEx(name, fields...) — array with typed fields via Field()

Typed fields with Field():

maker.PredictableKeys(
    dcdmaker.ObjectEx("info",
        dcdmaker.Field("invoice_no", "string"),
        dcdmaker.Field("date", "date-str", "DD-MM-YYYY"),
        dcdmaker.Field("total", "number"),
    ),
    dcdmaker.ArrayEx("items",
        dcdmaker.Field("name", "string"),
        dcdmaker.Field("qty", "number"),
    ),
    dcdmaker.KeysEx(
        dcdmaker.Field("date", "date-str", "DD-MM-YYYY"),
        dcdmaker.Field("total", "number"),
    ),
)
Field usage Prompt output
Field("name", "string") name: string
Field("qty", "number") qty: number
Field("active", "boolean") active: boolean
Field("date", "date-str", "DD-MM-YYYY") date: date-str (DD-MM-YYYY)

Applies to ObjectEx, ArrayEx, KeysEx:

ObjectEx("info",  Field("name", "string"))         // info {name: string}
ArrayEx("items",  Field("qty", "number"))           // items []qty: number
KeysEx(           Field("date", "date-str", "DD-MM-YYYY")) // date: date-str ... (keys)

Additional fields found in the document are written to [object-unpredictable] and [keys-unpredictable] sections.

Retrieving Unpredictable Fields
maker.Run("output.dcd")

for _, obj := range maker.UnpredictableObjects() {
    fmt.Printf("Object: %s (array=%v) fields=%v\n", obj.Name, obj.IsArray, obj.Fields)
}

keys := maker.UnpredictableKeys()
fmt.Println("Additional keys:", keys)

// Raw DCD output
_ = maker.LastResult()

// Which provider/model succeeded (e.g. "gemini:gemini-2.5-flash")
_ = maker.LastProvider()
AddPredictableKeys

Append variable keys without clearing previously set ones:

maker.
    AddPredictableKeys(
        dcdmaker.Object("extra", "notes", "approved_by"),
    )
Fallback by model
maker := dcdmaker.NewMaker(
    // Gemini Pro → retry 3x → Gemini Flash → retry 3x → OpenAI
    dcdmaker.Gemini(dcdmaker.WithModel("gemini-2.5-pro-exp-03-25")),
    dcdmaker.Gemini(dcdmaker.WithModel("gemini-2.5-flash")),
    dcdmaker.OpenAI(dcdmaker.WithOpenAIModel("gpt-4o")),
)

Configuration

Gemini
Option Default Description
WithModel gemini-2.5-flash Model name
WithTemperature 0.5 Temperature (0–1)
WithAPIKey $GEMINI_API_KEY API key
WithTimeout 60s Request timeout
OpenAI
Option Default Description
WithOpenAIModel gpt-4o Model name
WithOpenAIBaseURL Custom base URL (for Ollama, vLLM, etc.)
WithOpenAITemperature 0.5 Temperature (0–1)
WithOpenAIMaxTokens 8192 Max output tokens
WithOpenAIAPIKey $OPENAI_API_KEY API key
WithOpenAITimeout 60s Request timeout

For large documents (28+ pages), use 180s+ timeout: WithTimeout(180*time.Second) or WithOpenAITimeout(180*time.Second)

How It Works

DOCX ──> dcdmaker ──> AI (Gemini / OpenAI) ──> .dcd template
  1. Read — Source document loaded from disk
  2. Parse — DOCX parsed into structured format: layout, margins, fonts, headings, paragraphs
  3. Generate — AI produces DCD template based on structured source, with [style] generated deterministically by code
  4. Validate — Output checked for valid DCD structure
  5. Retry — 3 attempts per provider, fallback to next provider

Output: .dcd Template

[style]
layout=A4
unit=inch
m=1

[title]
title=Invoice

[header]
right={{page}} / {{total}}

[section 0]
name=header
var=info
keys=invoice_no, date, customer

--- BODY ---
<h1>{{info.invoice_no}}</h1>
<p>Date: {{info.date}}</p>
<p>Customer: {{info.customer}}</p>

[section 1]
name=items
var=info, items
keys=title, items.name, items.qty, items.price

--- BODY ---
<table border=1 width=100%>
<loop:row x from items>
  <col>{{x.name}}</col>
  <col align=right>{{x.qty}}</col>
  <col align=right>{{x.price}}</col>
</loop:row>
</table>

[object-unpredictable]
- info=discount, shipping_address

[keys-unpredictable]
- po_number, department

Development

go test ./...
go vet ./...
go build ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidationErrorCount

func ValidationErrorCount(err error) int

Types

type CategorizedErrors

type CategorizedErrors struct {
	SectionLimits  []string
	MissingKeys    []string
	UndeclaredVars []string
	Other          []string
}

type FieldDef

type FieldDef struct {
	Name   string
	Type   string // "string", "number", "boolean", "date-str"
	Format string // optional, used with date-str
}

func Field

func Field(name string, typ string, format ...string) FieldDef

type GeminiOption

type GeminiOption func(*geminiConfig)

func WithAPIKey

func WithAPIKey(k string) GeminiOption

func WithModel

func WithModel(m string) GeminiOption

func WithStream

func WithStream(s bool) GeminiOption

func WithTemperature

func WithTemperature(t float64) GeminiOption

func WithTimeout

func WithTimeout(d time.Duration) GeminiOption

type KeyDef

type KeyDef struct {
	Name      string
	Type      VarType
	Fields    []string   // backwards compat, used when FieldDefs is nil
	FieldDefs []FieldDef // takes priority over Fields when set
}

func Array

func Array(name string, fields ...string) KeyDef

func ArrayEx

func ArrayEx(name string, fields ...FieldDef) KeyDef

func Keys

func Keys(fields ...string) KeyDef

func KeysEx

func KeysEx(fields ...FieldDef) KeyDef

func Object

func Object(name string, fields ...string) KeyDef

func ObjectEx

func ObjectEx(name string, fields ...FieldDef) KeyDef

type Maker

type Maker struct {
	// contains filtered or unexported fields
}

func NewMaker

func NewMaker(providers ...Provider) *Maker

func (*Maker) AddPredictableKeys

func (m *Maker) AddPredictableKeys(keys ...KeyDef) *Maker

func (*Maker) Generate

func (m *Maker) Generate() (string, error)

func (*Maker) LastProvider added in v0.2.3

func (m *Maker) LastProvider() string

func (*Maker) LastResult

func (m *Maker) LastResult() string

func (*Maker) MaxRetries

func (m *Maker) MaxRetries(n int) *Maker

func (*Maker) OptionalPrompt

func (m *Maker) OptionalPrompt(p string) *Maker

func (*Maker) PredictableKeys

func (m *Maker) PredictableKeys(keys ...KeyDef) *Maker

func (*Maker) Run

func (m *Maker) Run(output string) error

func (*Maker) Source

func (m *Maker) Source(path string) *Maker

func (*Maker) UnpredictableKeys

func (m *Maker) UnpredictableKeys() []string

func (*Maker) UnpredictableObjects

func (m *Maker) UnpredictableObjects() []UnpredictableObject

type Message

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type OpenAIOption

type OpenAIOption func(*openAIConfig)

func WithOpenAIAPIKey

func WithOpenAIAPIKey(k string) OpenAIOption

func WithOpenAIBaseURL

func WithOpenAIBaseURL(u string) OpenAIOption

func WithOpenAIMaxTokens added in v0.2.3

func WithOpenAIMaxTokens(n int) OpenAIOption

func WithOpenAIModel

func WithOpenAIModel(m string) OpenAIOption

func WithOpenAIStream

func WithOpenAIStream(s bool) OpenAIOption

func WithOpenAITemperature added in v0.2.3

func WithOpenAITemperature(t float64) OpenAIOption

func WithOpenAITimeout added in v0.2.3

func WithOpenAITimeout(d time.Duration) OpenAIOption

type Provider

type Provider interface {
	Name() string
	GenerateWithFile(ctx context.Context, prompt string, filename string, data []byte) (string, error)
	GenerateWithHistory(ctx context.Context, history []Message, prompt string) (string, error)
}

func Gemini

func Gemini(opts ...GeminiOption) Provider

func OpenAI

func OpenAI(opts ...OpenAIOption) Provider

type UnpredictableObject

type UnpredictableObject struct {
	Name    string
	Fields  []string
	IsArray bool
}

type VarType

type VarType int
const (
	VarObject VarType = iota
	VarArray
	VarKeys
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL