-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathserver.ts
More file actions
136 lines (115 loc) · 4.18 KB
/
server.ts
File metadata and controls
136 lines (115 loc) · 4.18 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import express from "express";
import path from "path";
import { createServer as createViteServer } from "vite";
import { GoogleGenAI } from "@google/genai";
import multer from "multer";
import dotenv from "dotenv";
dotenv.config();
const upload = multer({ storage: multer.memoryStorage() });
async function startServer() {
const app = express();
const PORT = 3000;
const ai = new GoogleGenAI({
apiKey: process.env.GEMINI_API_KEY || "",
httpOptions: {
headers: {
'User-Agent': 'aistudio-build',
}
}
});
app.use(express.json());
// Arbitration Endpoint
app.post("/api/arbitrate", upload.fields([
{ name: 'bylaws', maxCount: 1 },
{ name: 'records', maxCount: 1 },
{ name: 'csv', maxCount: 1 }
]), async (req: any, res) => {
try {
const { message, chatHistory } = req.body;
const files = req.files as { [fieldname: string]: Express.Multer.File[] };
let contextParts: any[] = [];
if (files?.bylaws?.[0]) {
contextParts.push({
text: `CHAMA BYLAWS:\n${files.bylaws[0].buffer.toString('utf-8')}`
});
}
if (files?.records?.[0]) {
contextParts.push({
text: `M-PESA RECORDS:\n${files.records[0].buffer.toString('utf-8')}`
});
}
if (files?.csv?.[0]) {
contextParts.push({
text: `CONTRIBUTION CSV RECORDS:\n${files.csv[0].buffer.toString('utf-8')}`
});
}
const systemInstruction = `
You are "Chama Arbitrator", a professional, fair, and culturally informed AI mediator for Kenyan Chamas.
Your goal is to resolve member disputes fairly based on:
1. The provided Chama Bylaws.
2. Transaction/Contribution records (often in Sheng/Kiswahili or M-Pesa format).
3. General Kenyan legal and financial norms if bylaws are silent.
Guidelines:
- Handle inputs in Sheng, Kiswahili, and English. Respond in the language used by the user or a mix if appropriate.
- Always cite specific sections from the bylaws if they exist in the context.
- Be neutral. Don't take sides unless the evidence (records/bylaws) clearly supports one party.
- If a dispute is heated, use calming language.
- If records show a missing contribution, point it out politely.
STRUCTURED RESOLUTION:
When you reach a conclusion or propose a specific settlement, include a block at the end of your response like this:
[RESOLUTION_DRAFT]
{
"planName": "Name of the plan",
"penaltyWaived": "YES/NO",
"extension": "Duration or NONE",
"nextDue": "Date",
"summary": "Brief summary"
}
[/RESOLUTION_DRAFT]
`;
const rawHistory = chatHistory ? JSON.parse(chatHistory) : [];
const formattedContents = rawHistory.map((msg: any) => ({
role: msg.role === 'user' ? 'user' : 'model',
parts: [{ text: msg.text }]
}));
// Add the current user message
formattedContents.push({ role: 'user', parts: [{ text: message }] });
// Build the final contents array
const contents = [];
if (contextParts.length > 0) {
contents.push({ role: 'user', parts: contextParts });
}
contents.push(...formattedContents);
const response = await ai.models.generateContent({
model: "gemini-3-flash-preview",
contents,
config: {
systemInstruction,
temperature: 0.7,
},
});
res.json({ text: response.text });
} catch (error: any) {
console.error("Arbitration Error:", error);
res.status(500).json({ error: error.message });
}
});
// Vite middleware for development
if (process.env.NODE_ENV !== "production") {
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "spa",
});
app.use(vite.middlewares);
} else {
const distPath = path.join(process.cwd(), 'dist');
app.use(express.static(distPath));
app.get('*', (req, res) => {
res.sendFile(path.join(distPath, 'index.html'));
});
}
app.listen(PORT, "0.0.0.0", () => {
console.log(`Server running on http://localhost:${PORT}`);
});
}
startServer();