Client libraries
Matricxon speaks plain HTTP and JSON, so any HTTP client works. The examples below are small, ready-to-copy clients for Python, Node.js and Go. All endpoints and options are in the API reference.
Every example reads the server address from MATRICXON_URL, or uses http://localhost:8420.
Python
Section titled “Python”Needs Python 3.10 or newer and requests:
pip install requestsimport jsonimport os
import requests
class Matricxon: """A small client for the Matricxon API."""
def __init__(self, url: str | None = None) -> None: self.url = (url or os.environ.get("MATRICXON_URL", "http://localhost:8420")).rstrip("/")
def chat(self, model: str, messages: list[dict], **options): """Yields the reply piece by piece.""" body = {"model": model, "messages": messages, "options": options} with requests.post(f"{self.url}/api/chat", json=body, stream=True, timeout=600) as r: r.raise_for_status() for line in r.iter_lines(): if line: yield json.loads(line)["message"]["content"]
def embed(self, model: str, texts: list[str]) -> list[list[float]]: r = requests.post(f"{self.url}/api/embed", json={"model": model, "input": texts}, timeout=600) r.raise_for_status() return r.json()["embeddings"]
mx = Matricxon()model = "hf.co/unsloth/Llama-3.2-3B-Instruct-GGUF:Llama-3.2-3B-Instruct-Q3_K_M"for piece in mx.chat(model, [{"role": "user", "content": "What is a GGUF file?"}], temperature=0.7): print(piece, end="", flush=True)Node.js
Section titled “Node.js”Needs Node.js 18 or newer, which has fetch built in. No packages to install. Save it as matricxon.mjs:
export class Matricxon { constructor(url = process.env.MATRICXON_URL ?? 'http://localhost:8420') { this.url = url.replace(/\/$/, ''); }
// Yields the reply piece by piece. async *chat(model, messages, options = {}) { const res = await fetch(`${this.url}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, messages, options }), }); if (!res.ok) throw new Error(`Matricxon: ${res.status} ${await res.text()}`); const decoder = new TextDecoder(); let buffer = ''; for await (const chunk of res.body) { buffer += decoder.decode(chunk, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) if (line.trim()) yield JSON.parse(line).message.content; } }
async embed(model, texts) { const res = await fetch(`${this.url}/api/embed`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, input: texts }), }); if (!res.ok) throw new Error(`Matricxon: ${res.status} ${await res.text()}`); return (await res.json()).embeddings; }}import { Matricxon } from './matricxon.mjs';
const mx = new Matricxon();const model = 'hf.co/unsloth/Llama-3.2-3B-Instruct-GGUF:Llama-3.2-3B-Instruct-Q3_K_M';for await (const piece of mx.chat(model, [{ role: 'user', content: 'What is a GGUF file?' }], { temperature: 0.7 })) { process.stdout.write(piece);}Needs Go 1.23 or newer (for range-over-func iterators). Only the standard library, no packages to install. Save it as matricxon/matricxon.go inside your module:
// Package matricxon is a small client for the Matricxon API.package matricxon
import ( "bufio" "bytes" "context" "encoding/json" "fmt" "io" "iter" "net/http" "os" "strings")
type Message struct { Role string `json:"role"` Content string `json:"content"`}
type Client struct { URL string HTTP *http.Client}
// New reads the server address from MATRICXON_URL, or uses http://localhost:8420.func New() *Client { url := os.Getenv("MATRICXON_URL") if url == "" { url = "http://localhost:8420" } return &Client{URL: strings.TrimRight(url, "/"), HTTP: http.DefaultClient}}
func (c *Client) post(ctx context.Context, path string, body any) (*http.Response, error) { data, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL+path, bytes.NewReader(data)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") res, err := c.HTTP.Do(req) if err != nil { return nil, err } if res.StatusCode != http.StatusOK { defer res.Body.Close() text, _ := io.ReadAll(res.Body) return nil, fmt.Errorf("matricxon: %s %s", res.Status, text) } return res, nil}
// Chat yields the reply piece by piece.func (c *Client) Chat(ctx context.Context, model string, messages []Message, options map[string]any) iter.Seq2[string, error] { return func(yield func(string, error) bool) { res, err := c.post(ctx, "/api/chat", map[string]any{"model": model, "messages": messages, "options": options}) if err != nil { yield("", err) return } defer res.Body.Close() lines := bufio.NewScanner(res.Body) lines.Buffer(make([]byte, 64*1024), 4*1024*1024) // the last line carries the timings for lines.Scan() { if len(bytes.TrimSpace(lines.Bytes())) == 0 { continue } var part struct { Message Message `json:"message"` } if err := json.Unmarshal(lines.Bytes(), &part); err != nil { yield("", err) return } if !yield(part.Message.Content, nil) { return } } if err := lines.Err(); err != nil { yield("", err) } }}
func (c *Client) Embed(ctx context.Context, model string, texts []string) ([][]float64, error) { res, err := c.post(ctx, "/api/embed", map[string]any{"model": model, "input": texts}) if err != nil { return nil, err } defer res.Body.Close() var out struct { Embeddings [][]float64 `json:"embeddings"` } return out.Embeddings, json.NewDecoder(res.Body).Decode(&out)}Then call it from your program. Change example.com/app to your own module path:
package main
import ( "context" "fmt" "log"
"example.com/app/matricxon")
func main() { mx := matricxon.New() model := "hf.co/unsloth/Llama-3.2-3B-Instruct-GGUF:Llama-3.2-3B-Instruct-Q3_K_M" messages := []matricxon.Message{{Role: "user", Content: "What is a GGUF file?"}} for piece, err := range mx.Chat(context.Background(), model, messages, map[string]any{"temperature": 0.7}) { if err != nil { log.Fatal(err) } fmt.Print(piece) } fmt.Println()}Good to know
Section titled “Good to know”- Replies always stream, one JSON object per line. The last line has
"done": trueand the timings. - A model that is not loaded yet loads on the first call, which can take a while on a CPU. Keep the timeout long.
- Admin routes need a signed request. See Admin routes and the admin secret.