Skip to content
Draft
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
50 changes: 37 additions & 13 deletions apps/google-docs/contentful-app-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
},
"functions": [
{
"id": "createEntriesFromDocumentFunction",
"name": "Create content entries from document function",
"description": "Function to create content blocks from App Action.",
"path": "functions/createEntriesFromDocument.js",
"entryFile": "functions/createEntriesFromDocument.ts",
"id": "createPreview",
"name": "Create Preview",
"description": "Parses the Google Doc and creates preview entries",
"path": "functions/handlers/createPreviewHandler.js",
"entryFile": "functions/handlers/createPreviewHandler.ts",
"allowNetworks": [
"https://api.openai.com",
"*.googleapis.com",
Expand All @@ -37,12 +37,36 @@
"appaction.call"
]
},
{
"id": "analyzeContentTypes",
"name": "Analyze Content Types",
"description": "Analyzes content type structure and relationships using AI.",
"path": "functions/handlers/analyzeContentTypesHandler.js",
"entryFile": "functions/handlers/analyzeContentTypesHandler.ts",
"allowNetworks": [
"https://api.openai.com"
],
"accepts": [
"appaction.call"
]
},
{
"id": "createEntries",
"name": "Create Entries",
"description": "Creates entries in Contentful",
"path": "functions/handlers/createEntriesHandler.js",
"entryFile": "functions/handlers/createEntriesHandler.ts",
"allowNetworks": [],
"accepts": [
"appaction.call"
]
},
{
"id": "initiateGdocOauth",
"name": "Initiate Gdoc OAuth Flow",
"description": "Initiates the OAuth flow for Google Docs",
"path": "functions/initiateOauth.js",
"entryFile": "functions/initiateOauth.ts",
"path": "functions/oauth/initiateOauth.js",
"entryFile": "functions/oauth/initiateOauth.ts",
"allowNetworks": [
"oauth2.googleapis.com"
],
Expand All @@ -54,8 +78,8 @@
"id": "completeGdocOauth",
"name": "Complete Gdoc OAuth Flow",
"description": "Completes the OAuth flow for Google Docs",
"path": "functions/completeOauth.js",
"entryFile": "functions/completeOauth.ts",
"path": "functions/oauth/completeOauth.js",
"entryFile": "functions/oauth/completeOauth.ts",
"allowNetworks": [
"oauth2.googleapis.com"
],
Expand All @@ -67,8 +91,8 @@
"id": "revokeGdocOauthToken",
"name": "Revoke Gdoc OAuth Token",
"description": "Revoke token for the Google Docs app to disconnect from the app",
"path": "functions/disconnect.js",
"entryFile": "functions/disconnect.ts",
"path": "functions/oauth/disconnect.js",
"entryFile": "functions/oauth/disconnect.ts",
"allowNetworks": [
"oauth2.googleapis.com"
],
Expand All @@ -80,8 +104,8 @@
"id": "checkGdocOauthTokenStatus",
"name": "Check Gdoc OAuth Token Status",
"description": "Checks the status of the Google Docs OAuth token to see if it is valid",
"path": "functions/checkStatus.js",
"entryFile": "functions/checkStatus.ts",
"path": "functions/oauth/checkStatus.js",
"entryFile": "functions/oauth/checkStatus.ts",
"allowNetworks": [
"oauth2.googleapis.com"
],
Expand Down
90 changes: 0 additions & 90 deletions apps/google-docs/functions/createEntriesFromDocument.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type {
FunctionEventContext,
FunctionEventHandler,
FunctionTypeEnum,
AppActionRequest,
} from '@contentful/node-apps-toolkit';
import { analyzeContentTypes as analyzeContentTypesAgent } from '../agents/contentTypeParserAgent/contentTypeParser.agent';
import { fetchContentTypes } from '../service/contentTypeService';
import { initContentfulManagementClient } from '../service/initCMAClient';

export type AnalyzeContentTypesParameters = {
contentTypeIds: string[];
};

interface AppInstallationParameters {
openAiApiKey: string;
}

export const handler: FunctionEventHandler<
FunctionTypeEnum.AppActionCall,
AnalyzeContentTypesParameters
> = async (
event: AppActionRequest<'Custom', AnalyzeContentTypesParameters>,
context: FunctionEventContext
) => {
const { contentTypeIds } = event.body;
const { openAiApiKey } = context.appInstallationParameters as AppInstallationParameters;

if (!contentTypeIds || contentTypeIds.length === 0) {
throw new Error('At least one content type ID is required');
}

const cma = initContentfulManagementClient(context);
const contentTypes = await fetchContentTypes(cma, new Set<string>(contentTypeIds));

const contentTypeParserAgentResult = await analyzeContentTypesAgent({
contentTypes,
openAiApiKey,
});

console.log('Content type analysis completed', contentTypeParserAgentResult);
return {
success: true,
analysis: contentTypeParserAgentResult,
};
};
51 changes: 51 additions & 0 deletions apps/google-docs/functions/handlers/createEntriesHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { AppActionRequest, FunctionEventHandler } from '@contentful/node-apps-toolkit';
import { createEntries } from '../service/entryService';
import { initContentfulManagementClient } from '../service/initCMAClient';
import { EntryToCreate } from '../agents/documentParserAgent/schema';
import { FunctionTypeEnum, FunctionEventContext } from '@contentful/node-apps-toolkit';

interface CreateEntriesParameters {
entries: EntryToCreate[];
contentTypeIds: string[];
}

export const handler: FunctionEventHandler<
FunctionTypeEnum.AppActionCall,
CreateEntriesParameters
> = async (
event: AppActionRequest<'Custom', CreateEntriesParameters>,
context: FunctionEventContext
) => {
const { entries, contentTypeIds } = event.body;

if (!entries || !Array.isArray(entries) || entries.length === 0) {
throw new Error('entries parameter is required and must be a non-empty array');
}

if (!contentTypeIds || !Array.isArray(contentTypeIds) || contentTypeIds.length === 0) {
throw new Error('contentTypeIds parameter is required and must be a non-empty array');
}

const cma = initContentfulManagementClient(context);

// Fetch content types
const contentTypesResponse = await cma.contentType.getMany({});
const contentTypes = contentTypesResponse.items.filter((ct) =>
contentTypeIds.includes(ct.sys.id)
);

if (contentTypes.length === 0) {
throw new Error('No matching content types found');
}

const result = await createEntries(cma, entries, {
spaceId: context.spaceId,
environmentId: context.environmentId,
contentTypes: contentTypes,
});

return {
success: true,
result: result,
};
};
60 changes: 60 additions & 0 deletions apps/google-docs/functions/handlers/createPreviewHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type {
FunctionEventContext,
FunctionEventHandler,
FunctionTypeEnum,
AppActionRequest,
} from '@contentful/node-apps-toolkit';
import { analyzeDocumentWithAgent } from '../agents/documentParserAgent/documentParser.agent';
import { fetchContentTypes } from '../service/contentTypeService';
import { initContentfulManagementClient } from '../service/initCMAClient';

export type CreatePreviewParameters = {
contentTypeIds: string[];
documentId: string;
oauthToken: string;
};

interface AppInstallationParameters {
openAiApiKey: string;
}

/**
* Create Preview
*
* Processes a Google Doc and creates preview entries based on the document structure
* and the provided content types.
*
*/
export const handler: FunctionEventHandler<
FunctionTypeEnum.AppActionCall,
CreatePreviewParameters
> = async (
event: AppActionRequest<'Custom', CreatePreviewParameters>,
context: FunctionEventContext
) => {
const { contentTypeIds, documentId, oauthToken } = event.body;
const { openAiApiKey } = context.appInstallationParameters as AppInstallationParameters;

if (!contentTypeIds || contentTypeIds.length === 0) {
throw new Error('At least one content type ID is required');
}

const cma = initContentfulManagementClient(context);

const contentTypes = await fetchContentTypes(cma, new Set<string>(contentTypeIds));

// Process the document and create preview entries
const aiDocumentResponse = await analyzeDocumentWithAgent({
documentId,
oauthToken,
openAiApiKey,
contentTypes,
});

return {
success: true,
summary: aiDocumentResponse.summary,
totalEntriesExtracted: aiDocumentResponse.totalEntries,
entries: aiDocumentResponse.entries,
};
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
AppEventHandlerRequest,
AppEventHandlerResponse,
AppEventContext,
} from './types/oauth.types';
import { AppEventHandlerRequest, AppEventHandlerResponse, AppEventContext } from './oauth.types';

export const handler = async (
event: AppEventHandlerRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
AppEventHandlerRequest,
AppEventContext,
AppEventHandlerResponse,
} from './types/oauth.types';
} from './oauth.types';

export type OAuthSDK = {
init: () => Promise<OAuthInitResponse>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export const ContentTypePickerModal = ({
variant="primary"
isDisabled={isLoading || isSubmitting}
endIcon={isSubmitting ? <Spinner /> : undefined}>
Create
Next
</Button>
</Modal.Controls>
</>
Expand Down
Loading
Loading