Skip to content

Commit

Permalink
feat: ✨ (api) 最低機能を実装
Browse files Browse the repository at this point in the history
  • Loading branch information
dino3616 committed Jan 18, 2024
1 parent 7115bfa commit e223eb5
Show file tree
Hide file tree
Showing 76 changed files with 3,427 additions and 92 deletions.
34 changes: 0 additions & 34 deletions apps/api/drizzle.config.ts

This file was deleted.

15 changes: 13 additions & 2 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
"test": "cross-env NODE_ENV=test jest --silent=false --verbose false --passWithNoTests",
"db:generate": "prisma generate --schema ./src/infra/prisma/schema.prisma",
"db:push:dev": "dotenv -e .env.development -- cross-env NODE_ENV=development prisma db push --schema ./src/infra/prisma/schema.prisma",
"db:migrate": "dotenv -e .env.production -- cross-env NODE_ENV=production prisma migrate dev --schema ./src/infra/prisma/schema.prisma --name migration",
"db:migrate:dev": "dotenv -e .env.development -- cross-env NODE_ENV=development prisma migrate dev --schema ./src/infra/prisma/schema.prisma --name migration",
"db:migrate:sync": "supabase db diff -f migration",
"db:deploy:dev": "dotenv -e .env.development -- cross-env NODE_ENV=development prisma migrate deploy --schema ./src/infra/prisma/schema.prisma && pnpm db:migrate:sync",
"db:studio": "dotenv -e .env.development -- cross-env NODE_ENV=development prisma studio --schema ./src/infra/prisma/schema.prisma",
"apollo:rover": "rover graph publish lockerai@current --schema ./schema.gql"
},
"dependencies": {
"@apollo/server": "4.10.0",
"@huggingface/inference": "2.6.4",
"@langchain/community": "0.0.17",
"@langchain/core": "0.1.15",
"@langchain/openai": "0.0.12",
"@nestjs/apollo": "12.0.11",
"@nestjs/cli": "10.3.0",
"@nestjs/common": "10.3.0",
Expand All @@ -39,13 +43,18 @@
"@nestjs/platform-express": "10.3.0",
"@nestjs/testing": "10.3.0",
"@prisma/client": "5.8.0",
"@supabase/supabase-js": "2.39.3",
"class-transformer": "0.5.1",
"class-validator": "0.14.0",
"dataloader": "2.2.2",
"dotenv": "16.3.1",
"graphql-subscriptions": "2.0.0",
"graphql-upload": "15.0.2",
"graphql-validation-complexity": "0.4.2",
"ts-pattern": "5.0.6"
"langchain": "0.1.3",
"ts-pattern": "5.0.6",
"uuid": "9.0.1",
"zod": "3.22.4"
},
"devDependencies": {
"@apollo/rover": "0.22.0",
Expand All @@ -54,7 +63,9 @@
"@lockerai/tsconfig": "workspace:*",
"@lockerai/type": "workspace:*",
"@nestjs/schematics": "10.1.0",
"@types/graphql-upload": "15.0.2",
"@types/graphql-validation-complexity": "0.4.4",
"@types/uuid": "9.0.7",
"eslint-config-lockerai-node": "workspace:*",
"prisma": "5.8.0"
}
Expand Down
24 changes: 21 additions & 3 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { Module } from '@nestjs/common';
import { type MiddlewareConsumer, Module } from '@nestjs/common';
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js';
import { CacheModule } from '#api/common/service/cache/cache.module';
import { EnvModule } from '#api/common/service/env/env.module';
import { PubSubModule } from '#api/common/service/pubsub/pubsub.module';
import { GraphQLConfigModule } from '#api/config/graphql/graphql-config.module';
import { IdentificationNnModule } from '#api/infra/identification-nn/identification-nn.module';
import { LangchainModule } from '#api/infra/langchain/langchain.module';
import { PrismaModule } from '#api/infra/prisma/prisma.module';
import { SupabaseModule } from '#api/infra/supabase/supabase.module';
import { Modules } from '#api/module';

