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
- Reuse sessions - Create one session per document/conversation
- Store session IDs - Save session IDs for follow-up questions
- Clean up - Delete old sessions periodically
Question Quality
- Be specific - “What is the termination clause?” vs “Tell me about termination”
- Ask follow-ups - Archie remembers context
- Check confidence - Verify low-confidence answers
Error Handling
- Handle failures - Check for processing errors
- Retry logic - Implement retry for transient errors
- User feedback - Show loading states and errors
Next Steps
- Chat API - Complete chat API reference
- Chat Guide - Learn about chat features
- Webhook Handler - Handle chat events via webhooks
Questions? Check the FAQ or contact support@ubiship.com