Skip to content

Commit

Permalink
fix: #247 check service status and emit error if any
Browse files Browse the repository at this point in the history
  • Loading branch information
louis-menlo authored and hiento09 committed Oct 10, 2023
1 parent 65b1095 commit d7b2edf
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 38 deletions.
3 changes: 0 additions & 3 deletions electron/core/plugins/data-plugin/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,10 @@ function getModelById(modelId: string) {
path.join(app.getPath("userData"), "jan.db")
);

console.debug("Get model by id", modelId);
db.get(
`SELECT * FROM models WHERE id = ?`,
[modelId],
(err: any, row: any) => {
console.debug("Get model by id result", row);

if (row) {
const product = {
id: row.id,
Expand Down
16 changes: 13 additions & 3 deletions electron/core/plugins/inference-plugin/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ const { app, dialog } = require("electron");
const { spawn } = require("child_process");
const fs = require("fs");
const tcpPortUsed = require("tcp-port-used");
const { killPortProcess } = require("kill-port-process");

let subprocess = null;
const PORT = 3928;

const initModel = (product) =>
new Promise<void>(async (res) => {
Expand All @@ -29,8 +31,12 @@ const initModel = (product) =>
}
res();
})
.then(tcpPortUsed.waitUntilFree(3928, 200, 3000))
.then((res) => {
.then(() => tcpPortUsed.waitUntilFree(PORT, 200, 3000))
.catch(async () => {
await killPortProcess(PORT);
return;
})
.then(() => {
let binaryFolder = path.join(__dirname, "nitro"); // Current directory by default

// Read the existing config
Expand Down Expand Up @@ -86,7 +92,10 @@ const initModel = (product) =>
subprocess = null;
});
})
.then(() => tcpPortUsed.waitUntilUsed(3928, 300, 4000))
.then(() => tcpPortUsed.waitUntilUsed(PORT, 300, 30000))
.then(() => {
return {};
})
.catch((err) => {
return { error: err };
});
Expand All @@ -102,6 +111,7 @@ function killSubprocess() {
subprocess = null;
console.log("Subprocess terminated.");
} else {
killPortProcess(PORT);
console.error("No subprocess is currently running.");
}
}
Expand Down
4 changes: 3 additions & 1 deletion electron/core/plugins/inference-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
"webpack-cli": "^5.1.4"
},
"dependencies": {
"kill-port-process": "^3.2.0",
"tcp-port-used": "^1.0.2",
"ts-loader": "^9.5.0"
},
"bundledDependencies": [
"tcp-port-used"
"tcp-port-used",
"kill-port-process"
],
"engines": {
"node": ">=18.0.0"
Expand Down
22 changes: 15 additions & 7 deletions web/app/_components/HistoryItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
conversationStatesAtom,
getActiveConvoIdAtom,
setActiveConvoIdAtom,
updateConversationErrorAtom,
updateConversationWaitingForResponseAtom,
} from "@/_helpers/atoms/Conversation.atom";
import {
setMainViewStateAtom,
Expand All @@ -33,6 +35,10 @@ const HistoryItem: React.FC<Props> = ({
const conversationStates = useAtomValue(conversationStatesAtom);
const activeConvoId = useAtomValue(getActiveConvoIdAtom);
const setActiveConvoId = useSetAtom(setActiveConvoIdAtom);
const updateConvWaiting = useSetAtom(
updateConversationWaitingForResponseAtom
);
const updateConvError = useSetAtom(updateConversationErrorAtom);
const isSelected = activeConvoId === conversation.id;

const { initModel } = useInitModel();
Expand All @@ -42,13 +48,15 @@ const HistoryItem: React.FC<Props> = ({
DataService.GET_MODEL_BY_ID,
conversation.model_id
);
if (!model) {
alert(
`Model ${conversation.model_id} not found! Please re-download the model first.`
);
} else {
initModel(model);
}

if (conversation.id) updateConvWaiting(conversation.id, true);
initModel(model).then((res: any) => {
if (res?.error && conversation.id) {
updateConvError(conversation.id, res.error);
}
if (conversation.id) updateConvWaiting(conversation.id, false);
});

if (activeConvoId !== conversation.id) {
setMainViewState(MainViewState.Conversation);
setActiveConvoId(conversation.id);
Expand Down
20 changes: 14 additions & 6 deletions web/app/_components/InputToolbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import { Fragment } from "react";
import { PlusIcon } from "@heroicons/react/24/outline";
import useCreateConversation from "@/_hooks/useCreateConversation";
import { currentProductAtom } from "@/_helpers/atoms/Model.atom";
import { showingTyping } from "@/_helpers/JotaiWrapper";
import LoadingIndicator from "../LoadingIndicator";
import { currentConvoStateAtom } from "@/_helpers/atoms/Conversation.atom";

const InputToolbar: React.FC = () => {
const showingAdvancedPrompt = useAtomValue(showingAdvancedPromptAtom);
const currentProduct = useAtomValue(currentProductAtom);
const { requestCreateConvo } = useCreateConversation();
const isTyping = useAtomValue(showingTyping);
const currentConvoState = useAtomValue(currentConvoStateAtom);

if (showingAdvancedPrompt) {
return <div />;
Expand All @@ -34,12 +34,20 @@ const InputToolbar: React.FC = () => {
return (
<Fragment>
<div className="flex justify-between gap-2 mr-3 my-2">
<div className="h-6">
{isTyping && (
<div className="my-2" key="indicator">
<div className="h-6 space-x-5">
{currentConvoState?.waitingForResponse === true && (
<div className="ml-1 my-2" key="indicator">
<LoadingIndicator />
</div>
)}{" "}
)}
{!currentConvoState?.waitingForResponse &&
currentConvoState?.error && (
<div className="flex flex-row justify-center">
<span className="mx-5 my-2 text-red-500 text-sm">
{currentConvoState?.error?.toString()}
</span>
</div>
)}
</div>

{/* <SecondaryButton title="Regenerate" onClick={onRegenerateClick} /> */}
Expand Down
2 changes: 0 additions & 2 deletions web/app/_helpers/JotaiWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ export default function JotaiWrapper({ children }: Props) {

export const currentPromptAtom = atom<string>("");

export const showingTyping = atom<boolean>(false);

export const appDownloadProgress = atom<number>(-1);
export const searchingModelText = atom<string>("");

Expand Down
11 changes: 11 additions & 0 deletions web/app/_helpers/atoms/Conversation.atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ export const updateConversationWaitingForResponseAtom = atom(
set(conversationStatesAtom, currentState);
}
);
export const updateConversationErrorAtom = atom(
null,
(get, set, conversationId: string, error?: Error) => {
const currentState = { ...get(conversationStatesAtom) };
currentState[conversationId] = {
...currentState[conversationId],
error,
};
set(conversationStatesAtom, currentState);
}
);
export const updateConversationHasMoreAtom = atom(
null,
(get, set, conversationId: string, hasMore: boolean) => {
Expand Down
15 changes: 14 additions & 1 deletion web/app/_hooks/useCreateConversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
userConversationsAtom,
setActiveConvoIdAtom,
addNewConversationStateAtom,
updateConversationWaitingForResponseAtom,
updateConversationErrorAtom,
} from "@/_helpers/atoms/Conversation.atom";
import useInitModel from "./useInitModel";

Expand All @@ -17,6 +19,10 @@ const useCreateConversation = () => {
);
const setActiveConvoId = useSetAtom(setActiveConvoIdAtom);
const addNewConvoState = useSetAtom(addNewConversationStateAtom);
const updateConvWaiting = useSetAtom(
updateConversationWaitingForResponseAtom
);
const updateConvError = useSetAtom(updateConversationErrorAtom);

const requestCreateConvo = async (model: Product) => {
const conversationName = model.name;
Expand All @@ -27,7 +33,14 @@ const useCreateConversation = () => {
name: conversationName,
};
const id = await executeSerial(DataService.CREATE_CONVERSATION, conv);
await initModel(model);

if (id) updateConvWaiting(id, true);
initModel(model).then((res: any) => {
if (res?.error) {
updateConvError(id, res.error);
}
if (id) updateConvWaiting(id, false);
});

const mappedConvo: Conversation = {
id,
Expand Down
22 changes: 12 additions & 10 deletions web/app/_hooks/useInitModel.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { Product } from "@/_models/Product";
import { executeSerial } from "@/_services/pluginService";
import { InfereceService } from "../../shared/coreService";
import { useAtom } from "jotai";
import { useAtom, useSetAtom } from "jotai";
import { currentProductAtom } from "@/_helpers/atoms/Model.atom";
import { updateConversationWaitingForResponseAtom } from "@/_helpers/atoms/Conversation.atom";

export default function useInitModel() {
const [activeModel, setActiveModel] = useAtom(currentProductAtom);
const updateConvWaiting = useSetAtom(
updateConversationWaitingForResponseAtom
);

const initModel = async (model: Product) => {
if (activeModel && activeModel.id === model.id) {
console.debug(`Model ${model.id} is already init. Ignore..`);
return;
}
try {
const res = await executeSerial(InfereceService.INIT_MODEL, model);
if (res?.error) {
console.log("error occured: ", res);
} else {
console.debug(`Init model ${model.name} successfully!`);
}
const res = await executeSerial(InfereceService.INIT_MODEL, model);
if (res?.error) {
console.log("error occured: ", res);
return res;
} else {
console.log(`Init model successfully!`);
setActiveModel(model);
} catch (err) {
console.error(`Init model ${model.name} failed: ${err}`);
return {};
}
};

Expand Down
15 changes: 10 additions & 5 deletions web/app/_hooks/useSendChatMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { currentPromptAtom, showingTyping } from "@/_helpers/JotaiWrapper";
import { currentPromptAtom } from "@/_helpers/JotaiWrapper";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { selectAtom } from "jotai/utils";
import { DataService, InfereceService } from "../../shared/coreService";
Expand All @@ -18,6 +18,7 @@ import {
import {
currentConversationAtom,
getActiveConvoIdAtom,
updateConversationWaitingForResponseAtom,
} from "@/_helpers/atoms/Conversation.atom";

export default function useSendChatMessage() {
Expand All @@ -26,6 +27,9 @@ export default function useSendChatMessage() {
const addNewMessage = useSetAtom(addNewMessageAtom);
const updateMessage = useSetAtom(updateMessageAtom);
const activeConversationId = useAtomValue(getActiveConvoIdAtom) ?? "";
const updateConvWaiting = useSetAtom(
updateConversationWaitingForResponseAtom
);

const chatMessagesHistory = useAtomValue(
selectAtom(
Expand All @@ -34,10 +38,11 @@ export default function useSendChatMessage() {
)
);
const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom);
const [, setIsTyping] = useAtom(showingTyping);

const sendChatMessage = async () => {
setIsTyping(true);
setCurrentPrompt("");
const conversationId = activeConversationId;
updateConvWaiting(conversationId, true);
const prompt = currentPrompt.trim();
const newMessage: RawMessage = {
conversation_id: parseInt(currentConvo?.id ?? "0") ?? 0,
Expand Down Expand Up @@ -108,7 +113,7 @@ export default function useSendChatMessage() {
const lines = text.trim().split("\n");
for (const line of lines) {
if (line.startsWith("data: ") && !line.includes("data: [DONE]")) {
setIsTyping(false);
updateConvWaiting(conversationId, false);
const data = JSON.parse(line.replace("data: ", ""));
answer += data.choices[0]?.delta?.content ?? "";
if (answer.startsWith("assistant: ")) {
Expand Down Expand Up @@ -139,7 +144,7 @@ export default function useSendChatMessage() {
.replace("T", " ")
.replace(/\.\d+Z$/, ""),
});
setIsTyping(false);
updateConvWaiting(conversationId, false);
};
return {
sendChatMessage,
Expand Down
1 change: 1 addition & 0 deletions web/app/_models/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export interface Conversation {
export type ConversationState = {
hasMore: boolean;
waitingForResponse: boolean;
error?: Error;
};

0 comments on commit d7b2edf

Please sign in to comment.