Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
124
server/api/analyze-asnaf.post.ts
Normal file
124
server/api/analyze-asnaf.post.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { defineEventHandler, readBody } from 'h3';
|
||||
|
||||
// Define an interface for the expected request body (subset of AsnafProfile)
|
||||
interface AsnafAnalysisRequest {
|
||||
monthlyIncome: string;
|
||||
otherIncome: string;
|
||||
totalIncome: string;
|
||||
occupation: string;
|
||||
maritalStatus: string;
|
||||
dependents: Array<any>; // Or a more specific type if you have one for dependents
|
||||
// Add any other fields you deem necessary for OpenAI to analyze
|
||||
}
|
||||
|
||||
interface AidSuggestion {
|
||||
nama: string;
|
||||
peratusan: string;
|
||||
}
|
||||
|
||||
// Define an interface for the expected OpenAI response structure (and our API response)
|
||||
interface AsnafAnalysisResponse {
|
||||
hadKifayahPercentage: string;
|
||||
kategoriAsnaf: string;
|
||||
kategoriKeluarga: string;
|
||||
cadanganKategori: string;
|
||||
statusKelayakan: string;
|
||||
cadanganBantuan: AidSuggestion[];
|
||||
ramalanJangkaMasaPulih: string;
|
||||
rumusan: string;
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event): Promise<AsnafAnalysisResponse> => {
|
||||
const body = await readBody<AsnafAnalysisRequest>(event);
|
||||
|
||||
// --- Placeholder for Actual OpenAI API Call ---
|
||||
// In a real application, you would:
|
||||
// 1. Retrieve your OpenAI API key securely (e.g., from environment variables)
|
||||
const openAIApiKey = process.env.OPENAI_API_KEY;
|
||||
if (!openAIApiKey) {
|
||||
console.error('OpenAI API key not configured. Please set OPENAI_API_KEY in your .env file.');
|
||||
throw createError({ statusCode: 500, statusMessage: 'OpenAI API key not configured' });
|
||||
}
|
||||
|
||||
// 2. Construct the prompt for OpenAI using the data from `body`.
|
||||
// IMPORTANT: Sanitize or carefully construct any data from `body` included in the prompt to prevent prompt injection.
|
||||
const prompt = `You are an expert Zakat administrator. Based on the following applicant data: monthlyIncome: ${body.monthlyIncome}, totalIncome: ${body.totalIncome}, occupation: ${body.occupation}, maritalStatus: ${body.maritalStatus}, dependents: ${body.dependents.length}.
|
||||
Return JSON with keys: hadKifayahPercentage, kategoriAsnaf, kategoriKeluarga, cadanganKategori, statusKelayakan, cadanganBantuan, ramalanJangkaMasaPulih, rumusan.
|
||||
For 'cadanganBantuan', provide a JSON array of objects, where each object has a 'nama' (string, name of the aid) and 'peratusan' (string, e.g., '85%', representing suitability). Suggest 2-3 most relevant aid types.
|
||||
Example for cadanganBantuan: [{"nama": "Bantuan Kewangan Bulanan", "peratusan": "90%"}, {"nama": "Bantuan Makanan Asas", "peratusan": "75%"}].
|
||||
Full JSON Example: {"hadKifayahPercentage": "75%", ..., "cadanganBantuan": [{"nama": "Bantuan Kewangan Bulanan", "peratusan": "90%"}], ...}`;
|
||||
// Adjust the prompt to be more detailed and specific to your needs and desired JSON output structure.
|
||||
|
||||
// 3. Make the API call to OpenAI
|
||||
try {
|
||||
const openAIResponse = await fetch('https://api.openai.com/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${openAIApiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'gpt-3.5-turbo', // Or your preferred model like gpt-4
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
// For more consistent JSON output, consider using a model version that officially supports JSON mode if available
|
||||
// and set response_format: { type: "json_object" }, (check OpenAI documentation for model compatibility)
|
||||
}),
|
||||
});
|
||||
|
||||
if (!openAIResponse.ok) {
|
||||
const errorData = await openAIResponse.text();
|
||||
console.error('OpenAI API Error details:', errorData);
|
||||
throw createError({ statusCode: openAIResponse.status, statusMessage: `Failed to get analysis from OpenAI: ${openAIResponse.statusText}` });
|
||||
}
|
||||
|
||||
const openAIData = await openAIResponse.json();
|
||||
|
||||
// Parse the content from the response - structure might vary slightly based on OpenAI model/API version
|
||||
// It's common for the JSON string to be in openAIData.choices[0].message.content
|
||||
if (openAIData.choices && openAIData.choices[0] && openAIData.choices[0].message && openAIData.choices[0].message.content) {
|
||||
const analysisResult = JSON.parse(openAIData.choices[0].message.content) as AsnafAnalysisResponse;
|
||||
return analysisResult;
|
||||
} else {
|
||||
console.error('OpenAI response structure not as expected:', openAIData);
|
||||
throw createError({ statusCode: 500, statusMessage: 'Unexpected response structure from OpenAI' });
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during OpenAI API call or parsing:', error);
|
||||
// Avoid exposing detailed internal errors to the client if they are not createError objects
|
||||
if (typeof error === 'object' && error !== null && 'statusCode' in error) {
|
||||
// We can infer error has statusCode here, but to be super safe with TS:
|
||||
const e = error as { statusCode: number };
|
||||
if (e.statusCode) throw e;
|
||||
}
|
||||
throw createError({ statusCode: 500, statusMessage: 'Internal server error during AI analysis' });
|
||||
}
|
||||
// --- End of Actual OpenAI API Call ---
|
||||
|
||||
// The simulated response below this line should be REMOVED once the actual OpenAI call is implemented and working.
|
||||
/*
|
||||
console.log('Received for analysis in server route:', body);
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate API delay
|
||||
|
||||
const totalIncomeNumeric = parseFloat(body.totalIncome);
|
||||
let percentage = '50%';
|
||||
if (totalIncomeNumeric < 1000) percentage = '30%';
|
||||
else if (totalIncomeNumeric < 2000) percentage = '65%';
|
||||
else if (totalIncomeNumeric < 3000) percentage = '85%';
|
||||
else percentage = '110%';
|
||||
|
||||
return {
|
||||
hadKifayahPercentage: percentage,
|
||||
kategoriAsnaf: 'Simulated - Miskin',
|
||||
kategoriKeluarga: 'Simulated - Miskin (50-100% HK)',
|
||||
cadanganKategori: 'Simulated - Miskin',
|
||||
statusKelayakan: 'Simulated - Layak (Miskin)',
|
||||
cadanganBantuan: [
|
||||
{ nama: 'Simulated - Bantuan Kewangan Bulanan', peratusan: '80%' },
|
||||
{ nama: 'Simulated - Bantuan Pendidikan Anak', peratusan: '65%' }
|
||||
],
|
||||
ramalanJangkaMasaPulih: 'Simulated - 6 bulan',
|
||||
rumusan: 'Simulated - Pemohon memerlukan perhatian segera.'
|
||||
};
|
||||
*/
|
||||
});
|
||||
Reference in New Issue
Block a user