Skip to content

Commit

Permalink
Merge pull request #135 from Samstar10/feat/ai-llm-implementation
Browse files Browse the repository at this point in the history
Feat/ai llm implementation
  • Loading branch information
Michaelndula authored Feb 18, 2025
2 parents 8e36f64 + be46308 commit b5c0e91
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 37 deletions.
4 changes: 2 additions & 2 deletions packages/esm-ai-model-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ehospital/esm-ai-model-app",
"version": "1.0.5",
"version": "1.1.1",
"description": "Patient flags microfrontend for the OpenMRS SPA",
"browser": "dist/ehospital-esm-patient-flags-app.js",
"main": "src/index.ts",
Expand Down Expand Up @@ -51,5 +51,5 @@
"@openmrs/esm-patient-common-lib": "next",
"webpack": "^5.74.0"
},
"gitHead": "b7bbdca24433b9ce30599ff829ad756e2ee6e3df"
"gitHead": "ef75e59e34785a3308f03eb24a3273e7cbda6aaa"
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import styles from "./ai-model-action-button.scss.scss";
import { ActionMenuButton } from "@openmrs/esm-framework";
import { t } from "i18next";
import { Chat } from "@carbon/react/icons";
import { useLaunchWorkspaceRequiringVisit } from '@openmrs/esm-patient-common-lib';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import styles from './ai-model.scss'
import PrimaryButton from "../components/primary-button.component";

const AIModelResponse: React.FC = () => {
return (
<div className={styles.container}>
<div className={styles.body}>
<div className={styles.summary}>
<p>This will be the final message to be sent to the client</p>
</div>

<div className={styles.actions}>
<PrimaryButton>Send via SMS</PrimaryButton>
<PrimaryButton>Send via Email</PrimaryButton>
<PrimaryButton>Send via WhatsApp</PrimaryButton>
</div>
</div>
</div>
)
}

export default AIModelResponse
25 changes: 25 additions & 0 deletions packages/esm-ai-model-app/src/ai-model/ai-model.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,29 @@
display: flex;
flex-direction: column;
gap: layout.$spacing-05;
}

.generated {
margin-bottom: layout.$spacing-05;
padding-right: layout.$spacing-05;
position: relative;
}

.editButton {
position: absolute;
top: 0;
right: 0;
cursor: pointer;
}

.title {
font-size: 1.5rem;
font-weight: 500;
}

.feedback {
display: flex;
flex-direction: column;
gap: layout.$spacing-05;
margin-bottom: layout.$spacing-05;
}
48 changes: 33 additions & 15 deletions packages/esm-ai-model-app/src/ai-model/ai-model.workspace.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import React from "react";
import React, { useState } from "react";
import styles from './ai-model.scss'
import {
Button
Button
} from "@carbon/react";
import { Save } from "@carbon/react/icons";
import { SendAlt } from "@carbon/react/icons";
import PrimaryButton from "../components/primary-button.component";
import { TextArea } from "@carbon/react";
import { SendAltFilled } from "@carbon/react/icons";
import { useLaunchWorkspaceRequiringVisit } from "@openmrs/esm-patient-common-lib";
import CustomTextArea from "../components/text-area.component";
import GeneratedResponse from "../components/generated-response.component";
import Feedback from "../components/feedback.component";


