| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import type { Artifact, PlanProposal, TraceEntry } from "./types"; |
|
|
| |
|
|
| function encodeBase64(s: string): string { |
| if (typeof window === "undefined") { |
| return Buffer.from(s, "utf8").toString("base64"); |
| } |
| return btoa(unescape(encodeURIComponent(s))); |
| } |
|
|
| function dataUrl(mime: string, content: string): string { |
| return `data:${mime};base64,${encodeBase64(content)}`; |
| } |
|
|
| function newId(): string { |
| return "art-" + Math.random().toString(36).slice(2, 10); |
| } |
|
|
| function utf8Bytes(s: string): number { |
| if (typeof TextEncoder !== "undefined") { |
| return new TextEncoder().encode(s).length; |
| } |
| return Buffer.byteLength(s, "utf8"); |
| } |
|
|
| |
|
|
| export interface DesignBriefInput { |
| target: string; |
| indication?: string; |
| mechanism?: string; |
| format?: string; |
| epitope?: string; |
| affinity?: string; |
| species?: string; |
| developability?: string; |
| route?: string; |
| competition?: string; |
| seed?: string; |
| scale?: string; |
| } |
|
|
| export function buildDesignBriefJson(brief: DesignBriefInput): string { |
| const payload = { |
| schema: "proteinea.design_brief/v1", |
| generated_at: new Date().toISOString(), |
| target: brief.target, |
| indication: brief.indication || null, |
| mechanism: brief.mechanism || null, |
| format: brief.format || "VHH", |
| epitope: brief.epitope || "no preference", |
| affinity_goal: brief.affinity || null, |
| species_cross_reactivity: brief.species || null, |
| developability: brief.developability || null, |
| route_of_administration: brief.route || null, |
| competitive_landscape: brief.competition || null, |
| starting_point: brief.seed || "de novo", |
| design_count: parseInt(brief.scale || "50", 10) || 50, |
| }; |
| return JSON.stringify(payload, null, 2); |
| } |
|
|
| export function buildPipelinePlanJson(plan: PlanProposal): string { |
| const payload = { |
| schema: "proteinea.pipeline_plan/v1", |
| generated_at: new Date().toISOString(), |
| title: plan.title, |
| steps: plan.steps.map((s, i) => ({ |
| index: i + 1, |
| label: s.label, |
| tools: s.tools, |
| })), |
| }; |
| return JSON.stringify(payload, null, 2); |
| } |
|
|
| export function buildExecutionTraceJson(trace: TraceEntry[]): string { |
| const payload = { |
| schema: "proteinea.execution_trace/v1", |
| generated_at: new Date().toISOString(), |
| event_count: trace.length, |
| events: trace, |
| }; |
| return JSON.stringify(payload, null, 2); |
| } |
|
|
| export function buildTopDesignsCsv(n = 10): string { |
| const aa = "ACDEFGHIKLMNPQRSTVWY"; |
| const rows: string[] = [ |
| "rank,design_id,cdr_h3,length,iPAE,pLDDT,affinity_nM,consensus_score", |
| ]; |
| for (let i = 0; i < n; i++) { |
| const id = `d${String(i + 1).padStart(3, "0")}`; |
| const len = 14 + Math.floor(Math.random() * 8); |
| let cdr = ""; |
| for (let j = 0; j < len; j++) cdr += aa[Math.floor(Math.random() * aa.length)]; |
| const iPAE = (5 + Math.random() * 5).toFixed(2); |
| const pLDDT = (82 + Math.random() * 12).toFixed(1); |
| const kd = (0.3 + Math.random() * 40).toFixed(2); |
| const score = (0.55 + Math.random() * 0.4).toFixed(3); |
| rows.push(`${i + 1},${id},${cdr},${len},${iPAE},${pLDDT},${kd},${score}`); |
| } |
| return rows.join("\n"); |
| } |
|
|
| |
|
|
| export function makeJsonArtifact(name: string, content: string): Artifact { |
| return { |
| id: newId(), |
| name, |
| bytes: utf8Bytes(content), |
| mime: "application/json", |
| url: dataUrl("application/json", content), |
| createdAt: Date.now(), |
| }; |
| } |
|
|
| export function makeCsvArtifact(name: string, content: string): Artifact { |
| return { |
| id: newId(), |
| name, |
| bytes: utf8Bytes(content), |
| mime: "text/csv", |
| url: dataUrl("text/csv", content), |
| createdAt: Date.now(), |
| }; |
| } |
|
|
| |
|
|
| export function makePhyloTreeArtifact(): Artifact { |
| return { |
| id: newId(), |
| name: "spike.nwk", |
| bytes: 4096, |
| mime: "text/x-nh", |
| url: "/sample-data/spike.nwk", |
| createdAt: Date.now(), |
| }; |
| } |
|
|
| export function makeMsaArtifact(): Artifact { |
| return { |
| id: newId(), |
| name: "igg-fc.fasta", |
| bytes: 8192, |
| mime: "text/x-fasta", |
| url: "/sample-data/igg-fc.fasta", |
| createdAt: Date.now(), |
| }; |
| } |
|
|
| export function makeStructureArtifact(): Artifact { |
| return { |
| id: newId(), |
| name: "her2-1n8z-mini.pdb", |
| bytes: 24576, |
| mime: "chemical/x-pdb", |
| url: "/sample-data/her2-1n8z-mini.pdb", |
| createdAt: Date.now(), |
| }; |
| } |
|
|
| |
| |
| |
| |
| export function detectSampleDataHints(msg: string): { |
| phylo: boolean; |
| msa: boolean; |
| structure: boolean; |
| } { |
| const m = msg.toLowerCase(); |
| return { |
| phylo: |
| m.includes("phylogen") || |
| m.includes("tree") || |
| m.includes(".nwk") || |
| m.includes("newick") || |
| m.includes("clade"), |
| msa: |
| m.includes("msa") || |
| m.includes("alignment") || |
| m.includes("multiple sequence") || |
| m.includes("fasta") || |
| m.includes("conservation"), |
| structure: |
| m.includes("structure") || |
| m.includes("pdb") || |
| m.includes("crystal") || |
| m.includes("cryo-em") || |
| m.includes("cryoem") || |
| m.includes("3d structure"), |
| }; |
| } |
|
|
| |
|
|
| export interface KbTopic { |
| name: string; |
| ms: number; |
| } |
|
|
| |
| |
| |
| |
| export function buildKbTopics(): KbTopic[] { |
| const jitter = (base: number, spread: number) => |
| Math.round(base + (Math.random() - 0.5) * spread); |
| return [ |
| { name: "antibody design best practices", ms: jitter(150, 60) }, |
| { name: "benchmark catalog", ms: jitter(80, 40) }, |
| { name: "target intelligence", ms: jitter(120, 60) }, |
| { name: "developability heuristics", ms: jitter(95, 40) }, |
| ]; |
| } |
|
|