Skip to content

Commit

Permalink
[PowerPage][Copilot] Nl2Site and Nl2Page Service Integration for Site…
Browse files Browse the repository at this point in the history
… Create (#1053)

* Refactor PowerPagesChatParticipantConstants and add NL2PAGE and NL2SITE constants

* Refactor PowerPagesChatParticipantConstants and add new page types

* Update constants and move telemetry to different file

* Refactor and add getCommonHeaders function

---------

Co-authored-by: amitjoshi <[email protected]>
  • Loading branch information
amitjoshi438 and amitjoshi authored Nov 12, 2024
1 parent 7246c08 commit ff6059d
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { sendApiRequest } from '../../copilot/IntelligenceApiService';
import { PacWrapper } from '../../../client/pac/PacWrapper';
import { intelligenceAPIAuthentication } from '../../services/AuthenticationProvider';
import { ActiveOrgOutput } from '../../../client/pac/PacTypes';
import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, COPILOT_NOT_RELEASED_MSG, DISCLAIMER_MESSAGE, INVALID_RESPONSE, NO_PROMPT_MESSAGE, PAC_AUTH_INPUT, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG, RESPONSE_SCENARIOS, SKIP_CODES, STATER_PROMPTS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ERROR, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_LOCATION_REFERENCED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NO_PROMPT, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NOT_AVAILABLE_ECS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SUCCESSFUL_PROMPT, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WEBPAGE_RELATED_FILES, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WELCOME_PROMPT, WELCOME_MESSAGE, WELCOME_PROMPT } from './PowerPagesChatParticipantConstants';
import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, COPILOT_NOT_RELEASED_MSG, DISCLAIMER_MESSAGE, INVALID_RESPONSE, NO_PROMPT_MESSAGE, PAC_AUTH_INPUT, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG, RESPONSE_SCENARIOS, SKIP_CODES, STATER_PROMPTS, WELCOME_MESSAGE, WELCOME_PROMPT } from './PowerPagesChatParticipantConstants';
import { ORG_DETAILS_KEY, handleOrgChangeSuccess, initializeOrgDetails } from '../../utilities/OrgHandlerUtils';
import { createAndReferenceLocation, getComponentInfo, getEndpoint, provideChatParticipantFollowups, handleChatParticipantFeedback, createErrorResult, createSuccessResult, removeChatVariables } from './PowerPagesChatParticipantUtils';
import { checkCopilotAvailability, fetchRelatedFiles, getActiveEditorContent } from '../../utilities/Utils';
Expand All @@ -23,6 +23,7 @@ import { isPowerPagesGitHubCopilotEnabled } from '../../copilot/utils/copilotUti
import { ADX_WEBPAGE, IApiRequestParams, IRelatedFiles } from '../../constants';
import { oneDSLoggerWrapper } from '../../OneDSLoggerTelemetry/oneDSLoggerWrapper';
import { CommandRegistry } from '../CommandRegistry';
import { VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NOT_AVAILABLE_ECS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SUCCESSFUL_PROMPT, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WELCOME_PROMPT, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NO_PROMPT, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_LOCATION_REFERENCED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WEBPAGE_RELATED_FILES, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ERROR } from './PowerPagesChatParticipantTelemetryConstants';

// Initialize Command Registry and Register Commands
const commandRegistry = new CommandRegistry();
Expand Down Expand Up @@ -169,7 +170,7 @@ export class PowerPagesChatParticipant {
powerPagesAgentSessionId: this.powerPagesAgentSessionId,
telemetry: this.telemetry
};

