Chat Integration Example

Complete example of integrating Archivus chat into your application.


Overview

This example demonstrates:

  • Creating chat sessions
  • Asking questions about documents
  • Handling follow-up questions
  • Displaying responses with sources

Python Example

import requests
from typing import Optional, Dict, Any, List

class ArchivusChat:
    def __init__(self, api_key: str, tenant: str):
        self.api_key = api_key
        self.tenant = tenant
        self.base_url = "https://api.archivus.app/api/v1"
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "X-Tenant-Subdomain": tenant
        }
    
    def create_session(
        self,
        document_ids: List[str] | str,
        name: Optional[str] = None
    ) -> Dict[str, Any]:
        """Create a new chat session."""
        url = f"{self.base_url}/chat/sessions"
        
        if isinstance(document_ids, str):
            data = {"document_id": document_ids}
        else:
            data = {"document_ids": document_ids}
        
        if name:
            data["name"] = name
        
        response = requests.post(url, headers=self.headers, json=data)
        response.raise_for_status()
        return response.json()
    
    def ask(
        self,
        session_id: str,
        message: str
    ) -> Dict[str, Any]:
        """Ask a question in a chat session."""
        url = f"{self.base_url}/chat/sessions/{session_id}/ask"
        data = {"message": message}
        
        response = requests.post(url, headers=self.headers, json=data)
        response.raise_for_status()
        return response.json()
    
    def get_history(
        self,
        session_id: str,
        limit: int = 50
    ) -> Dict[str, Any]:
        """Get conversation history."""
        url = f"{self.base_url}/chat/sessions/{session_id}/messages"
        params = {"limit": limit}
        
        response = requests.get(url, headers=self.headers, params=params)
        response.raise_for_status()
        return response.json()
    
    def display_response(self, response: Dict[str, Any]):
        """Display chat response in a readable format."""
        content = response.get("content", "")
        confidence = response.get("confidence", 0.0)
        sources = response.get("sources", [])
        
        print(f"\nArchie: {content}")
        print(f"\nConfidence: {confidence:.2f}")
        
        if sources:
            print("\nSources:")
            for i, source in enumerate(sources, 1):
                print(f"  {i}. Document: {source.get('document_id')}")
                if source.get("page"):
                    print(f"     Page: {source['page']}")
                if source.get("excerpt"):
                    print(f"     Excerpt: {source['excerpt'][:100]}...")


# Interactive Chat Example
def interactive_chat():
    chat = ArchivusChat(
        api_key="YOUR_API_KEY",
        tenant="your-tenant"
    )
    
    # Create session
    document_id = input("Enter document ID: ")
    session = chat.create_session(document_id, "Interactive Chat")
    session_id = session["id"]
    
    print(f"\nChat session created: {session_id}")
    print("Type 'exit' to quit, 'history' to see conversation\n")
    
    while True:
        question = input("You: ")
        
        if question.lower() == "exit":
            break
        elif question.lower() == "history":
            history = chat.get_history(session_id)
            for msg in history.get("messages", []):
                role = msg["role"]
                content = msg["content"][:100] + "..." if len(msg["content"]) > 100 else msg["content"]
                print(f"{role.capitalize()}: {content}")
            continue
        
        try:
            response = chat.ask(session_id, question)
            chat.display_response(response)
        except Exception as e:
            print(f"Error: {e}")


# Batch Question Example
def batch_questions():
    chat = ArchivusChat(
        api_key="YOUR_API_KEY",
        tenant="your-tenant"
    )
    
    # Create session
    session = chat.create_session("doc_abc123", "Contract Analysis")
    session_id = session["id"]
    
    questions = [
        "What is this contract about?",
        "What are the key terms?",
        "When does it expire?",
        "What are the payment terms?",
        "Can it be terminated early?"
    ]
    
    print("Analyzing contract...\n")
    
    for question in questions:
        print(f"Q: {question}")
        response = chat.ask(session_id, question)
        print(f"A: {response['content'][:200]}...")
        print(f"   Confidence: {response['confidence']:.2f}\n")


if __name__ == "__main__":
    # Run interactive chat
    interactive_chat()
    
    # Or run batch questions
    # batch_questions()

JavaScript Example

class ArchivusChat {
  constructor(apiKey, tenant) {
    this.apiKey = apiKey;
    this.tenant = tenant;
    this.baseURL = 'https://api.archivus.app/api/v1';
    this.headers = {
      'Authorization': `Bearer ${apiKey}`,
      'X-Tenant-Subdomain': tenant
    };
  }
  
