DEV Community

sharkflow ltd
sharkflow ltd

Posted on

SharkFlow Legal — devto

{
  "title": "Building AI Legal Assistance for Africa: How SharkFlow's API Handles Lawyer Consultations at Scale",
  "content": "# Building AI Legal Assistance for Africa: How SharkFlow's API Handles Lawyer Consultations at Scale\n\nLet's be honest: getting lawyer consultation in Kenya costs money most small businesses don't have. A basic contract review runs you 5,000–15,000 KES. A trademark search? Another 3,000–5,000 KES. For a startup burning through capital, these add up fast.\n\nThat's the problem SharkFlow Legal solves. But the technical implementation? That's where it gets interesting.\n\nIn this article, I'll walk through how we built an AI-powered legal assistance platform that works reliably across African mobile networks, integrates with M-Pesa for instant payments, and scales to handle Kenya's 400M+ potential users without breaking.\n\n## The Challenge: Building for Africa's Infrastructure Reality\n\nIf you've built for Silicon Valley, you haven't built for Nairobi.\n\nAfrican developers know this intimately. Your servers might be in Frankfurt. Your users? On 3G networks with 2–3 second latency and spotty connectivity. You need to design for this reality from day one, not patch it in later.\n\nWhen we architected SharkFlow Legal, we made three core technical decisions:\n\n1. **Offline-first architecture** – Users shouldn't need constant connectivity\n2. **Lightweight API responses** – Sub-50KB payloads as a hard rule\n3. **M-Pesa-native payments** – Because 99% of our users prefer it to cards\n\nLet's dig into each.\n\n## API Design: Efficiency Over Elegance\n\nHere's our lawyer consultation endpoint:\n\n```

javascript\n// POST /api/v1/legal/consult\n// Request: ~2.3KB\n{\n  \"document_type\": \"contract_review\", // enum: contract_review, trademark_search, nda\n  \"document_base64\": \"JVBERi0xLjQK...\", // max 2MB, we compress\n  \"jurisdiction\": \"KE\", // Critical: Kenyan law ≠ Nigerian law\n  \"user_id\": \"usr_abc123\",\n  \"priority\": \"standard\" // standard, express (faster AI processing)\n}\n\n// Response: ~18KB (including analysis)\n{\n  \"consultation_id\": \"cons_xyz789\",\n  \"status\": \"completed\",\n  \"jurisdiction\": \"KE\",\n  \"summary\": {\n    \"document_type\": \"Employment Contract\",\n    \"risk_level\": \"medium\",\n    \"key_issues\": [\n      {\n        \"issue\": \"Non-compete clause extends beyond employment\",\n        \"severity\": \"high\",\n        \"suggestion\": \"Negotiate to 6 months post-termination max per Kenyan employment law\"\n      }\n    ]\n  },\n  \"next_steps\": \"Request human lawyer review for final signature\",\n  \"cost_kes\": 799,\n  \"cost_cents\": 85 // for M-Pesa integration\n}\n

```\n\nThree design choices here that matter:\n\n**1. Jurisdiction-first approach**\n\nWe don't have a generic \"legal AI.\" Each jurisdiction gets its own prompt engineering, fine-tuned models, and compliance rules. A contract valid in Kenya might violate Tanzanian employment law.\n\n```

python\n# api/handlers/legal_consultation.py\n\nclass JurisdictionalHandler:\n    JURISDICTION_CONFIGS = {\n        'KE': {\n            'model': 'gpt-4-kenya-legal-v2',\n            'knowledge_cutoff': '2024-01',\n            'compliance_framework': 'kenyan_law_2024',\n            'max_tokens': 2000,\n        },\n        'NG': {\n            'model': 'gpt-4-nigeria-legal-v2',\n            'compliance_framework': 'nigerian_law_2024',\n        }\n    }\n    \n    @staticmethod\n    def get_handler(jurisdiction_code: str):\n        config = JurisdictionalHandler.JURISDICTION_CONFIGS.get(jurisdiction_code)\n        if not config:\n            raise UnsupportedJurisdictionError(f\"{jurisdiction_code} not yet supported\")\n        return LegalAIHandler(config)\n

```\n\n**2. Compressed document handling**\n\nPDFs are huge. Users on slow networks can't upload 5MB contracts.\n\n```

python\n# api/utils/document_processor.py\n\nimport zlib\nfrom PyPDF2 import PdfReader\n\nclass DocumentOptimizer:\n    @staticmethod\n    def compress_document(base64_pdf: str) -> tuple[str, dict]:\n        \"\"\"Extract text, discard images, compress to ~50KB\"\"\"\n        pdf_data = base64.b64decode(base64_pdf)\n        reader = PdfReader(BytesIO(pdf_data))\n        \n        # Extract text only—no images, no formatting\n        text = \"\".join([page.extract_text() for page in reader.pages])\n        \n        # Compress with zlib\n        compressed = zlib.compress(text.encode('utf-8'), level=9)\n        compressed_b64 = base64.b64encode(compressed).decode()\n        \n        return compressed_b64, {\n            'original_size_kb': len(base64_pdf) / 1024,\n            'compressed_size_kb': len(compressed_b64) / 1024,\n            'compression_ratio': (1 - len(compressed) / len(pdf_data)) * 100\n        }\n

Enter fullscreen mode Exit fullscreen mode


\n\nOur

Top comments (0)