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
5 changes: 4 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,24 @@
"@types/fs-extra": "^11.0.4",
"@types/normalize-path": "^3.0.2",
"@types/toposort": "^2.0.7",
"toposort": "^2.0.2",
"axios": "^1.7.7",
"bcrypt": "^5.1.1",
"class-validator": "^0.14.1",
"dotenv": "^16.4.7",
"fastembed": "^1.14.1",
"fs-extra": "^11.2.0",
"graphql": "^16.9.0",
"graphql-subscriptions": "^2.0.0",
"graphql-ws": "^5.16.0",
"lodash": "^4.17.21",
"markdown-to-txt": "^2.0.1",
"normalize-path": "^3.0.0",
"openai": "^4.77.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
"subscriptions-transport-ws": "^0.11.0",
"toposort": "^2.0.2",
"typeorm": "^0.3.20",
"uuid": "^10.0.0"
},
Expand Down
3 changes: 2 additions & 1 deletion backend/src/chat/chat.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export class Chat extends SystemBaseModel {
@Column({ nullable: true })
title: string;

@Field({ nullable: true })
// 修改这里
@Field(() => [Message], { nullable: true })
@Column('simple-json', { nullable: true, default: '[]' })
messages: Message[];

Expand Down
9 changes: 2 additions & 7 deletions backend/src/chat/chat.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,9 @@ import { ChatGuard } from '../guard/chat.guard';
import { AuthModule } from '../auth/auth.module';
import { UserService } from 'src/user/user.service';
import { PubSub } from 'graphql-subscriptions';
import { ModelProvider } from 'src/common/model-provider';

@Module({
imports: [
HttpModule,
TypeOrmModule.forFeature([Chat, User, Message]),
AuthModule,
],
imports: [TypeOrmModule.forFeature([Chat, User, Message]), AuthModule],
providers: [
ChatResolver,
ChatProxyService,
Expand All @@ -31,6 +26,6 @@ import { ModelProvider } from 'src/common/model-provider';
useValue: new PubSub(),
},
],
exports: [ChatService, ChatGuard, ModelProvider],
exports: [ChatService, ChatGuard],
})
export class ChatModule {}
5 changes: 2 additions & 3 deletions backend/src/chat/chat.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import {
UpdateChatTitleInput,
} from './dto/chat.input';
import { GetUserIdFromToken } from 'src/decorator/get-auth-token.decorator';
import { Inject, Logger, UseGuards } from '@nestjs/common';
import { ChatGuard, MessageGuard } from 'src/guard/chat.guard';
import { Inject, Logger } from '@nestjs/common';
import { JWTAuth } from 'src/decorator/jwt-auth.decorator';
import { PubSubEngine } from 'graphql-subscriptions';
@Resolver('Chat')
Expand Down Expand Up @@ -76,7 +75,7 @@ export class ChatResolver {
await this.chatService.saveMessage(
input.chatId,
accumulatedContent,
MessageRole.Model,
MessageRole.Assistant,
);

return true;
Expand Down
15 changes: 10 additions & 5 deletions backend/src/chat/chat.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ import { ModelProvider } from 'src/common/model-provider';
@Injectable()
export class ChatProxyService {
private readonly logger = new Logger('ChatProxyService');
private readonly models: ModelProvider = ModelProvider.getInstance();

constructor(
private httpService: HttpService,
private readonly models: ModelProvider,
) {}
constructor() {}

streamChat(
input: ChatInput,
): CustomAsyncIterableIterator<ChatCompletionChunk> {
return this.models.chat(input.message, input.model, input.chatId);
return this.models.chat(
{
messages: [{ role: MessageRole.User, content: input.message }],
model: input.model,
},
input.model,
input.chatId,
);
}

async fetchModelTags(): Promise<any> {
Expand Down
1 change: 1 addition & 0 deletions backend/src/config/config-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as _ from 'lodash';
import { getConfigPath } from './common-path';
import { ConfigType } from 'src/downloader/universal-utils';
import { Logger } from '@nestjs/common';
import * as path from 'path';

export interface ModelConfig {
model: string;
Expand Down
5 changes: 1 addition & 4 deletions backend/src/embedding/openai-embbeding-provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Logger } from '@nestjs/common';
import { EmbeddingModel } from 'fastembed';
import openai, { OpenAI } from 'openai';
import { EmbeddingDownloader } from 'src/downloader/embedding-downloader';
import { OpenAI } from 'openai';

export class OpenAIEmbProvider {
private logger = new Logger(OpenAIEmbProvider.name);
Expand All @@ -26,7 +24,6 @@ export class OpenAIEmbProvider {
input: message,
encoding_format: 'float',
});
console.log(embedding.data[0].embedding);
return embedding.data[0].embedding;
}

Expand Down
94 changes: 47 additions & 47 deletions backend/src/guard/chat.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,53 +54,53 @@ export class ChatGuard implements CanActivate {
}
}

@Injectable()
export class MessageGuard implements CanActivate {
constructor(
private readonly chatService: ChatService, // Inject ChatService to fetch chat details
private readonly jwtService: JwtService, // JWT Service to verify tokens
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const gqlContext = GqlExecutionContext.create(context);
const request = gqlContext.getContext().req;

// Extract the authorization header
const authHeader = request.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new UnauthorizedException('Authorization token is missing');
}

// Decode the token to get user information
const token = authHeader.split(' ')[1];
let user: any;
try {
user = this.jwtService.verify(token);
} catch (error) {
throw new UnauthorizedException('Invalid token');
}

// Extract chatId from the request arguments
const args = gqlContext.getArgs();
const { messageId } = args;

// Fetch the message and its associated chat
const message = await this.chatService.getMessageById(messageId);
if (!message) {
throw new UnauthorizedException('Message not found');
}

// Ensure that the user is part of the chat the message belongs to
const chat = message.chat;
if (chat.user.id !== user.userId) {
throw new UnauthorizedException(
'User is not authorized to access this message',
);
}

return true;
}
}
// @Injectable()
// export class MessageGuard implements CanActivate {
// constructor(
// private readonly chatService: ChatService, // Inject ChatService to fetch chat details
// private readonly jwtService: JwtService, // JWT Service to verify tokens
// ) {}

