diff --git a/apps/backend/src/api/routes/posts.controller.ts b/apps/backend/src/api/routes/posts.controller.ts index 1590411a..e02f743e 100644 --- a/apps/backend/src/api/routes/posts.controller.ts +++ b/apps/backend/src/api/routes/posts.controller.ts @@ -7,6 +7,7 @@ import { Post, Put, Query, + Res, } from '@nestjs/common'; import { PostsService } from '@gitroom/nestjs-libraries/database/prisma/posts/posts.service'; import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; @@ -23,6 +24,8 @@ import { ApiTags } from '@nestjs/swagger'; import { MessagesService } from '@gitroom/nestjs-libraries/database/prisma/marketplace/messages.service'; import { GeneratorDto } from '@gitroom/nestjs-libraries/dtos/generator/generator.dto'; import { CreateGeneratedPostsDto } from '@gitroom/nestjs-libraries/dtos/generator/create.generated.posts.dto'; +import { AgentGraphService } from '@gitroom/nestjs-libraries/agent/agent.graph.service'; +import { Response } from 'express'; @ApiTags('Posts') @Controller('/posts') @@ -30,7 +33,8 @@ export class PostsController { constructor( private _postsService: PostsService, private _starsService: StarsService, - private _messagesService: MessagesService + private _messagesService: MessagesService, + private _agentGraphService: AgentGraphService ) {} @Get('/marketplace/:id?') @@ -100,11 +104,20 @@ export class PostsController { @Post('/generator') @CheckPolicies([AuthorizationActions.Create, Sections.POSTS_PER_MONTH]) - generatePosts( + async generatePosts( @GetOrgFromRequest() org: Organization, - @Body() body: GeneratorDto + @Body() body: GeneratorDto, + @Res({ passthrough: false }) res: Response ) { - return this._postsService.generatePosts(org.id, body); + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + for await (const event of this._agentGraphService.start( + org.id, + body, + )) { + res.write(JSON.stringify(event) + '\n'); + } + + res.end(); } @Delete('/:group') diff --git a/apps/backend/src/api/routes/public.controller.ts b/apps/backend/src/api/routes/public.controller.ts index dc4d16fc..44ff199f 100644 --- a/apps/backend/src/api/routes/public.controller.ts +++ b/apps/backend/src/api/routes/public.controller.ts @@ -10,14 +10,29 @@ import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.req import { User } from '@prisma/client'; import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; import { getCookieUrlFromDomain } from '@gitroom/helpers/subdomain/subdomain.management'; +import { AgentGraphService } from '@gitroom/nestjs-libraries/agent/agent.graph.service'; +import { AgentGraphInsertService } from '@gitroom/nestjs-libraries/agent/agent.graph.insert.service'; @ApiTags('Public') @Controller('/public') export class PublicController { constructor( private _agenciesService: AgenciesService, - private _trackService: TrackService + private _trackService: TrackService, + private _agentGraphInsertService: AgentGraphInsertService ) {} + @Post('/agent') + async createAgent(@Body() body: { text: string; apiKey: string }) { + if ( + !body.apiKey || + !process.env.AGENT_API_KEY || + body.apiKey !== process.env.AGENT_API_KEY + ) { + return; + } + return this._agentGraphInsertService.newPost(body.text); + } + @Get('/agencies-list') async getAgencyByUser() { return this._agenciesService.getAllAgencies(); diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index f9cc38ba..3412b76a 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -9,6 +9,7 @@ import { PluginModule } from '@gitroom/plugins/plugin.module'; import { PublicApiModule } from '@gitroom/backend/public-api/public.api.module'; import { ThrottlerBehindProxyGuard } from '@gitroom/nestjs-libraries/throttler/throttler.provider'; import { ThrottlerModule } from '@nestjs/throttler'; +import { AgentModule } from '@gitroom/nestjs-libraries/agent/agent.module'; @Global() @Module({ @@ -18,6 +19,7 @@ import { ThrottlerModule } from '@nestjs/throttler'; ApiModule, PluginModule, PublicApiModule, + AgentModule, ThrottlerModule.forRoot([ { ttl: 3600000, diff --git a/apps/commands/project.json b/apps/commands/project.json index bd2b0ad9..3629dc78 100644 --- a/apps/commands/project.json +++ b/apps/commands/project.json @@ -25,17 +25,7 @@ "executor": "nx:run-commands", "defaultConfiguration": "development", "options": { - "buildTarget": "commands:build", - "inspect": false, "command": "cd dist/apps/commands && node main.js" - }, - "configurations": { - "development": { - "buildTarget": "commands:build:development" - }, - "production": { - "buildTarget": "commands:build:production" - } } }, "lint": { diff --git a/apps/commands/src/command.module.ts b/apps/commands/src/command.module.ts index 9430ef56..44d9d5e5 100644 --- a/apps/commands/src/command.module.ts +++ b/apps/commands/src/command.module.ts @@ -5,11 +5,18 @@ import { DatabaseModule } from '@gitroom/nestjs-libraries/database/prisma/databa import { RefreshTokens } from './tasks/refresh.tokens'; import { BullMqModule } from '@gitroom/nestjs-libraries/bull-mq-transport-new/bull.mq.module'; import { ConfigurationTask } from './tasks/configuration'; +import { AgentRun } from './tasks/agent.run'; +import { AgentModule } from '@gitroom/nestjs-libraries/agent/agent.module'; @Module({ - imports: [ExternalCommandModule, DatabaseModule, BullMqModule], + imports: [ + ExternalCommandModule, + DatabaseModule, + BullMqModule, + AgentModule, + ], controllers: [], - providers: [CheckStars, RefreshTokens, ConfigurationTask], + providers: [CheckStars, RefreshTokens, ConfigurationTask, AgentRun], get exports() { return [...this.imports, ...this.providers]; }, diff --git a/apps/commands/src/tasks/agent.run.ts b/apps/commands/src/tasks/agent.run.ts new file mode 100644 index 00000000..ad8e67c0 --- /dev/null +++ b/apps/commands/src/tasks/agent.run.ts @@ -0,0 +1,15 @@ +import { Command } from 'nestjs-command'; +import { Injectable } from '@nestjs/common'; +import { AgentGraphService } from '@gitroom/nestjs-libraries/agent/agent.graph.service'; + +@Injectable() +export class AgentRun { + constructor(private _agentGraphService: AgentGraphService) {} + @Command({ + command: 'run:agent', + describe: 'Run the agent', + }) + async agentRun() { + console.log(await this._agentGraphService.createGraph('hello', true)); + } +} diff --git a/apps/frontend/src/app/global.scss b/apps/frontend/src/app/global.scss index 885b1e7d..f9e668fa 100644 --- a/apps/frontend/src/app/global.scss +++ b/apps/frontend/src/app/global.scss @@ -394,4 +394,25 @@ div div .set-font-family { transform: translate(-50%, -50%); white-space: nowrap; opacity: 30%; +} + +.loading-shimmer { + position: relative; + color: rgba(255, 255, 255, .5); +} + +.loading-shimmer:before { + content: attr(data-text); + position: absolute; + overflow: hidden; + max-width: 100%; + white-space: nowrap; + color: white; + animation: loading 4s linear 0s infinite; + filter: blur(0.4px); +} +@keyframes loading { + 0% { + max-width: 0; + } } \ No newline at end of file diff --git a/apps/frontend/src/components/launches/add.edit.model.tsx b/apps/frontend/src/components/launches/add.edit.model.tsx index 38c434de..79a0a01a 100644 --- a/apps/frontend/src/components/launches/add.edit.model.tsx +++ b/apps/frontend/src/components/launches/add.edit.model.tsx @@ -66,8 +66,13 @@ export const AddEditModal: FC<{ integrations: Integrations[]; reopenModal: () => void; mutate: () => void; + onlyValues?: Array<{ + content: string; + id?: string; + image?: Array<{ id: string; path: string }>; + }>; }> = (props) => { - const { date, integrations: ints, reopenModal, mutate } = props; + const { date, integrations: ints, reopenModal, mutate, onlyValues } = props; const [customer, setCustomer] = useState(''); // selected integrations to allow edit @@ -104,7 +109,7 @@ export const AddEditModal: FC<{ id?: string; image?: Array<{ id: string; path: string }>; }> - >([{ content: '' }]); + >(onlyValues ? onlyValues : [{ content: '' }]); const fetch = useFetch(); diff --git a/apps/frontend/src/components/launches/editor.tsx b/apps/frontend/src/components/launches/editor.tsx index e2906b01..20c743c2 100644 --- a/apps/frontend/src/components/launches/editor.tsx +++ b/apps/frontend/src/components/launches/editor.tsx @@ -22,7 +22,7 @@ export const Editor = forwardRef< const user = useUser(); useCopilotReadable({ description: 'Content of the post number ' + (props.order + 1), - value: props.content, + value: props.value, }); useCopilotAction({ diff --git a/apps/frontend/src/components/launches/generator/generator.tsx b/apps/frontend/src/components/launches/generator/generator.tsx index e75b32c1..00acb205 100644 --- a/apps/frontend/src/components/launches/generator/generator.tsx +++ b/apps/frontend/src/components/launches/generator/generator.tsx @@ -1,193 +1,30 @@ -import React, { - FC, - useCallback, - useMemo, - useState, -} from 'react'; +import React, { FC, useCallback, useMemo, useState } from 'react'; import { useUser } from '@gitroom/frontend/components/layout/user.context'; import { useRouter } from 'next/navigation'; import { deleteDialog } from '@gitroom/react/helpers/delete.dialog'; -import { - Step, - StepSpace, -} from '@gitroom/frontend/components/onboarding/onboarding'; import { useModals } from '@mantine/modals'; -import { Select } from '@gitroom/react/form/select'; -import { Input } from '@gitroom/react/form/input'; -import dayjs from 'dayjs'; import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'; import { classValidatorResolver } from '@hookform/resolvers/class-validator'; import { GeneratorDto } from '@gitroom/nestjs-libraries/dtos/generator/generator.dto'; import { Button } from '@gitroom/react/form/button'; -import { PostSelector } from '@gitroom/frontend/components/post-url-selector/post.url.selector'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; +import { Textarea } from '@gitroom/react/form/textarea'; +import { Checkbox } from '@gitroom/react/form/checkbox'; import clsx from 'clsx'; +import { + CalendarWeekProvider, + useCalendar, +} from '@gitroom/frontend/components/launches/calendar.context'; +import { AddEditModal } from '@gitroom/frontend/components/launches/add.edit.model'; +import dayjs from 'dayjs'; +import { Select } from '@gitroom/react/form/select'; -const ThirdStep: FC<{ week: number; year: number }> = (props) => { - const { week, year } = props; - - const gotToPosts = useCallback(() => { - window.location.href = `/launches?week=${week}&year=${year}`; - }, [week, year]); - return ( -