Skip to content

Commit

Permalink
feat: add model name to chat window
Browse files Browse the repository at this point in the history
  • Loading branch information
comoser committed Sep 8, 2023
1 parent 0617908 commit 20b0adb
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 28 deletions.
16 changes: 14 additions & 2 deletions packages/api/src/ai/ai.controller.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { AiModelResponseDto } from '@/ai/dtos/ai-model.response.dto';
import { FindAiModelUsecase } from '@/ai/usecases/find-ai-model.usecase';
import { FindAiModelsUsecase } from '@/ai/usecases/find-ai-models.usecase';
import { ClerkAuthGuard } from '@/auth/guards/clerk/clerk.auth.guard';
import { ApiClerkAuthHeaders } from '@/auth/guards/clerk/open-api-clerk-headers.decorator';
import { Controller, Get, UseGuards } from '@nestjs/common';
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';

@Controller({ path: 'ai', version: '1' })
@ApiTags('ai')
@UseGuards(ClerkAuthGuard)
export class AiController {
constructor(private readonly findAiModelsUsecase: FindAiModelsUsecase) {}
constructor(
private readonly findAiModelsUsecase: FindAiModelsUsecase,
private readonly findAiModelUsecase: FindAiModelUsecase
) {}

@Get('ai-models')
@ApiClerkAuthHeaders()
Expand All @@ -18,4 +22,12 @@ export class AiController {
async findAiModels(): Promise<AiModelResponseDto[]> {
return this.findAiModelsUsecase.execute();
}

@Get('ai-models/:id')
@ApiClerkAuthHeaders()
@ApiOkResponse({ type: AiModelResponseDto })
@ApiOperation({ description: 'Get an AI Model' })
async findAiModel(@Param('id') id: string): Promise<AiModelResponseDto> {
return this.findAiModelUsecase.execute(id);
}
}
2 changes: 2 additions & 0 deletions packages/api/src/ai/ai.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ToolService } from '@/ai/services/tool.service';
import { VectorDbService } from '@/ai/services/vector-db.service';
import { AdminAddAiModelUsecase } from '@/ai/usecases/admin-add-ai-model.usecase';
import { AdminFindAiModelsUsecase } from '@/ai/usecases/admin-find-ai-models.usecase';
import { FindAiModelUsecase } from '@/ai/usecases/find-ai-model.usecase';
import { FindAiModelsUsecase } from '@/ai/usecases/find-ai-models.usecase';
import { AppConfigModule } from '@/app-config/app-config.module';
import { ClerkAuthGuard } from '@/auth/guards/clerk/clerk.auth.guard';
Expand Down Expand Up @@ -41,6 +42,7 @@ import { ScheduleModule } from '@nestjs/schedule';
AdminAddAiModelUsecase,
AdminFindAiModelsUsecase,
FindAiModelsUsecase,
FindAiModelUsecase,
// Private services
AiModelsRepository,
MemoryService,
Expand Down
20 changes: 20 additions & 0 deletions packages/api/src/ai/usecases/find-ai-model.usecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AiModelsRepository } from '@/ai/ai-models.repository';
import { AiModelResponseDto } from '@/ai/dtos/ai-model.response.dto';
import { InternalServerErrorException } from '@/common/exceptions/internal-server-error.exception';
import { Usecase } from '@/common/types/usecase';
import { AiModelResponseSchema } from '@/contract/ai/ai-model.response.dto';
import { Injectable } from '@nestjs/common';