@Module({
imports: [EnvModule, GraphQLConfigModule, PrismaModule, CacheModule, PubSubModule, ...Modules],
imports: [
EnvModule,
GraphQLConfigModule,
PrismaModule,
LangchainModule,
SupabaseModule,
IdentificationNnModule,
CacheModule,
PubSubModule,
...Modules,
],
})
export class AppModule {}
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(graphqlUploadExpress()).forRoutes('graphql');
}
}
5 changes: 5 additions & 0 deletions apps/api/src/common/constant/injection-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@
export enum InjectionToken {
USER_REPOSITORY = 'USER_REPOSITORY',
USER_USE_CASE = 'USER_USE_CASE',
LOST_ITEM_REPOSITORY = 'LOST_ITEM_REPOSITORY',
LOST_ITEM_USE_CASE = 'LOST_ITEM_USE_CASE',
DRAWER_REPOSITORY = 'DRAWER_REPOSITORY',
DRAWER_USE_CASE = 'DRAWER_USE_CASE',
LOCKER_REPOSITORY = 'LOCKER_REPOSITORY',
}
33 changes: 33 additions & 0 deletions apps/api/src/common/guard/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { type CanActivate, type ExecutionContext, Injectable } from '@nestjs/common';
import { EnvService } from '#api/common/service/env/env.service';
import { SupabaseService } from '#api/infra/supabase/supabase.service';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private readonly supabaseService: SupabaseService,
private readonly envService: EnvService,
) {}

async canActivate(context: ExecutionContext) {
if (this.envService.NodeEnv === 'development') {
return true;
}
let accessToken: string | undefined;
context.getArgs().forEach((arg) => {
if (arg && arg.req && arg.req.headers) {
if (arg.req.headers.authorization) {
[, accessToken] = arg.req.headers.authorization.split(' ');
}
}
});
if (!accessToken) {
return false;
}
const user = await this.supabaseService.getUserByAccessToken(accessToken);
if (!user) {
throw new Error(`Invalid access token: ${accessToken}`);
}
return !!user;
}
}
60 changes: 45 additions & 15 deletions apps/api/src/common/service/env/env.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ export class EnvService {
this.logger.log(`NODE_ENV: ${this.NodeEnv}`);
}

