Skip to content

Commit

Permalink
feat: add ai vote decesion to party vote resolver
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Ruck <[email protected]>
  • Loading branch information
Manuel Ruck authored and ManAnRuck committed Apr 21, 2024
1 parent 2ee1586 commit 86095f9
Show file tree
Hide file tree
Showing 44 changed files with 2,901 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ NODE_ENV=development

# Enable express status
EXPRESS_STATUS=true

# AI Votes
OPENAI_API_KEY=
OPENAI_ORGANIZATION=
ACCESS_TOKEN=EMPTY
7 changes: 7 additions & 0 deletions bundestag.io/admin/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREDENTIALS=user:password
BUNDESTAGIO_SERVER_URL=https://internal.api.bundestag.io
NEXTAUTH_SECRET=secret
BIO_EDIT_TOKEN=""
AI_SERVER_URL=http://ai-votes:4003
AI_SERVER_URL_CODEGEN=http://localhost:4003
AI_ACCESS_TOKEN=EMPTY
30 changes: 30 additions & 0 deletions bundestag.io/admin/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
overwrite: true,
generates: {
// 'src/__generated/gql/': {
// schema: 'https://internal.api.bundestag.io',
// preset: 'client',
// documents: 'src/**/*.bio.graphql',
// config: {
// documentMode: 'string',
// },
// plugins: [],
// },
'src/__generated/gql-ai/': {
schema: {
[process.env.AI_SERVER_URL_CODEGEN!]: {
headers: {
'x-token': process.env.AI_ACCESS_TOKEN!,
},
},
},
preset: 'client',
documents: 'src/**/*.ai.graphql',
plugins: [],
},
},
};

export default config;
1 change: 0 additions & 1 deletion bundestag.io/admin/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
7 changes: 6 additions & 1 deletion bundestag.io/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint && tsc --noEmit"
"lint": "next lint && tsc --noEmit",
"codegen": "graphql-codegen --require dotenv/config --config codegen.ts dotenv_config_path=.env.local"
},
"dependencies": {
"@ant-design/icons": "^5.3.6",
"@apollo/client": "^3.9.10",
"@democracy-deutschland/bundestag.io-definitions": "^1.0.2",
"@graphql-typed-document-node/core": "^3.2.0",
"antd": "5.16.1",
"axios": "^1.6.8",
"graphql": "^16.8.1",
"graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6",
"next": "^14.2.2",
"next-auth": "^4.24.7",
Expand All @@ -25,6 +28,8 @@
"@babel/core": "^7.24.4",
"@babel/preset-typescript": "^7.24.1",
"@babel/register": "^7.23.7",
"@graphql-codegen/cli": "5.0.2",
"@graphql-codegen/client-preset": "4.2.5",
"@types/node": "^20.12.6",
"@types/react": "^18.2.75",
"@types/request": "^2.48.12",
Expand Down
67 changes: 67 additions & 0 deletions bundestag.io/admin/src/__generated/gql-ai/fragment-masking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* eslint-disable */
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
import { FragmentDefinitionNode } from 'graphql';
import { Incremental } from './graphql';


export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
infer TType,
any
>
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
: never
: never
: never;

// return non-nullable if `fragmentType` is non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
): TType;
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
): ReadonlyArray<TType>;
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}


export function makeFragmentData<
F extends DocumentTypeDecoration<any, any>,
FT extends ResultOf<F>
>(data: FT, _fragment: F): FragmentType<F> {
return data as FragmentType<F>;
}
export function isFragmentReady<TQuery, TFrag>(
queryNode: DocumentTypeDecoration<TQuery, any>,
fragmentNode: TypedDocumentNode<TFrag>,
data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
): data is FragmentType<typeof fragmentNode> {
const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
?.deferredFields;

if (!deferredFields) return true;

const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
const fragName = fragDef?.name?.value;

const fields = (fragName && deferredFields[fragName]) || [];
return fields.length > 0 && fields.every(field => data && field in data);
}
42 changes: 42 additions & 0 deletions bundestag.io/admin/src/__generated/gql-ai/gql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable */
import * as types from './graphql';
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';