  async createSession(documentIds, name = null) {
    const data = Array.isArray(documentIds)
      ? { document_ids: documentIds }
      : { document_id: documentIds };
    if (name) data.name = name;
    
    const response = await fetch(`${this.baseURL}/chat/sessions`, {
      method: 'POST',
      headers: { ...this.headers, 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    
    if (!response.ok) {
      throw new Error(`Failed to create session: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  async ask(sessionId, message) {
    const response = await fetch(`${this.baseURL}/chat/sessions/${sessionId}/ask`, {
      method: 'POST',
      headers: { ...this.headers, 'Content-Type': 'application/json' },
      body: JSON.stringify({ message })
    });
    
    if (!response.ok) {
      throw new Error(`Failed to ask question: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  async getHistory(sessionId, limit = 50) {
    const url = new URL(`${this.baseURL}/chat/sessions/${sessionId}/messages`);
    url.searchParams.set('limit', limit);
    
    const response = await fetch(url, { headers: this.headers });
    if (!response.ok) {
      throw new Error(`Failed to get history: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  displayResponse(response) {
    const content = response.content || '';
    const confidence = response.confidence || 0;
    const sources = response.sources || [];
    
    console.log(`\nArchie: ${content}`);
    console.log(`\nConfidence: ${confidence.toFixed(2)}`);
    
    if (sources.length > 0) {
      console.log('\nSources:');
      sources.forEach((source, i) => {
        console.log(`  ${i + 1}. Document: ${source.document_id}`);
        if (source.page) {
          console.log(`     Page: ${source.page}`);
        }
        if (source.excerpt) {
          console.log(`     Excerpt: ${source.excerpt.substring(0, 100)}...`);
        }
      });
    }
  }
}

// React Component Example
function ChatInterface({ documentId, apiKey, tenant }) {
  const [sessionId, setSessionId] = useState(null);
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(false);
  
  const chat = new ArchivusChat(apiKey, tenant);
  
  useEffect(() => {
    // Create session on mount
    chat.createSession(documentId, 'Chat Session')
      .then(session => {
        setSessionId(session.id);
        loadHistory(session.id);
      });
  }, [documentId]);
  
  const loadHistory = async (sid) => {
    const history = await chat.getHistory(sid);
    setMessages(history.messages || []);
  };
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!input.trim() || loading) return;
    
    const userMessage = input;
    setInput('');
    setLoading(true);
    
    // Add user message
    setMessages(prev => [...prev, {
      role: 'user',
      content: userMessage
    }]);
    
    try {
      const response = await chat.ask(sessionId, userMessage);
      
      // Add assistant response
      setMessages(prev => [...prev, {
        role: 'assistant',
        content: response.content,
        confidence: response.confidence,
        sources: response.sources
      }]);
    } catch (error) {
      console.error('Error:', error);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div className="chat-container">
      <div className="messages">
        {messages.map((msg, i) => (
          <div key={i} className={`message ${msg.role}`}>
            <div className="content">{msg.content}</div>
            {msg.confidence && (
              <div className="confidence">
                Confidence: {msg.confidence.toFixed(2)}
              </div>
            )}
            {msg.sources && msg.sources.length > 0 && (
              <div className="sources">
                Sources: {msg.sources.length}
              </div>
            )}
          </div>
        ))}
      </div>
      
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Ask a question..."
          disabled={loading}
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Sending...' : 'Send'}
        </button>
      </form>
    </div>
  );
}

Real-World Use Cases

Contract Analysis Bot

def analyze_contract(document_id: str):
    """Analyze a contract and extract key information."""
    chat = ArchivusChat(api_key, tenant)
    session = chat.create_session(document_id, "Contract Analysis")
    
    questions = {
        "parties": "Who are the parties to this contract?",
        "term": "What is the contract term?",
        "payment": "What are the payment terms?",
        "termination": "What are the termination clauses?",
        "obligations": "What are the key obligations?"
    }
    
    analysis = {}
    for key, question in questions.items():
        response = chat.ask(session["id"], question)
        analysis[key] = {
            "answer": response["content"],
            "confidence": response["confidence"]
        }
    
    return analysis

Document Q&A Widget

// Embeddable Q&A widget
class DocumentQAWidget {
  constructor(containerId, documentId, apiKey, tenant) {
    this.container = document.getElementById(containerId);
    this.documentId = documentId;
    this.chat = new ArchivusChat(apiKey, tenant);
    this.sessionId = null;
    this.init();
  }
  
  async init() {
    const session = await this.chat.createSession(this.documentId);
    this.sessionId = session.id;
    this.render();
  }
  
  async askQuestion(question) {
    const response = await this.chat.ask(this.sessionId, question);
    this.displayAnswer(response);
  }
  
  displayAnswer(response) {
    const answerDiv = document.createElement('div');
    answerDiv.className = 'answer';
    answerDiv.innerHTML = `
      <p>${response.content}</p>
      <small>Confidence: ${(response.confidence * 100).toFixed(0)}%</small>
    `;
    this.container.appendChild(answerDiv);
  }
  
  render() {
    this.container.innerHTML = `
      <div class="qa-widget">
        <h3>Ask about this document</h3>
        <input type="text" id="question-input" placeholder="Ask a question...">
        <button onclick="widget.askQuestion(document.getElementById('question-input').value)">
          Ask
        </button>
        <div id="answers"></div>
      </div>
    `;
  }
}

Best Practices

Session Management

  1. Reuse sessions - Create one session per document/conversation
  2. Store session IDs - Save session IDs for follow-up questions
  3. Clean up - Delete old sessions periodically

Question Quality

  1. Be specific - “What is the termination clause?” vs “Tell me about termination”
  2. Ask follow-ups - Archie remembers context
  3. Check confidence - Verify low-confidence answers

Error Handling

  1. Handle failures - Check for processing errors
  2. Retry logic - Implement retry for transient errors
  3. User feedback - Show loading states and errors

Next Steps


Questions? Check the FAQ or contact support@ubiship.com