Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
// throw new MissingConfigurationError('Missing or invalid PRD content.');
// }

// Generate the prompt dynamically
// const prompt = prompts.generateUxsmdPrompt(projectName, platform);
// // Generate the prompt dynamically
// const prompt = prompts.generateUxsmdrompt(
// projectName,
Expand Down
16 changes: 14 additions & 2 deletions backend/src/chat/chat.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,21 @@ export class Chat extends SystemBaseModel {
@Column({ nullable: true })
title: string;

// 修改这里
@Field(() => [Message], { nullable: true })
@Column('simple-json', { nullable: true, default: '[]' })
@Column('simple-json', {
nullable: true,
default: '[]',
transformer: {
to: (messages: Message[]) => messages,
from: (value: any) => {
return value.map((message: any) => ({
...message,
createdAt: message.createdAt ? new Date(message.createdAt) : null,
updatedAt: message.updatedAt ? new Date(message.updatedAt) : null,
}));
},
},
})
messages: Message[];

@ManyToOne(() => User, (user) => user.chats)
Expand Down
3 changes: 3 additions & 0 deletions backend/src/chat/chat.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ export class ChatResolver {
async getAvailableModelTags(
@GetUserIdFromToken() userId: string,
): Promise<string[]> {
this.logger.log('Fetching model tags for user:', userId);
try {
const response = await this.chatProxyService.fetchModelTags();
this.logger.log('Loaded model tags:', response);
return response;
} catch (error) {
throw new Error('Failed to fetch model tags');
Expand All @@ -92,6 +94,7 @@ export class ChatResolver {
@Query(() => [Chat], { nullable: true })
async getUserChats(@GetUserIdFromToken() userId: string): Promise<Chat[]> {
const user = await this.userService.getUserChats(userId);

return user ? user.chats : [];
}
// To do: message need a update resolver
Expand Down
8 changes: 6 additions & 2 deletions backend/src/common/model-provider/openai-model-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import OpenAI from 'openai';
import { Logger } from '@nestjs/common';
import { Stream } from 'openai/streaming';
import { ChatCompletionChunk as OpenAIChatCompletionChunk } from 'openai/resources/chat';
import { ChatCompletionChunk } from 'src/chat/chat.model';
import { ChatCompletionChunk, StreamStatus } from 'src/chat/chat.model';
import PQueue from 'p-queue-es5';
import { ConfigLoader, ModelConfig } from 'codefox-common';
export class OpenAIModelProvider implements IModelProvider {
Expand Down Expand Up @@ -140,9 +140,13 @@ export class OpenAIModelProvider implements IModelProvider {
try {
const currentIterator = await createStream();
const chunk = await currentIterator.next();
const chunkValue = chunk.value as OpenAIChatCompletionChunk;
return {
done: chunk.done,
value: chunk.value as ChatCompletionChunk,
value: {
...chunkValue,
status: StreamStatus.STREAMING,
} as unknown as ChatCompletionChunk,
};
} catch (error) {
stream = null;
Expand Down
2 changes: 1 addition & 1 deletion backend/src/common/scalar/date.scalar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class DateScalar implements CustomScalar<number, Date> {
}

serialize(value: Date): number {
return value.getTime(); // value sent to the client
return value.getTime();
}

parseLiteral(ast: ValueNode): Date {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/decorator/get-auth-token.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import {
createParamDecorator,
ExecutionContext,
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
Expand All @@ -27,6 +28,7 @@ export const GetUserIdFromToken = createParamDecorator(
const authHeader = request.headers.authorization;

if (!authHeader || !authHeader.startsWith('Bearer ')) {
Logger.error('Authorization token is missing or invalid');
throw new UnauthorizedException(
'Authorization token is missing or invalid',
);
Expand Down
2 changes: 1 addition & 1 deletion backend/src/system-base-model/system-base.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class SystemBaseModel {
createdAt: Date;

@Field()
@UpdateDateColumn()
@UpdateDateColumn({ type: 'datetime' })
updatedAt: Date;

@Field()
Expand Down
63 changes: 0 additions & 63 deletions frontend/src/app/(main)/[id]/page.tsx

This file was deleted.

53 changes: 48 additions & 5 deletions frontend/src/app/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,64 @@
'use client';

import { useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { Message } from '@/components/types';
import { useModels } from '../hooks/useModels';
import ChatContent from '@/components/chat/chat';
import { useChatStream } from '../hooks/useChatStream';
import { GET_CHAT_HISTORY } from '@/graphql/request';
import { useQuery } from '@apollo/client';
import { toast } from 'sonner';
import { useChatList } from '../hooks/useChatList';
import { EventEnum } from '@/components/enum';

export default function Home() {
const urlParams = new URLSearchParams(window.location.search);
const [chatId, setChatId] = useState('');
// Core message states
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const formRef = useRef<HTMLFormElement>(null);

const { selectedModel, setSelectedModel } = useModels();
const { models } = useModels();
const [selectedModel, setSelectedModel] = useState<string>(
models[0] || 'gpt-4o'
);

const { refetchChats } = useChatList();

useEffect(() => {
setChatId(urlParams.get('id') || '');
refetchChats();
console.log(`update ${urlParams.get('id')}`);
}, [urlParams]);

useQuery(GET_CHAT_HISTORY, {
variables: { chatId },
onCompleted: (data) => {
if (data?.getChatHistory) {
setMessages(data.getChatHistory);
}
},
onError: (error) => {
toast.error('Failed to load chat history');
},
});

const updateChatId = () => {
setChatId('');
};

useEffect(() => {
window.addEventListener(EventEnum.NEW_CHAT, updateChatId);

return () => {
window.removeEventListener(EventEnum.NEW_CHAT, updateChatId);
};
}, []);

const { loadingSubmit, handleSubmit, handleInputChange, stop, isStreaming } =
const { loadingSubmit, handleSubmit, handleInputChange, stop } =
useChatStream({
chatId: '',
chatId,
input,
setInput,
setMessages,
Expand All @@ -24,7 +67,7 @@ export default function Home() {

return (
<ChatContent
chatId=""
chatId={chatId}
setSelectedModel={setSelectedModel}
messages={messages}
input={input}
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/app/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export const useAuth = () => {
const { refetch: checkToken } = useQuery<{ checkToken: boolean }>(
CHECK_TOKEN_QUERY,
{
variables: {
input: {
token: '',
},
},
skip: true,
}
);
Expand Down
15 changes: 12 additions & 3 deletions frontend/src/app/hooks/useChatStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMutation, useSubscription } from '@apollo/client';
import { CHAT_STREAM, CREATE_CHAT, TRIGGER_CHAT } from '@/graphql/request';
import { Message } from '@/components/types';
import { toast } from 'sonner';

import { useRouter } from 'next/navigation';
enum StreamStatus {
IDLE = 'IDLE',
STREAMING = 'STREAMING',
Expand Down Expand Up @@ -49,6 +49,12 @@ export function useChatStream({
variables: null,
});

const updateChatId = () => {
setCurrentChatId('');
};

window.addEventListener('newchat', updateChatId);

const [triggerChat] = useMutation(TRIGGER_CHAT, {
onCompleted: () => {
setStreamStatus(StreamStatus.STREAMING);
Expand All @@ -62,9 +68,10 @@ export function useChatStream({
const [createChat] = useMutation(CREATE_CHAT, {
onCompleted: async (data) => {
const newChatId = data.createChat.id;
window.history.replaceState({}, '', `/${newChatId}`);
setCurrentChatId(newChatId);
await startChatStream(newChatId, input);
window.history.pushState({}, '', `/?id=${newChatId}`);
console.log(`new chat: ${newChatId}`);
},
onError: () => {
toast.error('Failed to create chat');
Expand Down Expand Up @@ -120,6 +127,7 @@ export function useChatStream({
}
},
onError: (error) => {
console.log(error);
toast.error('Connection error. Please try again.');
setStreamStatus(StreamStatus.IDLE);
finishChatResponse();
Expand All @@ -133,7 +141,9 @@ export function useChatStream({
message,
model: selectedModel,
};
console.log(input);

setInput('');
setStreamStatus(StreamStatus.STREAMING);
setSubscription({
enabled: true,
Expand All @@ -153,7 +163,6 @@ export function useChatStream({
e.preventDefault();

const content = input;
setInput('');

if (!content.trim() || loadingSubmit) return;

Expand Down
24 changes: 10 additions & 14 deletions frontend/src/app/hooks/useModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { gql, useQuery } from '@apollo/client';
import { toast } from 'sonner';
import { useState, useEffect } from 'react';
import { LocalStore } from '@/lib/storage';
import { GET_MODEL_TAGS } from '@/graphql/request';

interface ModelsCache {
models: string[];
Expand Down Expand Up @@ -48,23 +49,18 @@ export const useModels = () => {

const { data, loading, error } = useQuery<{
getAvailableModelTags: string[];
}>(
gql`
query {
getAvailableModelTags
}>(GET_MODEL_TAGS, {
skip: !shouldUpdateCache(),
onCompleted: (data) => {
console.log(data);
if (data?.getAvailableModelTags) {
updateCache(data.getAvailableModelTags);
}
`,
{
skip: !shouldUpdateCache(),
onCompleted: (data) => {
if (data?.getAvailableModelTags) {
updateCache(data.getAvailableModelTags);
}
},
}
);
},
});

if (error) {
console.log(error);
toast.error('Failed to load models');
}

Expand Down
3 changes: 0 additions & 3 deletions frontend/src/app/page.tsx

This file was deleted.

Loading
Loading