/**
* Map of all GraphQL operations in the project.
*
* This map has several performance disadvantages:
* 1. It is not tree-shakeable, so it will include all operations in the project.
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
* 3. It does not support dead code elimination, so it will add unused operations.
*
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
"query ParseDecision($decision: String, $period: Int) {\n parseDecision(decision: $decision, period: $period) {\n input {\n decision\n period\n }\n result {\n votes {\n name\n vote\n }\n votingDocument\n votingRecommendation\n }\n usage {\n costs {\n completion\n prompt\n total\n }\n duration\n model\n tokens {\n completion\n prompt\n total\n }\n }\n }\n}": types.ParseDecisionDocument,
};

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*
*
* @example
* ```ts
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
* ```
*
* The query argument is unknown!
* Please regenerate the types.
*/
export function graphql(source: string): unknown;

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query ParseDecision($decision: String, $period: Int) {\n parseDecision(decision: $decision, period: $period) {\n input {\n decision\n period\n }\n result {\n votes {\n name\n vote\n }\n votingDocument\n votingRecommendation\n }\n usage {\n costs {\n completion\n prompt\n total\n }\n duration\n model\n tokens {\n completion\n prompt\n total\n }\n }\n }\n}"): (typeof documents)["query ParseDecision($decision: String, $period: Int) {\n parseDecision(decision: $decision, period: $period) {\n input {\n decision\n period\n }\n result {\n votes {\n name\n vote\n }\n votingDocument\n votingRecommendation\n }\n usage {\n costs {\n completion\n prompt\n total\n }\n duration\n model\n tokens {\n completion\n prompt\n total\n }\n }\n }\n}"];

export function graphql(source: string) {
return (documents as any)[source] ?? {};
}

export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;
98 changes: 98 additions & 0 deletions bundestag.io/admin/src/__generated/gql-ai/graphql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* eslint-disable */
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: { input: string; output: string; }
String: { input: string; output: string; }
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
};

export type Input = {
__typename?: 'Input';
decision?: Maybe<Scalars['String']['output']>;
period?: Maybe<Scalars['Int']['output']>;
};

export type ProcessResult = {
__typename?: 'ProcessResult';
input?: Maybe<Input>;
result?: Maybe<Result>;
usage?: Maybe<ProcessUsage>;
};

export type ProcessUsage = {
__typename?: 'ProcessUsage';
costs?: Maybe<Usage>;
duration?: Maybe<Scalars['String']['output']>;
model?: Maybe<Scalars['String']['output']>;
tokens?: Maybe<Usage>;
};

export type Query = {
__typename?: 'Query';
parseDecision?: Maybe<ProcessResult>;
};


export type QueryParseDecisionArgs = {
decision?: InputMaybe<Scalars['String']['input']>;
period?: InputMaybe<Scalars['Int']['input']>;
};

export type Result = {
__typename?: 'Result';
votes?: Maybe<Array<Maybe<Vote>>>;
votingDocument?: Maybe<VoteDocument>;
votingRecommendation?: Maybe<VotingRecommendation>;
};

export type Usage = {
__typename?: 'Usage';
completion?: Maybe<Scalars['Float']['output']>;
prompt?: Maybe<Scalars['Float']['output']>;
total?: Maybe<Scalars['Float']['output']>;
};

export type Vote = {
__typename?: 'Vote';
name?: Maybe<Scalars['String']['output']>;
vote?: Maybe<VoteResult>;
};

export enum VoteDocument {
MainDocument = 'mainDocument',
RecommendedDecision = 'recommendedDecision'
}

export enum VoteResult {
Abstination = 'ABSTINATION',
Mixed = 'MIXED',
No = 'NO',
Yes = 'YES'
}

export enum VotingRecommendation {
Accept = 'ACCEPT',
Reject = 'REJECT',
Unknown = 'UNKNOWN'
}

