'use server'; import { AccountWithParams } from '@/packages/features/accounts/src/types/accounts'; import { AnalysisResponse, Patient, } from '@/packages/features/doctor/src/lib/server/schema/doctor-analysis-detail-view.schema'; import { getLogger } from '@/packages/shared/src/logger'; import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client'; import OpenAI from 'openai'; import PersonalCode from '~/lib/utils'; import { AnalysisResponses, ILifeStyleResponse, PROMPT_NAME, } from '../../_components/ai/types'; import { OrderAnalysisCard } from '../../_components/order-analyses-cards'; export async function updateLifeStyle({ account, analysisResponses, isDoctorView = false, aiResponseTimestamp, }: { account: AccountWithParams; analysisResponses?: AnalysisResponses; isDoctorView?: boolean; aiResponseTimestamp: string; }): Promise { const LIFE_STYLE_PROMPT_ID = process.env.PROMPT_ID_LIFE_STYLE; if (!LIFE_STYLE_PROMPT_ID || !account?.personal_code) { return { lifestyle: [], summary: null, }; } const openAIClient = new OpenAI(); const supabaseClient = getSupabaseServerClient(); const { gender, age } = PersonalCode.parsePersonalCode(account.personal_code); const weight = account.accountParams?.weight || 'unknown'; const height = account.accountParams?.height || 'unknown'; const isSmoker = !!account.accountParams?.isSmoker; const cholesterol = analysisResponses ?.find((ar) => ar.analysis_name_lab === 'Kolesterool') ?.response_value.toString() || 'unknown'; const ldl = analysisResponses ?.find((ar) => ar.analysis_name_lab === 'LDL kolesterool') ?.response_value.toString() || 'unknown'; const hdl = analysisResponses ?.find((ar) => ar.analysis_name_lab === 'HDL kolesterool') ?.response_value.toString() || 'unknown'; const vitamind = analysisResponses ?.find((ar) => ar.analysis_name_lab === 'Vitamiin D (25-OH)') ?.response_value.toString() || 'unknown'; try { const response = await openAIClient.responses.create({ store: false, prompt: { id: LIFE_STYLE_PROMPT_ID, variables: { gender: gender.value, age: age.toString(), weight: weight.toString(), height: height.toString(), cholesterol, ldl, hdl, vitamind, is_smoker: isSmoker.toString(), }, }, }); await supabaseClient .schema('medreport') .from('ai_responses') .insert({ account_id: account.id, prompt_name: PROMPT_NAME.LIFE_STYLE, prompt_id: LIFE_STYLE_PROMPT_ID, input: JSON.stringify({ gender: gender.value, age: age.toString(), weight: weight.toString(), cholesterol, ldl, hdl, vitamind, is_smoker: isSmoker.toString(), }), latest_data_change: aiResponseTimestamp, response: response.output_text, is_visible_to_customer: !isDoctorView, }); const json = JSON.parse(response.output_text); return json; } catch (error) { console.error('Error calling OpenAI: ', error); return { lifestyle: [], summary: null, }; } } export async function updateRecommendations({ analyses, analysisResponses, account, aiResponseTimestamp, }: { analyses: OrderAnalysisCard[]; analysisResponses?: AnalysisResponses; account: AccountWithParams; aiResponseTimestamp: string; }) { const RECOMMENDATIONS_PROMPT_IT = process.env.PROMPT_ID_ANALYSIS_RECOMMENDATIONS; if (!RECOMMENDATIONS_PROMPT_IT || !account?.personal_code) { console.error('No prompt ID for analysis recommendations'); return []; } const openAIClient = new OpenAI(); const supabaseClient = getSupabaseServerClient(); const { gender, age } = PersonalCode.parsePersonalCode(account.personal_code); const weight = account.accountParams?.weight || 'unknown'; const formattedAnalysisResponses = analysisResponses?.map( ({ analysis_name_lab, response_value, norm_upper, norm_lower, norm_status, }) => ({ name: analysis_name_lab, value: response_value, normUpper: norm_upper, normLower: norm_lower, normStatus: norm_status, }), ); const formattedAnalyses = analyses.map(({ description, title }) => ({ description, title, })); try { const response = await openAIClient.responses.create({ store: false, prompt: { id: RECOMMENDATIONS_PROMPT_IT, variables: { analyses: JSON.stringify(formattedAnalyses), results: JSON.stringify(formattedAnalysisResponses), gender: gender.value, age: age.toString(), weight: weight.toString(), }, }, }); await supabaseClient .schema('medreport') .from('ai_responses') .insert({ account_id: account.id, prompt_name: PROMPT_NAME.ANALYSIS_RECOMMENDATIONS, prompt_id: RECOMMENDATIONS_PROMPT_IT, input: JSON.stringify({ analyses: formattedAnalyses, results: formattedAnalysisResponses, gender, age, weight, }), latest_data_change: aiResponseTimestamp, response: response.output_text, is_visible_to_customer: false, }); const json = JSON.parse(response.output_text); return json.recommended; } catch (error) { console.error('Error getting recommendations: ', error); return []; } } export async function generateDoctorFeedback({ patient, analysisResponses, aiResponseTimestamp, }: { patient: Patient; analysisResponses: AnalysisResponse[]; aiResponseTimestamp: string; }): Promise { const DOCTOR_FEEDBACK_PROMPT_ID = process.env.PROMPT_ID_DOCTOR_FEEDBACK; if (!DOCTOR_FEEDBACK_PROMPT_ID) { console.error('No secrets for doctor feedback'); return ''; } const openAIClient = new OpenAI(); const supabaseClient = getSupabaseServerClient(); const formattedAnalysisResponses = analysisResponses?.map( ({ analysis_name, response_value, norm_upper, norm_lower, norm_status, }) => ({ name: analysis_name, value: response_value, normUpper: norm_upper, normLower: norm_lower, normStatus: norm_status, }), ); try { const response = await openAIClient.responses.create({ store: false, prompt: { id: DOCTOR_FEEDBACK_PROMPT_ID, variables: { analysesresults: JSON.stringify(formattedAnalysisResponses), }, }, }); await supabaseClient .schema('medreport') .from('ai_responses') .insert({ account_id: patient.userId, prompt_name: PROMPT_NAME.FEEDBACK, prompt_id: DOCTOR_FEEDBACK_PROMPT_ID, input: JSON.stringify({ analysesresults: formattedAnalysisResponses, }), latest_data_change: aiResponseTimestamp, response: response.output_text, }); return response.output_text; } catch (error) { console.error('Error getting doctor feedback: ', error); return ''; } } export async function confirmPatientAIResponses( patientId: string, aiResponseTimestamp: string, recommendations: string[], isRecommendationsEdited: boolean, ) { const logger = await getLogger(); const supabaseClient = getSupabaseServerClient(); const { error } = await supabaseClient .schema('medreport') .from('ai_responses') .update({ is_visible_to_customer: true, }) .eq('latest_data_change', aiResponseTimestamp) .eq('account_id', patientId) .eq('prompt_name', PROMPT_NAME.LIFE_STYLE); if (error) { logger.error( { error, patientId, aiResponseTimestamp }, 'Failed updating life style', ); } const { error: _error } = await supabaseClient .schema('medreport') .from('ai_responses') .update({ is_visible_to_customer: true, ...(isRecommendationsEdited && { response: JSON.stringify({ why: 'This was edited by doctor', recommended: recommendations, }), }), }) .eq('latest_data_change', aiResponseTimestamp) .eq('account_id', patientId) .eq('prompt_name', PROMPT_NAME.ANALYSIS_RECOMMENDATIONS); if (_error) { logger.error( { error, aiResponseTimestamp, patientId, isRecommendationsEdited, }, 'Failed updating analysis recommendations', ); } }