@Injectable()
export class FindAiModelUsecase implements Usecase {
constructor(private readonly aiModelsRepository: AiModelsRepository) {}

async execute(id: string): Promise<AiModelResponseDto> {
try {
const aiModel = await this.aiModelsRepository.findAiModel(id);
return AiModelResponseSchema.parse(aiModel);
} catch (e) {
throw new InternalServerErrorException(e.message);
}
}
}
1 change: 1 addition & 0 deletions packages/web-ui/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const Endpoints = {
},
ai: {
getAiModels: () => '/ai/ai-models',
getAiModel: (aiModelId: string) => `/ai/ai-models/${aiModelId}`,
},
};
export default Endpoints;
68 changes: 60 additions & 8 deletions packages/web-ui/app/rooms/[room]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import '@/styles/globals.css';
import { ReactNode } from 'react';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { apiClient } from '@/api/apiClient';
import Endpoints from '@/api/endpoints';
import { AiModelResponseDto } from '@/contract/ai/ai-model.response.dto.d';
import { ChatResponseDto } from '@/contract/chats/chat.response.dto.d';
import { RoomResponseDto } from '@/contract/rooms/room.response.dto.d';
import { auth } from '@clerk/nextjs';

import { RoomHeader } from '@/components/room-header';
Expand All @@ -12,16 +14,61 @@ interface RootLayoutProps {
children: React.ReactNode;
}

