Skip to content

Commit 5c8e06d

Browse files
authored
Merge pull request #17 from import-ai/feature/index
Feature/index
2 parents 5727508 + 830b992 commit 5c8e06d

12 files changed

+258
-227
lines changed

src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { UserRoleModule } from 'src/user-role/user-role.module';
1111
import { NamespacesModule } from 'src/namespaces/namespaces.module';
1212
import { ResourcesModule } from 'src/resources/resources.module';
1313
import { TasksModule } from 'src/tasks/tasks.module';
14+
import { WizardModule } from 'src/wizard/wizard.module';
1415

1516
@Module({
1617
controllers: [AppController],
@@ -23,6 +24,7 @@ import { TasksModule } from 'src/tasks/tasks.module';
2324
NamespacesModule,
2425
ResourcesModule,
2526
TasksModule,
27+
WizardModule,
2628
ConfigModule.forRoot({
2729
cache: true,
2830
isGlobal: true,

src/resources/resources.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { TypeOrmModule } from '@nestjs/typeorm';
33
import { Resource } from 'src/resources/resources.entity';
44
import { ResourcesService } from 'src/resources/resources.service';
55
import { ResourcesController } from 'src/resources/resources.controller';
6+
import { Task } from 'src/tasks/tasks.entity';
67

78
@Module({
89
exports: [ResourcesService],
910
providers: [ResourcesService],
1011
controllers: [ResourcesController],
11-
imports: [TypeOrmModule.forFeature([Resource])],
12+
imports: [
13+
TypeOrmModule.forFeature([Resource]),
14+
TypeOrmModule.forFeature([Task]),
15+
],
1216
})
1317
export class ResourcesModule {}

src/resources/resources.service.ts

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { InjectRepository } from '@nestjs/typeorm';
2-
import { In, FindOptionsWhere, Repository } from 'typeorm';
2+
import { FindOptionsWhere, In, Repository } from 'typeorm';
33
import { Resource } from 'src/resources/resources.entity';
44
import { CreateResourceDto } from 'src/resources/dto/create-resource.dto';
55
import { UpdateResourceDto } from 'src/resources/dto/update-resource.dto';
66
import {
7+
BadRequestException,
78
Injectable,
89
NotFoundException,
9-
BadRequestException,
1010
} from '@nestjs/common';
11+
import { Task } from 'src/tasks/tasks.entity';
1112

1213
export interface IQuery {
1314
namespace: string;
@@ -22,6 +23,8 @@ export class ResourcesService {
2223
constructor(
2324
@InjectRepository(Resource)
2425
private readonly resourceRepository: Repository<Resource>,
26+
@InjectRepository(Task)
27+
private readonly taskRepository: Repository<Task>,
2528
) {}
2629

2730
async create(userId: string, data: CreateResourceDto) {
@@ -54,7 +57,7 @@ export class ResourcesService {
5457
...data,
5558
user: { id: userId },
5659
namespace: { id: data.namespace },
57-
parentId: parentResource ? parentResource.id : 0,
60+
parentId: parentResource ? parentResource.id : '',
5861
});
5962

6063
if (parentResource) {
@@ -63,7 +66,43 @@ export class ResourcesService {
6366
await this.resourceRepository.save(parentResourceRepo);
6467
}
6568

66-
return await this.resourceRepository.save(resource);
69+
const savedResource = await this.resourceRepository.save(resource);
70+
await this.index(savedResource);
71+
return savedResource;
72+
}
73+
74+
async index(resource: Resource) {
75+
if (resource.resourceType === 'folder' || !resource.content) {
76+
return;
77+
}
78+
const task = this.taskRepository.create({
79+
function: 'create_or_update_index',
80+
input: {
81+
title: resource.name,
82+
content: resource.content,
83+
meta_info: {
84+
user_id: resource.user.id,
85+
space_type: resource.spaceType,
86+
resource_id: resource.id,
87+
parent_id: resource.parentId,
88+
},
89+
},
90+
namespace: resource.namespace,
91+
user: resource.user,
92+
});
93+
return await this.taskRepository.save(task);
94+
}
95+
96+
async deleteIndex(resource: Resource) {
97+
const task = this.taskRepository.create({
98+
function: 'delete_index',
99+
input: {
100+
resource_id: resource.id,
101+
},
102+
namespace: resource.namespace,
103+
user: resource.user,
104+
});
105+
return await this.taskRepository.save(task);
67106
}
68107

69108
async getRoot(namespace: string, spaceType: string, userId: string) {
@@ -133,9 +172,10 @@ export class ResourcesService {
133172
}
134173

135174
async update(id: string, data: UpdateResourceDto) {
175+
console.debug({ id, data });
136176
const resource = await this.resourceRepository.findOne({
137177
where: { id, namespace: { id: data.namespace } },
138-
relations: ['namespace'],
178+
relations: ['namespace', 'user'],
139179
});
140180

141181
if (!resource) {
@@ -147,7 +187,9 @@ export class ResourcesService {
147187
...data,
148188
namespace: { id: data.namespace },
149189
});
150-
return await this.resourceRepository.save(newResource);
190+
const savedNewResource = await this.resourceRepository.save(newResource);
191+
await this.index(savedNewResource);
192+
return savedNewResource;
151193
}
152194

153195
async deleteChildren(id: string) {
@@ -166,7 +208,7 @@ export class ResourcesService {
166208
}
167209

168210
async delete(id: string) {
169-
// 更新父级 childCount
211+
// Update parent's childCount
170212
const resource = await this.get(id);
171213
const parent = await this.resourceRepository.findOne({
172214
where: {
@@ -178,9 +220,9 @@ export class ResourcesService {
178220
const parentResource = this.resourceRepository.create(parent);
179221
await this.resourceRepository.save(parentResource);
180222
}
181-
// 删除自身
182-
await this.resourceRepository.softDelete(id);
183-
// 递归删除子级
184-
await this.deleteChildren(id);
223+
await this.resourceRepository.softDelete(id); // Delete itself
224+
await this.deleteChildren(id); // Delete its children
225+
226+
await this.deleteIndex(resource);
185227
}
186228
}

src/tasks/tasks.controller.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import {
88
Param,
99
Post,
1010
Query,
11-
Req,
1211
} from '@nestjs/common';
13-
import { CollectRequestDto } from 'src/tasks/dto/collect-request.dto';
1412

1513
@Controller('api/v1/tasks')
1614
export class TasksController {
@@ -21,11 +19,6 @@ export class TasksController {
2119
return await this.tasksService.create(data);
2220
}
2321

24-
@Post('collect')
25-
async collect(@Req() req, @Body() data: CollectRequestDto) {
26-
return await this.tasksService.collect(req.user, data);
27-
}
28-
2922
@Get()
3023
async listTasks(
3124
@Query('namespace') namespace: string,

src/tasks/tasks.module.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@ import { Task } from 'src/tasks/tasks.entity';
33
import { TypeOrmModule } from '@nestjs/typeorm';
44
import { TasksService } from 'src/tasks/tasks.service';
55
import { TasksController } from 'src/tasks/tasks.controller';
6-
import { InternalTasksController } from 'src/tasks/internal.tasks.controller';
76
import { NamespacesModule } from 'src/namespaces/namespaces.module';
8-
import { ResourcesModule } from 'src/resources/resources.module';
97

108
@Module({
119
providers: [TasksService],
12-
imports: [
13-
NamespacesModule,
14-
TypeOrmModule.forFeature([Task]),
15-
ResourcesModule,
16-
],
17-
controllers: [TasksController, InternalTasksController],
10+
imports: [NamespacesModule, TypeOrmModule.forFeature([Task])],
11+
controllers: [TasksController],
1812
})
1913
export class TasksModule {}

src/tasks/tasks.service.ts

Lines changed: 1 addition & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,22 @@
11
import { Repository } from 'typeorm';
22
import { Task } from 'src/tasks/tasks.entity';
33
import { InjectRepository } from '@nestjs/typeorm';
4-
import {
5-
BadRequestException,
6-
Injectable,
7-
NotFoundException,
8-
} from '@nestjs/common';
4+
import { Injectable, NotFoundException } from '@nestjs/common';
95
import { NamespacesService } from 'src/namespaces/namespaces.service';
10-
import { ResourcesService } from 'src/resources/resources.service';
11-
import { CreateResourceDto } from 'src/resources/dto/create-resource.dto';
12-
import { CollectRequestDto } from 'src/tasks/dto/collect-request.dto';
13-
import { User } from 'src/user/user.entity';
14-
import { TaskCallbackDto } from './dto/task-callback.dto';
156

167
@Injectable()
178
export class TasksService {
189
constructor(
1910
@InjectRepository(Task)
2011
private taskRepository: Repository<Task>,
2112
private readonly namespacesService: NamespacesService,
22-
private readonly resourcesService: ResourcesService, // inject ResourcesService
2313
) {}
2414

2515
async create(data: Partial<Task>) {
2616
const newTask = this.taskRepository.create(data);
2717
return await this.taskRepository.save(newTask);
2818
}
2919

30-
async collect(user: User, data: CollectRequestDto) {
31-
const { html, url, title, namespace, spaceType } = data;
32-
if (!namespace || !spaceType || !url || !html) {
33-
throw new BadRequestException('Missing required fields');
34-
}
35-
const ns = await this.namespacesService.findByName(namespace);
36-
if (!ns) {
37-
throw new NotFoundException('Namespace not found');
38-
}
39-
40-
// Actually create a resource using ResourcesService
41-
const resourceDto: CreateResourceDto = {
42-
name: title || url,
43-
namespace: ns.id,
44-
resourceType: 'link',
45-
spaceType,
46-
parentId: '',
47-
tags: [],
48-
content: 'Processing...',
49-
attrs: { url },
50-
};
51-
// You may need to provide a userId, here assumed as 0 or fetch from context if available
52-
const resource = await this.resourcesService.create(user.id, resourceDto);
53-
54-
// Add resourceId to payload
55-
const payload = { spaceType, namespace, resourceId: resource.id };
56-
57-
// Create a new task with function "collect"
58-
const task = this.taskRepository.create({
59-
function: 'collect',
60-
input: { html, url, title },
61-
namespace: ns,
62-
payload,
63-
user,
64-
});
65-
await this.taskRepository.save(task);
66-
return { taskId: task.id, resourceId: resource.id };
67-
}
68-
69-
async taskDoneCallback(data: TaskCallbackDto) {
70-
const task = await this.taskRepository.findOne({
71-
where: { id: data.id },
72-
relations: ['namespace'],
73-
});
74-
if (!task) {
75-
throw new NotFoundException(`Task ${data.id} not found`);
76-
}
77-
78-
const endedAt: Date = new Date(data.endedAt);
79-
80-
task.endedAt = endedAt;
81-
task.exception = data.exception;
82-
task.output = data.output;
83-
await this.taskRepository.save(task);
84-
85-
// Calculate cost and wait (if timestamps are present)
86-
const cost: number = task.endedAt.getTime() - task.startedAt.getTime();
87-
const wait: number = task.startedAt.getTime() - task.createdAt.getTime();
88-
console.debug(`Task ${task.id} cost: ${cost}ms, wait: ${wait}ms`);
89-
90-
// Delegate postprocess logic to a separate method
91-
const postprocessResult = await this.postprocess(task);
92-
93-
return { taskId: task.id, function: task.function, ...postprocessResult };
94-
}
95-
96-
async postprocess(task: Task): Promise<Record<string, any>> {
97-
// Dispatch postprocess logic based on task.function
98-
if (task.function === 'collect') {
99-
return await this.postprocessCollect(task);
100-
}
101-
// Add more function types here as needed
102-
return {};
103-
}
104-
105-
private async postprocessCollect(task: Task): Promise<Record<string, any>> {
106-
if (!task.payload?.resourceId) {
107-
throw new BadRequestException('Invalid task payload');
108-
}
109-
const resourceId = task.payload.resourceId;
110-
if (task.exception) {
111-
// If there was an exception, update resource content with error
112-
await this.resourcesService.update(resourceId, {
113-
namespace: task.namespace.id,
114-
content: task.exception.error,
115-
});
116-
return {};
117-
} else if (task.output) {
118-
// If successful, update resource with output
119-
const { markdown, title, ...attrs } = task.output || {};
120-
await this.resourcesService.update(resourceId, {
121-
namespace: task.namespace.id,
122-
name: title,
123-
content: markdown,
124-
attrs,
125-
});
126-
return { resourceId };
127-
}
128-
return {};
129-
}
130-
13120
async list(namespaceId: string, offset: number, limit: number) {
13221
const namespace = await this.namespacesService.get(namespaceId);
13322

@@ -162,49 +51,4 @@ export class TasksService {
16251
}
16352
await this.taskRepository.softRemove(task);
16453
}
165-
166-
async fetch(): Promise<Task | null> {
167-
const rawQuery = `
168-
WITH running_tasks_sub_query AS (SELECT namespace_id,
169-
COUNT(id) AS running_count
170-
FROM tasks
171-
WHERE started_at IS NOT NULL
172-
AND ended_at IS NULL
173-
AND canceled_at IS NULL
174-
GROUP BY namespace_id),
175-
id_subquery AS (SELECT tasks.id
176-
FROM tasks
177-
LEFT OUTER JOIN running_tasks_sub_query
178-
ON tasks.namespace_id = running_tasks_sub_query.namespace_id
179-
LEFT OUTER JOIN namespaces
180-
ON tasks.namespace_id = namespaces.id
181-
WHERE tasks.started_at IS NULL
182-
AND tasks.canceled_at IS NULL
183-
AND COALESCE(running_tasks_sub_query.running_count, 0) <
184-
COALESCE(namespaces.max_running_tasks, 0)
185-
ORDER BY priority DESC,
186-
tasks.created_at
187-
LIMIT 1
188-
)
189-
SELECT *
190-
FROM tasks
191-
WHERE id IN (SELECT id FROM id_subquery)
192-
FOR UPDATE SKIP LOCKED;
193-
`;
194-
195-
const queryResult = await this.taskRepository.query(rawQuery);
196-
197-
if (queryResult.length > 0) {
198-
const task = this.taskRepository.create({
199-
...(queryResult[0] as Task),
200-
startedAt: new Date(),
201-
user: { id: queryResult[0].user_id },
202-
namespace: { id: queryResult[0].namespace_id },
203-
});
204-
await this.taskRepository.save(task);
205-
return task;
206-
}
207-
208-
return null;
209-
}
21054
}
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)