return await command.execute(commandRequest, stream);

} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,14 @@ export const DISCLAIMER_MESSAGE = vscode.l10n.t('Make sure AI-generated content
export const NO_PROMPT_MESSAGE = vscode.l10n.t('Hi! Power Pages lets you build secure, professional websites that you can quickly configure and publish across web browsers and devices.\n\nTo create your website, visit the [Power Pages](https://powerpages.microsoft.com/).\nReturn to this chat and @powerpages can help you write and edit your website code.');
export const PAC_AUTH_INPUT = vscode.l10n.t("Checking for active auth profile...");
export const COPILOT_NOT_RELEASED_MSG = vscode.l10n.t("@PowerPages is not yet available in your region.")

// Telemetry Event Names
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED = 'VSCodeExtensionGitHubPowerPagesAgentInvoked';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS = 'VSCodeExtensionGitHubPowerPagesAgentOrgDetails';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND = 'VSCodeExtensionGitHubPowerPagesAgentOrgDetailsNotFound';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO = 'VSCodeExtensionGitHubPowerPagesAgentScenario';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO_FEEDBACK_THUMBSUP = 'VSCodeExtensionGitHubPowerPagesAgentScenarioFeedbackThumbsUp';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO_FEEDBACK_THUMBSDOWN = 'VSCodeExtensionGitHubPowerPagesAgentScenarioFeedbackThumbsDown';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ERROR = 'VSCodeExtensionGitHubPowerPagesAgentError';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WEBPAGE_RELATED_FILES = 'VSCodeExtensionGitHubPowerPagesAgentWebpageRelatedFiles';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_LOCATION_REFERENCED = 'VSCodeExtensionGitHubPowerPagesAgentLocationReferenced';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NO_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentNoPrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WELCOME_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentWelcomePrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SUCCESSFUL_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentSuccessfulPrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NOT_AVAILABLE_ECS = 'VSCodeExtensionGitHubPowerPagesAgentNotAvailableECS';


export const NL2PAGE_REQUEST_FAILED = 'Request failed for page type:';
export const NL2SITE_INVALID_RESPONSE = 'Invalid response structure';
export const HOME_PAGE_TYPE = 'Home';
export const ABOUT_PAGE_TYPE = 'AboutUs';
export const FAQ_PAGE_TYPE = 'FAQ';
export const INFO_PAGE_TYPE = 'Informational';
export const NL2PAGE_SCENARIO = 'NL2Page';
export const NL2SITE_SCENARIO = 'NL2Site';
export const NL2PAGE_GENERATE_NEW_PAGE = 'GenerateNewPage';
export const NL2SITE_GENERATE_NEW_SITE = 'GenerateNewSite';
export const NL2PAGE_SCOPE = 'Page';
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED = 'VSCodeExtensionGitHubPowerPagesAgentInvoked';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS = 'VSCodeExtensionGitHubPowerPagesAgentOrgDetails';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND = 'VSCodeExtensionGitHubPowerPagesAgentOrgDetailsNotFound';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO = 'VSCodeExtensionGitHubPowerPagesAgentScenario';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO_FEEDBACK_THUMBSUP = 'VSCodeExtensionGitHubPowerPagesAgentScenarioFeedbackThumbsUp';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO_FEEDBACK_THUMBSDOWN = 'VSCodeExtensionGitHubPowerPagesAgentScenarioFeedbackThumbsDown';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ERROR = 'VSCodeExtensionGitHubPowerPagesAgentError';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WEBPAGE_RELATED_FILES = 'VSCodeExtensionGitHubPowerPagesAgentWebpageRelatedFiles';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_LOCATION_REFERENCED = 'VSCodeExtensionGitHubPowerPagesAgentLocationReferenced';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NO_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentNoPrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_WELCOME_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentWelcomePrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SUCCESSFUL_PROMPT = 'VSCodeExtensionGitHubPowerPagesAgentSuccessfulPrompt';
export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_NOT_AVAILABLE_ECS = 'VSCodeExtensionGitHubPowerPagesAgentNotAvailableECS';
export const VSCODE_EXTENSION_NL2PAGE_REQUEST_FAILED = 'VSCodeExtensionNL2PageRequestFailed';
export const VSCODE_EXTENSION_NL2PAGE_REQUEST_SUCCESS = 'VSCodeExtensionNL2PageRequestSuccess';
export const VSCODE_EXTENSION_NL2SITE_REQUEST_FAILED = 'VSCodeExtensionNL2SiteRequestFailed';
export const VSCODE_EXTENSION_NL2SITE_REQUEST_SUCCESS = 'VSCodeExtensionNL2SiteRequestSuccess';
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { ITelemetry } from "../../../../OneDSLoggerTelemetry/telemetry/ITelemetry";
import { getCommonHeaders } from "../../../../services/AuthenticationProvider";
import { ABOUT_PAGE_TYPE, FAQ_PAGE_TYPE, HOME_PAGE_TYPE, INFO_PAGE_TYPE, NL2PAGE_GENERATE_NEW_PAGE, NL2PAGE_REQUEST_FAILED, NL2PAGE_SCENARIO, NL2PAGE_SCOPE} from "../../PowerPagesChatParticipantConstants";
import { VSCODE_EXTENSION_NL2PAGE_REQUEST_FAILED, VSCODE_EXTENSION_NL2PAGE_REQUEST_SUCCESS } from "../../PowerPagesChatParticipantTelemetryConstants";

export async function getNL2PageData(aibEndpoint: string, aibToken: string, userPrompt: string, siteName: string, sitePagesList: string[], sessionId: string, telemetry: ITelemetry) {

const constructRequestBody = (pageType: string, colorNumber:number, exampleNumber: number) => ({
"crossGeoOptions": {
"enableCrossGeoCall": true
},
"question": `${userPrompt} - ${pageType} page`,
"context": {
"shouldCheckBlockList": false,
"sessionId": sessionId,
"scenario": NL2PAGE_SCENARIO,
"subScenario": NL2PAGE_GENERATE_NEW_PAGE,
"version": "V1",
"information": {
"scope": NL2PAGE_SCOPE,
"includeImages": true,
"pageType": pageType === 'FAQ' ? 'FAQ' : 'Home', //Verify if this is correct
"title": siteName,
"pageName": pageType,
"colorNumber": colorNumber,
"shuffleImages": false,
"exampleNumber": exampleNumber
}
}
});

const requests = sitePagesList.map(async pageType => {
const colorNumber = generateRandomColorNumber();
const exampleNumber = generateRandomExampleNumber(pageType);
const requestBody = constructRequestBody(pageType, colorNumber, exampleNumber);

const requestInit: RequestInit = {
method: "POST",
headers: getCommonHeaders(aibToken),
body: JSON.stringify(requestBody)
};

try {
const response = await fetch(aibEndpoint, requestInit);
if (!response.ok) {
throw new Error(`${NL2PAGE_REQUEST_FAILED} ${pageType}`);
}

const responseData = await response.json();

if (responseData && responseData.additionalData[0]) {
return responseData.additionalData[0].snippets[0];
}
return null;
} catch (error) {
telemetry.sendTelemetryErrorEvent(VSCODE_EXTENSION_NL2PAGE_REQUEST_FAILED, { error: (error as Error)?.message, pageType });
return null;
}
});

const responses = await Promise.all(requests);

telemetry.sendTelemetryEvent(VSCODE_EXTENSION_NL2PAGE_REQUEST_SUCCESS, { sessionId });

// TODO: Home page is mandatory, so if it is not generated, return null
return responses.filter(response => response !== null);
}

export const generateRandomColorNumber = () => {
const colorNumbers = [1, 2, 3, 5, 6, 7, 8];
return colorNumbers[Math.floor(Math.random() * colorNumbers.length)];
};

export const generateRandomExampleNumber = (pageType: string) => {
const isFaqOrAboutPage = pageType === FAQ_PAGE_TYPE || pageType === ABOUT_PAGE_TYPE;
if (isFaqOrAboutPage) {
return 0;
} else if (pageType === HOME_PAGE_TYPE) {
const homeExampleNumbers = [1, 2, 3, 4];
return homeExampleNumbers[Math.floor(Math.random() * homeExampleNumbers.length)];
} else if (pageType === INFO_PAGE_TYPE) {
const infoExampleNumbers = [1, 2, 3];
return infoExampleNumbers[Math.floor(Math.random() * infoExampleNumbers.length)];
}
return 0;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { ITelemetry } from "../../../../OneDSLoggerTelemetry/telemetry/ITelemetry";
import { NL2SITE_GENERATE_NEW_SITE, NL2SITE_INVALID_RESPONSE, NL2SITE_SCENARIO} from "../../PowerPagesChatParticipantConstants";
import { VSCODE_EXTENSION_NL2SITE_REQUEST_SUCCESS, VSCODE_EXTENSION_NL2SITE_REQUEST_FAILED } from "../../PowerPagesChatParticipantTelemetryConstants";
import { getCommonHeaders } from "../../../../services/AuthenticationProvider";

export async function getNL2SiteData(aibEndpoint: string, aibToken: string, userPrompt: string, sessionId: string, telemetry: ITelemetry) {
const requestBody = {
"crossGeoOptions": {
"enableCrossGeoCall": true
},
"question": userPrompt,
"context": {
"sessionId": sessionId,
"scenario": NL2SITE_SCENARIO,
"subScenario": NL2SITE_GENERATE_NEW_SITE,
// "shouldCheckBlockList": false, //TODO: Check if this is needed
"version": "V1",
"information": {
"minPages": 7,
"maxPages": 7
}
}
};

const requestInit: RequestInit = {
method: "POST",
headers: getCommonHeaders(aibToken),
body: JSON.stringify(requestBody)
};

try {
const response = await fetch(aibEndpoint, requestInit);
if (!response.ok) {
throw new Error(`${response.statusText} - ${response.status}`);
}

const responseBody = await response.json();

if (responseBody && responseBody.additionalData[0]?.website) {
telemetry.sendTelemetryEvent(VSCODE_EXTENSION_NL2SITE_REQUEST_SUCCESS, {sessionId: sessionId});
return responseBody.additionalData[0].website; // Contains the pages, siteName & site description
} else {
throw new Error(NL2SITE_INVALID_RESPONSE);
}
} catch (error) {
telemetry.sendTelemetryErrorEvent(VSCODE_EXTENSION_NL2SITE_REQUEST_FAILED, { error: (error as Error)?.message });
return null;
}
}

0 comments on commit ff6059d

Please sign in to comment.