* WIP on mobile connections todo: register devices todo: data sync or connection * improve connection flow and registration add streaming from service TODO: user scoping * dev build mobile support * fix path * handle relative URLs * handle localhost access in product * add device de-register * sync styles * move UI to be out of the normal path since beta only * Add user scoping to mobile connection requests Remigrate DB for user associations Implement temp token registration to prevent unauthorized device registration requests cleanup middlewares
196 lines
6.4 KiB
JavaScript
196 lines
6.4 KiB
JavaScript
const { Workspace } = require("../../../models/workspace");
|
|
const { WorkspaceChats } = require("../../../models/workspaceChats");
|
|
const { WorkspaceThread } = require("../../../models/workspaceThread");
|
|
const { ApiChatHandler } = require("../../../utils/chats/apiChatHandler");
|
|
const { reqBody } = require("../../../utils/http");
|
|
const prisma = require("../../../utils/prisma");
|
|
const { getModelTag } = require("../../utils");
|
|
const { MobileDevice } = require("../../../models/mobileDevice");
|
|
|
|
/**
|
|
*
|
|
* @param {import("express").Request} request
|
|
* @param {import("express").Response} response
|
|
* @returns
|
|
*/
|
|
async function handleMobileCommand(request, response) {
|
|
const { command } = request.params;
|
|
const user = response.locals.user ?? null;
|
|
const body = reqBody(request);
|
|
|
|
if (command === "workspaces") {
|
|
const workspaces = user
|
|
? await Workspace.whereWithUser(user, {})
|
|
: await Workspace.where({});
|
|
for (const workspace of workspaces) {
|
|
const [threadCount, chatCount] = await Promise.all([
|
|
prisma.workspace_threads.count({
|
|
where: {
|
|
workspace_id: workspace.id,
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
}),
|
|
prisma.workspace_chats.count({
|
|
where: {
|
|
workspaceId: workspace.id,
|
|
include: true,
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
}),
|
|
]);
|
|
workspace.threadCount = threadCount;
|
|
workspace.chatCount = chatCount;
|
|
workspace.platform = MobileDevice.platform;
|
|
}
|
|
return response.status(200).json({ workspaces });
|
|
}
|
|
|
|
if (command === "workspace-content") {
|
|
const workspace = user
|
|
? await Workspace.getWithUser(user, { slug: String(body.workspaceSlug) })
|
|
: await Workspace.get({ slug: String(body.workspaceSlug) });
|
|
|
|
if (!workspace)
|
|
return response.status(400).json({ error: "Workspace not found" });
|
|
const threads = [
|
|
{
|
|
id: 0,
|
|
name: "Default Thread",
|
|
slug: "default-thread",
|
|
workspace_id: workspace.id,
|
|
createdAt: new Date(),
|
|
lastUpdatedAt: new Date(),
|
|
},
|
|
...(await prisma.workspace_threads.findMany({
|
|
where: {
|
|
workspace_id: workspace.id,
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
})),
|
|
];
|
|
const chats = (
|
|
await prisma.workspace_chats.findMany({
|
|
where: {
|
|
workspaceId: workspace.id,
|
|
include: true,
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
})
|
|
).map((chat) => ({
|
|
...chat,
|
|
// Create a dummy thread_id for the default thread so the chats can be mapped correctly.
|
|
...(chat.thread_id === null ? { thread_id: 0 } : {}),
|
|
createdAt: chat.createdAt.toISOString(),
|
|
lastUpdatedAt: chat.lastUpdatedAt.toISOString(),
|
|
}));
|
|
return response.status(200).json({ threads, chats });
|
|
}
|
|
|
|
// Get the model for this workspace (workspace -> system)
|
|
if (command === "model-tag") {
|
|
const { workspaceSlug } = body;
|
|
const workspace = user
|
|
? await Workspace.getWithUser(user, { slug: String(workspaceSlug) })
|
|
: await Workspace.get({ slug: String(workspaceSlug) });
|
|
|
|
if (!workspace)
|
|
return response.status(400).json({ error: "Workspace not found" });
|
|
if (workspace.chatModel)
|
|
return response.status(200).json({ model: workspace.chatModel });
|
|
else return response.status(200).json({ model: getModelTag() });
|
|
}
|
|
|
|
if (command === "reset-chat") {
|
|
const { workspaceSlug, threadSlug } = body;
|
|
const workspace = user
|
|
? await Workspace.getWithUser(user, { slug: String(workspaceSlug) })
|
|
: await Workspace.get({ slug: String(workspaceSlug) });
|
|
|
|
if (!workspace)
|
|
return response.status(400).json({ error: "Workspace not found" });
|
|
const threadId = threadSlug
|
|
? await prisma.workspace_threads.findFirst({
|
|
where: {
|
|
workspace_id: workspace.id,
|
|
slug: String(threadSlug),
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
})?.id
|
|
: null;
|
|
|
|
await WorkspaceChats.markThreadHistoryInvalidV2({
|
|
workspaceId: workspace.id,
|
|
...(user ? { user_id: user.id } : {}),
|
|
thread_id: threadId, // if threadId is null, this will reset the default thread.
|
|
});
|
|
return response.status(200).json({ success: true });
|
|
}
|
|
|
|
if (command === "new-thread") {
|
|
const { workspaceSlug } = body;
|
|
const workspace = user
|
|
? await Workspace.getWithUser(user, { slug: String(workspaceSlug) })
|
|
: await Workspace.get({ slug: String(workspaceSlug) });
|
|
|
|
if (!workspace)
|
|
return response.status(400).json({ error: "Workspace not found" });
|
|
const { thread } = await WorkspaceThread.new(workspace, user?.id);
|
|
return response.status(200).json({ thread });
|
|
}
|
|
|
|
if (command === "stream-chat") {
|
|
const { workspaceSlug = null, threadSlug = null, message } = body;
|
|
if (!workspaceSlug)
|
|
return response.status(400).json({ error: "Workspace ID is required" });
|
|
else if (!message)
|
|
return response.status(400).json({ error: "Message is required" });
|
|
|
|
const workspace = user
|
|
? await Workspace.getWithUser(user, { slug: String(workspaceSlug) })
|
|
: await Workspace.get({ slug: String(workspaceSlug) });
|
|
|
|
if (!workspace)
|
|
return response.status(400).json({ error: "Workspace not found" });
|
|
const thread = threadSlug
|
|
? await prisma.workspace_threads.findFirst({
|
|
where: {
|
|
workspace_id: workspace.id,
|
|
slug: String(threadSlug),
|
|
...(user ? { user_id: user.id } : {}),
|
|
},
|
|
})
|
|
: null;
|
|
|
|
response.setHeader("Cache-Control", "no-cache");
|
|
response.setHeader("Content-Type", "text/event-stream");
|
|
response.setHeader("Access-Control-Allow-Origin", "*");
|
|
response.setHeader("Connection", "keep-alive");
|
|
response.flushHeaders();
|
|
await ApiChatHandler.streamChat({
|
|
response,
|
|
workspace,
|
|
thread,
|
|
message,
|
|
mode: "chat",
|
|
user: user,
|
|
sessionId: null,
|
|
attachments: [],
|
|
reset: false,
|
|
});
|
|
return response.end();
|
|
}
|
|
|
|
if (command === "unregister-device") {
|
|
if (!response.locals.device)
|
|
return response.status(200).json({ success: true });
|
|
await MobileDevice.delete(response.locals.device.id);
|
|
return response.status(200).json({ success: true });
|
|
}
|
|
|
|
return response.status(400).json({ error: "Invalid command" });
|
|
}
|
|
|
|
module.exports = {
|
|
handleMobileCommand,
|
|
};
|