These examples are for UI tools that call the local API directly.
Base URL:
const API_BASE_URL = "http://localhost:3000";
const API_ACCESS_TOKEN = sessionStorage.getItem("tri_model_access_token") || "";async function postJson(path, body = {}) {
const response = await fetch(`${API_BASE_URL}${path}`, {
method: "POST",
headers: {
"content-type": "application/json",
...(API_ACCESS_TOKEN
? { authorization: `Bearer ${API_ACCESS_TOKEN}` }
: {})
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error ? data.error.message : "Request failed.");
}
return data;
}For a deployed frontend, prefer a same-origin server-side proxy so the API token is not compiled into a public browser bundle.
async function startExperience() {
return postJson("/api/experience/start", {
birth_date: "1990-03-15",
birth_time: "10:30",
location: "Shanghai",
timezone: "Asia/Shanghai",
mbti: "INTJ",
explanation_mode: "dry_run",
user_question: "What is the main tension?"
});
}This is the preferred entry point for the polished frontend. The frontend may mirror the documented stages as transition copy while the request is pending, and the response confirms the stage vocabulary together with the full public profile.
async function getHealth() {
const response = await fetch(`${API_BASE_URL}/health`);
return response.json();
}
async function getApiIndex() {
const response = await fetch(`${API_BASE_URL}/api`);
return response.json();
}
async function getRulesSummary() {
return postJson("/api/rules/summary", {});
}async function validateProfileInput() {
return postJson("/api/profile/validate", {
birth_date: "1990-03-15",
birth_time: "10:30",
location: "Shanghai",
mbti: "INTJ"
});
}
async function previewProfile() {
return postJson("/api/profile/preview", {
birth_date: "1990-03-15",
birth_time: "10:30",
location: "Shanghai",
mbti: "INTJ"
});
}
async function generateProfile() {
return postJson("/api/profile/generate", {
birth_date: "1990-03-15",
birth_time: "10:30",
location: "Shanghai",
mbti: "INTJ"
});
}
async function rebuildProfile(profileId) {
return postJson("/api/profile/rebuild", {
profile_id: profileId
});
}
async function rebuildProfilesBatch(profileIds) {
return postJson("/api/profile/rebuild-batch", {
profile_ids: profileIds
});
}Store the returned profile_id in UI state.
async function listProfiles(filters = {}) {
return postJson("/api/profile/list", {
limit: 50,
offset: 0,
...filters
});
}
async function getProfileStats() {
return postJson("/api/profile/stats", {});
}
async function getProfile(profileId) {
return postJson("/api/profile/get", {
profile_id: profileId
});
}
async function compareProfile(profileId) {
return postJson("/api/profile/compare", {
profile_id: profileId
});
}listProfiles returns summary rows only. Use getProfile for full public profile data.
Dry-run mode builds the LLM payload without calling a provider:
async function previewExplanationRequest(profileId, userQuestion, options = {}) {
return postJson("/api/profile/explain", {
profile_id: profileId,
user_question: userQuestion,
mode: "dry_run",
...options
});
}Live mode requires OPENAI_API_KEY and OPENAI_MODEL in the server environment:
async function createLiveExplanation(profileId, userQuestion, options = {}) {
return postJson("/api/profile/explain", {
profile_id: profileId,
user_question: userQuestion,
mode: "live",
...options
});
}
async function deleteExplanation(profileId, explanationId) {
return postJson("/api/profile/explanation/delete", {
profile_id: profileId,
explanation_id: explanationId
});
}
async function clearExplanations(profileId) {
return postJson("/api/profile/explanation/clear", {
profile_id: profileId
});
}async function exportProfile(profileId) {
return postJson("/api/profile/export", {
profile_id: profileId
});
}
async function exportProfilesBatch(profileIds) {
return postJson("/api/profile/export-batch", {
profile_ids: profileIds
});
}
async function importProfile(exportPackage, overwrite = false) {
return postJson("/api/profile/import", {
...exportPackage,
overwrite
});
}
async function importProfilesBatch(exportPackage, overwrite = false) {
return postJson("/api/profile/import-batch", {
...exportPackage,
overwrite
});
}Batch export and batch import support up to 50 profiles per request.
async function deleteProfile(profileId) {
return postJson("/api/profile/delete", {
profile_id: profileId
});
}
async function deleteProfilesBatch(profileIds) {
return postJson("/api/profile/delete-batch", {
profile_ids: profileIds
});
}Batch deletion reports missing ids without failing the whole request.
Validation errors use:
{
"error": {
"code": "validation_failed",
"message": "Request validation failed.",
"details": {
"fields": []
}
}
}Use error.details.fields to attach messages to form inputs.