تخطَّ إلى المحتوى

JavaScript / TypeScript

هذا المحتوى غير متوفر بلغتك بعد.

All examples use fetch (Node 18+ or any modern browser) and read the key from the environment. They are runnable as-is against the live API.

const BASE = "https://ghostmind.optdmsa.com";
const AUTH = { Authorization: `Bearer ${process.env.GHOSTMIND_API_KEY}` };
const JSON_HEADERS = { ...AUTH, "Content-Type": "application/json" };

Chat Completions

const response = await fetch(`${BASE}/v1/chat/completions`, {
method: "POST",
headers: JSON_HEADERS,
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
}),
});
const data = await response.json();
console.log(data.choices[0].message.content);
// The conversation id for follow-up messages:
const convId = response.headers.get("x-ghostmind-conversation-id");

Streaming

const response = await fetch(`${BASE}/v1/chat/completions`, {
method: "POST",
headers: JSON_HEADERS,
body: JSON.stringify({
model: "gpt-4o",
stream: true,
messages: [{ role: "user", content: "Count to five." }],
}),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
process.stdout.write(decoder.decode(value)); // SSE data: lines
}

Durable conversation

Capture the conversation id once, continue anytime — same upstream thread.

const first = await fetch(`${BASE}/v1/chat/completions`, {
method: "POST",
headers: JSON_HEADERS,
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "Remember: the invoice prefix is RT-." }],
}),
});
const convId = first.headers.get("x-ghostmind-conversation-id");
const later = await fetch(`${BASE}/v1/chat/completions`, {
method: "POST",
headers: {
...JSON_HEADERS,
"X-GhostMind-Conversation-Id": convId!,
},
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "What is the invoice prefix?" }],
}),
});

Project-scoped chat with a source file

The upstream-project slug (not the UUID) goes in X-GhostMind-Upstream-Project.

const proj = await (
await fetch(`${BASE}/v1/projects`, {
method: "POST",
headers: JSON_HEADERS,
body: JSON.stringify({
name: "My Engine",
instructions: "Always answer in JSON.",
memory_policy: "project_only",
}),
})
).json();
const { slug, id: projId } = proj;
// Multipart upload — do NOT set Content-Type; fetch sets the boundary.
const form = new FormData();
form.append("file", new Blob([fileBytes], { type: "text/plain" }), "brand_voice.txt");
const file = await (
await fetch(`${BASE}/v1/projects/${projId}/files`, {
method: "POST",
headers: AUTH,
body: form,
})
).json();
// Wait until the file is indexed ("ready") — required for retrieval.
while (true) {
const detail = await (
await fetch(`${BASE}/v1/projects/${projId}`, { headers: AUTH })
).json();
const status = detail.sources.find((s: any) => s.id === file.id)?.status;
if (status === "ready") break;
if (status === "failed") throw new Error("file indexing failed");
await new Promise((r) => setTimeout(r, 2000));
}
const answer = await fetch(`${BASE}/v1/chat/completions`, {
method: "POST",
headers: {
...JSON_HEADERS,
"X-GhostMind-Upstream-Project": slug,
},
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "Summarize the brand voice file." }],
}),
});

Async speech generation

Speech takes ~30–120 s upstream — always use the job endpoint, never the bounded sync path for real workloads.

const job = await (
await fetch(`${BASE}/v1/audio/generations`, {
method: "POST",
headers: JSON_HEADERS,
body: JSON.stringify({
input: "مرحباً بك في منصتنا",
voice: "savio_default",
response_format: "wav",
}),
})
).json(); // 202 Accepted
while (true) {
const { status } = await (
await fetch(`${BASE}/v1/audio/generations/${job.id}`, { headers: AUTH })
).json();
if (status === "completed") break;
if (status === "failed" || status === "cancelled")
throw new Error(`job ${status}`);
await new Promise((r) => setTimeout(r, 5000));
}
const audio = await fetch(`${BASE}/v1/audio/generations/${job.id}/content`, {
headers: AUTH,
});
const wav = Buffer.from(await audio.arrayBuffer());
// Generated content expires after 24 h by default
// (operator-configurable via GHOSTMIND_AUDIO_JOB_TTL_HOURS).

Transcription

const form = new FormData();
form.append("file", new Blob([wav], { type: "audio/wav" }), "clip.wav");
form.append("model", "whisper-1");
const result = await (
await fetch(`${BASE}/v1/audio/transcriptions`, {
method: "POST",
headers: AUTH, // no Content-Type — fetch sets the multipart boundary
body: form,
})
).json();
console.log(result.text); // usually < 2 s for short clips

Usage

const usage = await (
await fetch(`${BASE}/v1/usage?period=7d`, { headers: AUTH })
).json();
console.log(usage.total_requests, usage.total_tokens_in, usage.total_tokens_out);
// Scoped to THIS api key — never other tenants.

Next Steps