const getRoom = async (roomId: string) => {
const getRoom = async (
roomId: string
): Promise<RoomResponseDto | undefined> => {
const { sessionId, getToken } = auth();

try {
const nextCookies = cookies();
const clerkJwtToken = nextCookies.get('__session');
const { sessionId } = auth();
const res = await apiClient({
url: Endpoints.rooms.getRoomById(roomId),
options: { method: 'GET', cache: 'no-store' },
sessionId: sessionId ?? '',
jwtToken: clerkJwtToken?.value ?? '',
jwtToken: (await getToken()) ?? '',
});
if (!res.ok) {
return;
}

return res.json();
} catch (e) {
console.log(e);
}
};

const getChat = async (
roomId: string
): Promise<ChatResponseDto | undefined> => {
const { sessionId, getToken } = auth();

try {
const res = await apiClient({
url: Endpoints.chats.getChat(roomId),
options: { method: 'GET' },
sessionId: sessionId ?? '',
jwtToken: (await getToken()) ?? '',
});
if (!res.ok) {
return;
}

return res.json();
} catch (e) {
console.log(e);
}
};

const getAiModel = async (
aiModelId: string
): Promise<AiModelResponseDto | undefined> => {
const { sessionId, getToken } = auth();

try {
const res = await apiClient({
url: Endpoints.ai.getAiModel(aiModelId),
options: { method: 'GET' },
sessionId: sessionId ?? '',
jwtToken: (await getToken()) ?? '',
});
if (!res.ok) {
return;
Expand All @@ -40,15 +87,20 @@ export default async function RoomLayout({
children: ReactNode;
params: { room: string };
}) {
const room = await getRoom(params.room);
const [room, chat] = await Promise.all([
getRoom(params.room),
getChat(params.room),
]);

const aiModel = await getAiModel(chat?.aiModelId ?? '');

if (!room) {
redirect('/');
}

return (
<div className="flex h-full w-full flex-col">
<RoomHeader id={room.id} name={room.name} />
<RoomHeader id={room.id} name={room.name} llmModel={aiModel} />
<div className="h-[calc(100%-41px)] w-full">{children}</div>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions packages/web-ui/app/rooms/[room]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const getChat = async (
console.log(e);
}
};

const getOwner = async (
sessionId: string,
clerkJwtToken: string,
Expand Down
29 changes: 13 additions & 16 deletions packages/web-ui/app/rooms/[room]/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const getOwner = async (
sessionId: string,
clerkJwtToken: string,
ownerId: string
) => {
): Promise<UserResponseDto | undefined> => {
try {
const res = await apiClient({
url: Endpoints.users.getUser(ownerId),
Expand All @@ -74,7 +74,10 @@ const getOwner = async (
}
};

const getAllUsers = async (sessionId: string, clerkJwtToken: string) => {
const getAllUsers = async (
sessionId: string,
clerkJwtToken: string
): Promise<UserResponseDto[] | undefined> => {
try {
const res = await apiClient({
url: Endpoints.users.getUsers(),
Expand All @@ -92,7 +95,7 @@ const getRoomMembers = async (
sessionId: string,
clerkJwtToken: string,
members: string[]
) => {
): Promise<UserResponseDto[] | undefined> => {
try {
const res = await apiClient({
url: Endpoints.users.getUsers(members),
Expand Down Expand Up @@ -146,13 +149,7 @@ export default async function Settings({
params.room
);

const [members, allUsers, owner] = await Promise.all<
[
Promise<UserResponseDto[]>,
Promise<UserResponseDto[]>,
Promise<UserResponseDto>
]
>([
const [members = [], allUsers = [], owner] = await Promise.all([
getRoomMembers(sessionId!, clerkJwtToken!.value, room.members),
getAllUsers(sessionId!, clerkJwtToken!.value),
getOwner(sessionId!, clerkJwtToken!.value, room.ownerId),
Expand All @@ -164,7 +161,7 @@ export default async function Settings({

const membersSearchList = getUserList(members);

const isOwner = owner.id === userId;
const isOwner = owner?.id === userId;

return (
<div className="h-full">
Expand All @@ -180,22 +177,22 @@ export default async function Settings({
<p className="font-bold">Room owner</p>
<div className="flex gap-4">
<Avatar className="h-16 w-16">
<AvatarImage src={owner.profileImageUrl} alt="Profile Image" />
<AvatarImage src={owner?.profileImageUrl} alt="Profile Image" />
</Avatar>
<div className="flex flex-col text-gray-500">
<p>{`Name: ${
owner.firstName && owner.lastName
owner?.firstName && owner.lastName
? `${owner.firstName} ${owner.lastName}`
: ' - '
}`}</p>
<p>
{`Email: ${
owner.emailAddresses.find(
owner?.emailAddresses.find(
(email) => owner.primaryEmailAddressId === email.id
)?.emailAddress ?? ' - '
}`}
</p>
<p>{`Username: ${owner.username}`}</p>
<p>{`Username: ${owner?.username}`}</p>
</div>
</div>
</div>
Expand All @@ -210,7 +207,7 @@ export default async function Settings({
<UserSearchItems
data={userSearchList}
roomId={room.id}
roomOwnerRoles={owner.roles}
roomOwnerRoles={owner?.roles ?? []}
isPrivateRoom={room.isPrivate}
/>
</SearchList>
Expand Down
10 changes: 8 additions & 2 deletions packages/web-ui/components/room-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import React, { useEffect } from 'react';
import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { AiModelResponseDto } from '@/contract/ai/ai-model.response.dto.d';
import { ArrowLeft, Command, Settings } from 'lucide-react';

import { useBrowserInfo } from '@/hooks/use-browser-info';
Expand All @@ -15,9 +16,10 @@ import {
interface RoomHeaderProps {
id: string;
name: string;
llmModel: AiModelResponseDto;
}

export function RoomHeader({ id, name }: RoomHeaderProps) {
export function RoomHeader({ id, name, llmModel }: RoomHeaderProps) {
const router = useRouter();
const pathname = usePathname();
const { isMacUser } = useBrowserInfo();
Expand All @@ -36,6 +38,7 @@ export function RoomHeader({ id, name }: RoomHeaderProps) {
return () => document.removeEventListener('keydown', down);
}
}, [isSettingsPage]);

return (
<div className="flex min-h-[41px] w-full items-center justify-between border-b px-4">
{isSettingsPage ? (
Expand All @@ -47,7 +50,10 @@ export function RoomHeader({ id, name }: RoomHeaderProps) {
{name} | settings
</Link>
) : (
<p className="text-lg font-semibold tracking-tight">{name}</p>
<>
<p className="text-lg font-semibold tracking-tight">{name}</p>
<p className="text-sm text-gray-500">{`${llmModel.chatLlmName} - ${llmModel.alias}`}</p>
</>
)}
{!isSettingsPage && (
<HoverCard>
Expand Down

0 comments on commit 20b0adb

Please sign in to comment.