const AIModel: React.FC = () => {
const [isEditMode, setEditMode] = useState(false);
const [isRegenerated, setRegenerated] = useState(false);
const launchAiModelGeneratedWorkSpace = useLaunchWorkspaceRequiringVisit('ai-model-generated');

const toggleEditMode = () => {
setEditMode(true);
}

const toggleRegenerate = () => {
setRegenerated(true)
}

return (
<div className={styles.container}>
<div className={styles.body}>
Expand All @@ -32,24 +46,28 @@ const AIModel: React.FC = () => {
</div>

<Button
renderIcon={Save}
renderIcon={SendAlt}
kind="secondary"
size="sm"
>
Save
Generate Message
</Button>
</div>

<div className={styles.chat}>

{!isEditMode && <GeneratedResponse toggleEditMode={toggleEditMode} />}

{isEditMode && <CustomTextArea />}

<div className={styles.actions}>
<PrimaryButton>Send via SMS</PrimaryButton>
<PrimaryButton>Send via Email</PrimaryButton>
<PrimaryButton>Send via WhatsApp</PrimaryButton>
<PrimaryButton onClick={launchAiModelGeneratedWorkSpace}>Approve</PrimaryButton>
<PrimaryButton onClick={toggleRegenerate}>Regenerate</PrimaryButton>
</div>
</div>

{/* <div className={styles.chat}>
<p>Type any question or request to improve the summary if not accurate</p>
<CustomTextArea />
</div> */}
{isRegenerated && <Feedback title="Reason for Regeneration" />}
{isEditMode && <Feedback title="Reason for Edit" />}
</div>
)
}
Expand Down
40 changes: 40 additions & 0 deletions packages/esm-ai-model-app/src/components/feedback.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from 'react';
import styles from '../ai-model/ai-model.scss'
import { Tile, Dropdown } from '@carbon/react';
import { TextInput } from '@carbon/react';

interface FeedbackProps {
title: string,
}

const Feedback: React.FC<FeedbackProps> = ({ title }) => {
const [selectedItem, setSelectedItem] = useState(null);

const items = [
{text: 'Dissatisfied with the response'},
{text: 'Missing information'},
{text: "Other"}
]

return (
<div>
<Tile className={styles.feedback}>
<h1 className={styles.title}>{title}</h1>
<Dropdown
items={items}
itemToString={item => item ? item.text : ''}
label="Select"
onChange={({ selectedItem }) => setSelectedItem(selectedItem)}
/>

{selectedItem?.text === 'Other' && (
<TextInput
placeholder="Type other reason here"
/>
)}
</Tile>
</div>
)
}

export default Feedback
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { Tile } from '@carbon/react';
import styles from '../ai-model/ai-model.scss'
import { Edit } from '@carbon/react/icons';

interface GeneratedResponseProps {
toggleEditMode: () => void
}

const GeneratedResponse: React.FC<GeneratedResponseProps> = ({ toggleEditMode }) => {
return (
<Tile>
<div className={styles.generated}>
This is the generated text from the LLM
<div className={styles.editButton} onClick={toggleEditMode}>
<Edit aria-label="Edit response" size={20} />
</div>
</div>
</Tile>
)
}

export default GeneratedResponse
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { Button } from '@carbon/react';

interface PrimaryButtonProps {
children: React.ReactNode
onClick?: () => void
}

const PrimaryButton: React.FC<PrimaryButtonProps> = ({ children }) => {
const PrimaryButton: React.FC<PrimaryButtonProps> = ({ children, onClick }) => {
return (
<Button
size="sm"
style={{paddingRight: '1.2rem'}}
onClick={onClick}
>
{children}
</Button>
Expand Down
16 changes: 0 additions & 16 deletions packages/esm-ai-model-app/src/components/text-area.component.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import { TextArea } from '@carbon/react';
import { SendAltFilled } from '@carbon/icons-react'; // Import the Send icon

const CustomTextArea = () => {
return (
Expand All @@ -9,21 +8,6 @@ const CustomTextArea = () => {
id="custom-textarea"
labelText=""
placeholder="Message eChat"
style={{
paddingRight: '40px',
paddingBottom: '40px',
}}
/>
<SendAltFilled
style={{
position: 'absolute',
right: '10px',
bottom: '10px',
cursor: 'pointer',
color: '#0f62fe',
width: '30px',
height: '30px',
}}
/>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions packages/esm-ai-model-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const importTranslation = require.context(
export const aiModelWorkspace = getAsyncLifecycle(() => import("./ai-model/ai-model.workspace"), options);

export const aiModelLaunchButton = getSyncLifecycle(AiModelActionButton, options);
export const aiModelGeneratedWorkspace = getAsyncLifecycle(() => import("./ai-model/ai-model-generated.workspace"), options);

export function startupApp() {
defineConfigSchema(moduleName, configSchema);
Expand Down
10 changes: 9 additions & 1 deletion packages/esm-ai-model-app/src/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@
"workspaces": [
{
"name": "ai-model",
"title": "eChat",
"title": "iChat",
"component": "aiModelWorkspace",
"type": "ai-model",
"canHide": true,
"width":"wider"
},
{
"name": "ai-model-generated",
"title": "iChat",
"component": "aiModelGeneratedWorkspace",
"type": "ai-model",
"canHide": true,
"width": "wider"
}
]
}

0 comments on commit b5c0e91

Please sign in to comment.