Mirra
Mirra APIDocuments

Document Examples

Documents enable you to upload, process, and semantically search files within your knowledge graph. These examples demonstrate common document management patterns.

Upload and Share a Document

This example uploads a PDF report and shares it with a team group for collaborative review.

TypeScript

import { MirraSDK } from '@mirra-messenger/sdk';
import { readFileSync } from 'fs';
 
const mirra = new MirraSDK({
  apiKey: process.env.MIRRA_API_KEY
});
 
async function uploadAndShare() {
  // Read and encode the file
  const fileBuffer = readFileSync('./reports/q4-2024.pdf');
  const base64File = fileBuffer.toString('base64');
 
  // Upload to personal graph
  const uploadResult = await mirra.documents.upload({
    file: base64File,
    filename: 'q4-2024.pdf',
    mimeType: 'application/pdf',
    title: 'Q4 2024 Financial Report',
    author: 'Finance Team',
    productTags: ['finance', 'quarterly', '2024-Q4']
  });
 
  console.log(`Document uploaded: ${uploadResult.documentId}`);
  console.log(`Created ${uploadResult.chunkCount} chunks`);
 
  // Share with team group
  const shareResult = await mirra.documents.share({
    documentId: uploadResult.documentId,
    targetGraphId: 'group:team-finance',
    shareReason: 'For quarterly review meeting on Dec 15'
  });
 
  console.log(`Shared with ${shareResult.graphIds.length} graphs`);
}
 
uploadAndShare();

Search Across Team Documents

This example performs a semantic search to find relevant information across all documents shared in a team graph.

TypeScript

async function searchTeamDocs() {
  const results = await mirra.documents.search({
    query: 'What were the key revenue drivers in Q4?',
    graphId: 'group:team-finance',
    limit: 5,
    threshold: 0.75
  });
 
  console.log(`Found ${results.count} relevant chunks:\n`);
 
  results.results.forEach((result, index) => {
    console.log(`${index + 1}. [Score: ${result.score.toFixed(3)}] ${result.documentName}`);
    console.log(`   Page ${result.pageNumber}, Position ${result.position}`);
    console.log(`   "${result.content.substring(0, 150)}..."\n`);
  });
}
 
searchTeamDocs();

Track Document Sharing

This example demonstrates how to track where a document has been shared and manage access.

TypeScript

async function manageDocumentAccess(documentId: string) {
  // List all graphs where document is shared
  const graphsList = await mirra.documents.listGraphs(documentId);
 
  console.log(`Document "${documentId}" is shared in ${graphsList.graphs.length} graphs:\n`);
 
  graphsList.graphs.forEach(graph => {
    const isPrimary = graph.isPrimary ? ' (PRIMARY)' : '';
    console.log(`- ${graph.graphName}${isPrimary}`);
    console.log(`  Type: ${graph.graphType}`);
    console.log(`  Shared by: ${graph.sharedByUserId}`);
    console.log(`  Shared at: ${new Date(graph.sharedAt).toLocaleString()}`);
    if (graph.shareReason) {
      console.log(`  Reason: ${graph.shareReason}`);
    }
    console.log();
  });
 
  // Remove access from a specific group
  const groupToRemove = graphsList.graphs.find(
    g => g.graphType === 'group' && !g.isPrimary
  );
 
  if (groupToRemove) {
    const unshareResult = await mirra.documents.unshare({
      documentId,
      graphId: groupToRemove.graphId
    });
 
    console.log(`Removed access from ${groupToRemove.graphName}`);
    console.log(`Document now in ${unshareResult.graphIds.length} graphs`);
  }
}
 
manageDocumentAccess('doc_abc123');

Batch Document Processing

This example shows how to upload multiple documents and track their processing status.

TypeScript

async function uploadMultipleDocs(filePaths: string[]) {
  const uploadPromises = filePaths.map(async (filePath) => {
    const fileBuffer = readFileSync(filePath);
    const base64File = fileBuffer.toString('base64');
    const filename = filePath.split('/').pop()!;
    
    // Determine MIME type based on extension
    const ext = filename.split('.').pop()?.toLowerCase();
    const mimeTypes: Record<string, string> = {
      'pdf': 'application/pdf',
      'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      'txt': 'text/plain',
      'md': 'text/markdown'
    };
 
    try {
      const result = await mirra.documents.upload({
        file: base64File,
        filename,
        mimeType: mimeTypes[ext!] || 'text/plain',
        productTags: ['batch-upload', '2024-12']
      });
 
      return {
        filename,
        success: true,
        documentId: result.documentId,
        chunks: result.chunkCount,
        processingTime: result.processingTimeMs
      };
    } catch (error) {
      return {
        filename,
        success: false,
        error: error.message
      };
    }
  });
 
  const results = await Promise.all(uploadPromises);
 
  // Summary
  const successful = results.filter(r => r.success);
  const failed = results.filter(r => !r.success);
  const totalChunks = successful.reduce((sum, r) => sum + (r.chunks || 0), 0);
 
  console.log('\nBatch Upload Summary:');
  console.log(`✓ Successful: ${successful.length}`);
  console.log(`✗ Failed: ${failed.length}`);
  console.log(`Total chunks created: ${totalChunks}`);
  
  if (failed.length > 0) {
    console.log('\nFailed uploads:');
    failed.forEach(f => {
      console.log(`- ${f.filename}: ${f.error}`);
    });
  }
 
  return results;
}
 
const filePaths = [
  './docs/report-1.pdf',
  './docs/report-2.pdf',
  './docs/notes.txt',
  './docs/summary.md'
];
 
uploadMultipleDocs(filePaths);

Best Practices

Document Organization

  • Use descriptive filenames - Include dates, versions, and context in filenames
  • Add metadata - Always provide title, author, and productTags for better organization
  • Tag consistently - Develop a tagging taxonomy for your team and use it consistently
  • Version control - Include version numbers in titles or tags when uploading new versions

Search Optimization

  • Query length - Use 5-15 word queries for best results
  • Natural language - Phrase queries as questions or statements, not keyword lists
  • Adjust threshold - Start with 0.7 and adjust based on precision/recall needs
  • Limit appropriately - Use smaller limits (5-10) for high-precision needs

Access Control

  • Default to personal - Upload to your personal graph first, then share selectively
  • Document sharing reasons - Always provide a shareReason to track why documents were shared
  • Regular audits - Periodically review listGraphs() to ensure documents aren't over-shared
  • Unshare when done - Remove document access from graphs when collaboration is complete

See Also

  • Overview - Document concepts and processing pipeline
  • Endpoints - Complete API reference
  • Technical Notes - Supported formats and troubleshooting
  • Scripts - Build serverless functions that search documents

On this page