export type ParseDecisionQueryVariables = Exact<{
decision?: InputMaybe<Scalars['String']['input']>;
period?: InputMaybe<Scalars['Int']['input']>;
}>;


export type ParseDecisionQuery = { __typename?: 'Query', parseDecision?: { __typename?: 'ProcessResult', input?: { __typename?: 'Input', decision?: string | null, period?: number | null } | null, result?: { __typename?: 'Result', votingDocument?: VoteDocument | null, votingRecommendation?: VotingRecommendation | null, votes?: Array<{ __typename?: 'Vote', name?: string | null, vote?: VoteResult | null } | null> | null } | null, usage?: { __typename?: 'ProcessUsage', duration?: string | null, model?: string | null, costs?: { __typename?: 'Usage', completion?: number | null, prompt?: number | null, total?: number | null } | null, tokens?: { __typename?: 'Usage', completion?: number | null, prompt?: number | null, total?: number | null } | null } | null } | null };


export const ParseDecisionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ParseDecision"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"decision"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"period"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"parseDecision"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"decision"},"value":{"kind":"Variable","name":{"kind":"Name","value":"decision"}}},{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"period"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"input"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"decision"}},{"kind":"Field","name":{"kind":"Name","value":"period"}}]}},{"kind":"Field","name":{"kind":"Name","value":"result"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votingDocument"}},{"kind":"Field","name":{"kind":"Name","value":"votingRecommendation"}}]}},{"kind":"Field","name":{"kind":"Name","value":"usage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"costs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"completion"}},{"kind":"Field","name":{"kind":"Name","value":"prompt"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"model"}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"completion"}},{"kind":"Field","name":{"kind":"Name","value":"prompt"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}}]}}]}}]}}]} as unknown as DocumentNode<ParseDecisionQuery, ParseDecisionQueryVariables>;
2 changes: 2 additions & 0 deletions bundestag.io/admin/src/__generated/gql-ai/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./fragment-masking";
export * from "./gql";
63 changes: 63 additions & 0 deletions bundestag.io/admin/src/__generated/gql/fragment-masking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable */
import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core';
import { Incremental, TypedDocumentString } from './graphql';


export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
infer TType,
any
>
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
: never
: never
: never;

// return non-nullable if `fragmentType` is non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
): TType;
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
): ReadonlyArray<TType>;
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}


export function makeFragmentData<
F extends DocumentTypeDecoration<any, any>,
FT extends ResultOf<F>
>(data: FT, _fragment: F): FragmentType<F> {
return data as FragmentType<F>;
}
export function isFragmentReady<TQuery, TFrag>(
queryNode: TypedDocumentString<TQuery, any>,
fragmentNode: TypedDocumentString<TFrag, any>,
data: FragmentType<TypedDocumentString<Incremental<TFrag>, any>> | null | undefined
): data is FragmentType<typeof fragmentNode> {
const deferredFields = queryNode.__meta__?.deferredFields as Record<string, (keyof TFrag)[]>;
const fragName = fragmentNode.__meta__?.fragmentName as string | undefined;

if (!deferredFields || !fragName) return true;

const fields = deferredFields[fragName] ?? [];
return fields.length > 0 && fields.every(field => data && field in data);
}
28 changes: 28 additions & 0 deletions bundestag.io/admin/src/__generated/gql/gql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable */
import * as types from './graphql';



/**
* Map of all GraphQL operations in the project.
*
* This map has several performance disadvantages:
* 1. It is not tree-shakeable, so it will include all operations in the project.
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
* 3. It does not support dead code elimination, so it will add unused operations.
*
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
"query LegislativePeriods {\n legislativePeriods {\n number\n deputies\n start\n end\n }\n}": types.LegislativePeriodsDocument,
};

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query LegislativePeriods {\n legislativePeriods {\n number\n deputies\n start\n end\n }\n}"): typeof import('./graphql').LegislativePeriodsDocument;


export function graphql(source: string) {
return (documents as any)[source] ?? {};
}
Loading

0 comments on commit 86095f9

Please sign in to comment.