// async canActivate(context: ExecutionContext): Promise<boolean> {
// const gqlContext = GqlExecutionContext.create(context);
// const request = gqlContext.getContext().req;

// // Extract the authorization header
// const authHeader = request.headers.authorization;
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
// throw new UnauthorizedException('Authorization token is missing');
// }

// // Decode the token to get user information
// const token = authHeader.split(' ')[1];
// let user: any;
// try {
// user = this.jwtService.verify(token);
// } catch (error) {
// throw new UnauthorizedException('Invalid token');
// }

// // Extract chatId from the request arguments
// const args = gqlContext.getArgs();
// const { messageId } = args;

// // Fetch the message and its associated chat
// const message = await this.chatService.getMessageById(messageId);
// if (!message) {
// throw new UnauthorizedException('Message not found');
// }

// // Ensure that the user is part of the chat the message belongs to
// const chat = message.chat;
// if (chat.user.id !== user.userId) {
// throw new UnauthorizedException(
// 'User is not authorized to access this message',
// );
// }

// return true;
// }
// }

@Injectable()
export class ChatSubscriptionGuard implements CanActivate {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { downloadAll } from './downloader/universal-utils';
import * as dotenv from 'dotenv';

async function bootstrap() {
dotenv.config(); // 加载 .env 文件中的环境变量
dotenv.config();
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: '*',
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/graphql/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ type Query {
getChatDetails(chatId: String!): Chat
getChatHistory(chatId: String!): [Message!]!
getHello: String!
getMessageDetail(messageId: String!): Message
getProjectDetails(projectId: String!): Project!
getUserChats: [Chat!]
getUserProjects: [Project!]!
Expand All @@ -138,7 +137,8 @@ input RegisterUserInput {
}

enum Role {
Model
Assistant
System
User
Comment on lines +140 to 142
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Update GraphQL schema and test file for Role/MessageRole consistency

The Role enum in the GraphQL schema needs to be updated to match the backend's MessageRole enum. Found inconsistencies in:

  • frontend/src/graphql/schema.gql: Role type should be 'Assistant' | 'User' | 'System' to match backend
  • backend/src/chat/__tests__/chat-isolation.spec.ts: Uses outdated MessageRole.Model, should be MessageRole.Assistant
🔗 Analysis chain

Verify Role enum usage after Model → Assistant change

The Role enum has been updated from Model to Assistant. Please verify all usages of the old Role.Model have been updated accordingly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to Role.Model
rg "Role\.Model|role:\s*['\"]Model['\"]" 

# Search for places where Role enum is used
rg "Role\." -A 2

Length of output: 1612


Script:

#!/bin/bash
# Search for MessageRole definition
ast-grep --pattern 'enum MessageRole'

# Search for files containing both Role and MessageRole
rg -l "MessageRole.*Role|Role.*MessageRole"

# Search for Role enum definition in TypeScript files
ast-grep --pattern 'enum Role'

Length of output: 118


Script:

#!/bin/bash
# Search for imports or type definitions of MessageRole and Role
rg "import.*MessageRole|import.*Role|type.*Role|interface.*Role"

# Search for enum values we know exist
rg "(User|Assistant|System|Model).*=.*['\"]" -A 2

# Search for files containing MessageRole
fd -e ts -e tsx -e js -e jsx --exec grep -l "MessageRole"

Length of output: 4003

}

Expand Down
Loading
Loading