All files contractController.ts

100% Statements 25/25
100% Branches 8/8
100% Functions 1/1
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99          1x   1x 1x                                           1x 10x 10x         10x 10x                           9x 9x 2x     9x 8x     7x       7x   7x   6x               6x                   6x 1x 1x   5x     3x 3x      
import axios from "axios";
import dotenv from "dotenv";
import { addItem, getItem, updateItem } from "@deliverables.org/database";
import { sendWhatsAppMessage } from "@deliverables.org/helpers";
 
dotenv.config();
 
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
const TABLE_NAME = "Deliverables";
 
export interface ContractData {
    id: string;
    name: string;
    address: string;
    complexId: string;
    email: string;
    phone: string;
    scanned: boolean;
    complete: boolean;
}
 
interface LlmResponse {
    choices: {
        message: {
            content: string;
        };
    }[];
}
 
// Process Contract Logic
export const processContract = async (text: string, phone: string): Promise<void> => {
    console.log("Processing contract text...");
    const prompt = `You will be given some OCR scanned text from a letter. You have to get the UUIDV4 ID of the contract from the text.
                    ONLY RETURN THE JSON!
                    Required format: {"id" : string | null}
                    OCR Text: ${text}`;
 
    try {
        const llmApiResponse = await axios.post<LlmResponse>(
            'https://openrouter.ai/api/v1/chat/completions',
            {
                model: 'google/gemini-2.0-flash-001',
                messages: [{ role: 'user', content: prompt }],
            },
            {
                headers: {
                    Authorization: `Bearer ${OPENROUTER_API_KEY}`,
                    'Content-Type': 'application/json',
                },
            }
        );
 
        let response = llmApiResponse.data.choices[0].message.content;
        if (response.startsWith('```')) {
            response = response.replace(/```(?:json)?\s*([\s\S]*?)\s*```/, '$1').trim();
        }
 
        const parsed = JSON.parse(response);
        if (!parsed.id) throw new Error("No ID found in contract");
 
        // Get Contract
        const contractResult = await getItem({
            TableName: TABLE_NAME,
            Key: { PK: `CONTRACT#${parsed.id}`, SK: `CONTRACT#${parsed.id}` }
        });
        const contract = contractResult.Item as ContractData | undefined;
 
        if (contract) {
            // Update Contract
            await updateItem({
                TableName: TABLE_NAME,
                Key: { PK: `CONTRACT#${parsed.id}`, SK: `CONTRACT#${parsed.id}` },
                UpdateExpression: "set scanned = :s, phone = :p",
                ExpressionAttributeValues: { ":s": true, ":p": phone }
            });
 
            // Create Phone Lookup for Contract
            await addItem({
                TableName: TABLE_NAME,
                Item: {
                    PK: `PHONE#${phone}`,
                    SK: `CONTRACT_LOOKUP`,
                    type: 'lookup_contract',
                    contractId: parsed.id
                }
            });
 
            if (contract.complete) {
                await sendWhatsAppMessage(phone, "Contract has already been processed!");
                return;
            }
            await sendWhatsAppMessage(phone, `Hello ${contract.name}! We have received your contract. Please type in your email.`);
        }
    } catch (error) {
        console.error("Error processing contract:", error);
        await sendWhatsAppMessage(phone, "Failed to process contract. Please ensure the image is clear or contact support.");
    }
};