get NodeEnv(): 'development' | 'production' | 'test' {
const nodeEnv = this.configService.get<'development' | 'production' | 'test'>('NODE_ENV', 'development');
get ApolloStudioConfig(): ApolloConfigInput {
const apolloConfigInput: ApolloConfigInput = {
key: this.configService.getOrThrow('APOLLO_KEY'),
graphRef: this.configService.getOrThrow('APOLLO_GRAPH_REF'),
};

return nodeEnv;
return apolloConfigInput;
}

get Port(): number {
const port = this.configService.get<number>('PORT', 4000);
get DatabaseSslCert(): string {
const databaseSslCert = this.configService.getOrThrow<string>('DATABASE_SSL_CERT');

return port;
return databaseSslCert;
}

get DatabaseUrl(): string {
Expand All @@ -29,18 +32,45 @@ export class EnvService {
return databaseUrl;
}

get DatabaseSslCert(): string {
const databaseSslCert = this.configService.getOrThrow<string>('DATABASE_SSL_CERT');
get HuggingfacehubApiToken(): string {
const huggingfacehubApiToken = this.configService.getOrThrow<string>('HUGGINGFACEHUB_API_TOKEN');

return databaseSslCert;
return huggingfacehubApiToken;
}

get ApolloStudioConfig(): ApolloConfigInput {
const apolloConfigInput: ApolloConfigInput = {
key: this.configService.getOrThrow('APOLLO_KEY'),
graphRef: this.configService.getOrThrow('APOLLO_GRAPH_REF'),
};
get IdentifyNnEndpoint(): string {
const identifyNnEndpoint = this.configService.getOrThrow<string>('IDENTIFY_NN_ENDPOINT');

return apolloConfigInput;
return identifyNnEndpoint;
}

get NodeEnv(): 'development' | 'production' | 'test' {
const nodeEnv = this.configService.get<'development' | 'production' | 'test'>('NODE_ENV', 'development');

return nodeEnv;
}

get OpenaiApiKey(): string {
const openaiApiKey = this.configService.getOrThrow<string>('OPENAI_API_KEY');

return openaiApiKey;
}

get Port(): number {
const port = this.configService.get<number>('PORT', 4000);

return port;
}

get SupabaseServiceRoleKey(): string {
const supabaseServiceRoleKey = this.configService.getOrThrow<string>('SUPABASE_SERVICE_ROLE_KEY');

return supabaseServiceRoleKey;
}

get SupabaseUrl(): string {
const supabaseUrl = this.configService.getOrThrow<string>('SUPABASE_URL');

return supabaseUrl;
}
}
26 changes: 19 additions & 7 deletions apps/api/src/common/service/env/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ import { Transform, plainToClass } from 'class-transformer';
import { IsEnum, IsNumber, IsUrl, validateSync } from 'class-validator';

export class EnvValidator {
APOLLO_GRAPH_REF!: string;

APOLLO_KEY!: string;

DATABASE_SSL_CERT!: string;

@IsUrl({ protocols: ['postgresql'], require_tld: process.env['NODE_ENV'] === 'production' })
DATABASE_URL!: string;

HUGGINGFACEHUB_API_TOKEN!: string;

@IsUrl({ protocols: ['http', 'https'], require_tld: process.env['NODE_ENV'] === 'production' })
IDENTIFY_NN_ENDPOINT!: string;

@IsEnum(['development', 'production', 'test'])
NODE_ENV!: 'development' | 'production' | 'test';

OPENAI_API_KEY!: string;

@Transform(({ value }) => parseInt(value, 10))
@IsNumber()
PORT = 4000;

@IsUrl({ protocols: ['postgresql'], require_tld: process.env['NODE_ENV'] === 'production' })
DATABASE_URL!: string;
SUPABASE_SERVICE_ROLE_KEY!: string;

DATABASE_SSL_CERT!: string;

APOLLO_KEY!: string;

APOLLO_GRAPH_REF!: string;
@IsUrl({ protocols: ['http', 'https'], require_tld: process.env['NODE_ENV'] === 'production' })
SUPABASE_URL!: string;
}

export const validate = (config: Record<string, unknown>) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Global, Module } from '@nestjs/common';
import { IdentificationNnService } from './identification-nn.service';

@Global()
@Module({
providers: [IdentificationNnService],
exports: [IdentificationNnService],
})
export class IdentificationNnModule {}
60 changes: 60 additions & 0 deletions apps/api/src/infra/identification-nn/identification-nn.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { EnvService } from '#api/common/service/env/env.service';

type SimilarItem = {
key: string;
similarity: number;
dateDifference: number;
};

@Injectable()
export class IdentificationNnService {
private readonly url: string;

private readonly logger = new Logger(IdentificationNnService.name);

constructor(@Inject(EnvService) private readonly envService: EnvService) {
this.url = this.envService.IdentifyNnEndpoint;

this.logger.debug(`${IdentificationNnService.name} constructed`);
}

async identify(similarItems: SimilarItem[]): Promise<string | null> {
type Request = {
similarity: number;
date_difference: number;
};

type Response = {
// NOTE: The first element of the tuple represents the probability of a match and the second element represents the probability of a mismatch.
data: [number, number];
error: string;
};

const identities = await Promise.all(
similarItems.map(async (similarItem): Promise<[string, [number, number]]> => {
const response = await fetch(this.url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
similarity: similarItem.similarity,
date_difference: similarItem.dateDifference,
} satisfies Request),
});

const { data: identity, error } = (await response.json()) as Response;
if (error) {
throw new Error(String(error));
}

return [similarItem.key, identity];
}),
);

const mostIdenticalKey = identities.reduce((prev, current) => (current[1][0] > prev[1][0] ? current : prev))[0];

return mostIdenticalKey;
}
}
9 changes: 9 additions & 0 deletions apps/api/src/infra/langchain/langchain.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Global, Module } from '@nestjs/common';
import { LangchainService } from './langchain.service';

@Global()
@Module({
providers: [LangchainService],
exports: [LangchainService],
})
export class LangchainModule {}
Loading

0 comments on commit e223eb5

Please sign in to comment.