Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content source: auto-translation #557

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
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
Binary file modified bun.lockb
Binary file not shown.
40 changes: 40 additions & 0 deletions docs/integrations/sources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Content sources

Integrations can act as sources for computing content from external sources. Use-cases include:

- Translation: auto-translate another content and keeping it updated
- Changelog
- Code documentation


## Flow

## Create a content source

First of all, content sources should be listed in the `gitbook-manifest.yaml` file, under `sources`:

```yaml
sources:
- id: pirate
title: Content as a Pirate
```

Then the content source can be implemented:

```ts
import { createContentSource } from '@gitbook/runtime';

const pirate = createContentSource({
sourceId: 'pirate',
getPages: () => {

},
getPageDocument: () => {

}
});
```

## Refreshing content when source has changed

At the moment, an integration source can only depend on a GitBook space as a dependency. But we plan on implementing supporting for custom dependencies that can be refreshed.
16 changes: 7 additions & 9 deletions integrations/github-copilot/src/configuration.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { ContentKitIcon } from '@gitbook/api';
import { createComponent, getOAuthToken } from '@gitbook/runtime';
import { InstallationConfigurationProps, createComponent, getOAuthToken } from '@gitbook/runtime';

import { fetchGitHubInstallations } from './github';
import { getGitHubOAuthConfiguration } from './oauth';
import type { GitHubCopilotConfiguration, GitHubCopilotRuntimeContext } from './types';
import type {
GitHubCopilotConfiguration,
GitHubCopilotRuntimeContext,
GitHubCopilotRuntimeEnvironment,
} from './types';
import { createGitHubSetupState } from './setup';

type ConfigureProps = {
installation: {
configuration?: GitHubCopilotConfiguration;
};
};

/**
* ContentKit component to configure the GitHub Copilot integration.
*/
export const configurationComponent = createComponent<
ConfigureProps,
InstallationConfigurationProps<GitHubCopilotRuntimeEnvironment>,
{
installations: string[];
},
Expand Down
Binary file added integrations/openai-translate/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions integrations/openai-translate/gitbook-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: openai-translate
title: Translate with OpenAI
organization: gitbook
visibility: public
description: Automatically generate translation content using OpenAI
icon: ./assets/icon.png
externalLinks:
- label: OpenAI Platform
url: https://platform.openai.com/
categories:
- collaboration
summary: |
# Overview
Automically generate translations of your content that are kept to date to any changes using OpenAI GPT models.
# How to use it
Install the integration on your account and grant access to the source space and the target space.
script: src/index.ts
scopes:
- space:content:read
configurations:
account:
componentId: configure
contentSources:
- id: translate
title: Translate with AI
description: Generate automatic translation from a space using AI.
configuration:
componentId: configureSource
23 changes: 23 additions & 0 deletions integrations/openai-translate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@gitbook/integration-openai-translate",
"version": "0.0.0",
"private": true,
"scripts": {
"typecheck": "tsc --noEmit",
"check": "gitbook check",
"publish-integrations": "gitbook publish .",
"publish-integrations-staging": "gitbook publish .",
"logs": "gitbook tail",
"dev": "gitbook dev",
"test": "bun test"
},
"dependencies": {
"@gitbook/api": "*",
"@gitbook/runtime": "*",
"openai": "^4.67.1"
},
"devDependencies": {
"@gitbook/cli": "workspace:*",
"@gitbook/tsconfig": "workspace:*"
}
}
90 changes: 90 additions & 0 deletions integrations/openai-translate/src/configureComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { createComponent, InstallationConfigurationProps } from '@gitbook/runtime';

import {
DEFAULT_MODEL,
type OpenAITranslateRuntimeContext,
type OpenAITranslateRuntimeEnvironment,
} from './types';

/**
* ContentKit component to configure the integration.
*/
export const configureComponent = createComponent<
InstallationConfigurationProps<OpenAITranslateRuntimeEnvironment>,
{
apiKey: string;
model: string;
apiUrl: string;
},
{ action: 'save' },
OpenAITranslateRuntimeContext
>({
componentId: 'configure',
initialState: (props, _, context) => {
return {
apiKey: props.installation.configuration.apiKey ?? '',
model: props.installation.configuration.model ?? DEFAULT_MODEL,
apiUrl: props.installation.configuration.apiUrl ?? '',
};
},
action: async (element, action, ctx) => {
const { integration, installation } = ctx.environment;
if (action.action === 'save' && installation) {
await ctx.api.integrations.updateIntegrationInstallation(
integration.name,
installation.id,
{
configuration: {
apiKey: element.state.apiKey,
model: element.state.model,
apiUrl: element.state.apiUrl,
},
},
);
}

return element;
},
render: async (element, context) => {
return (
<block>
<input
label="API Key"
hint="OpenAI API key"
element={<textinput state="apiKey" />}
/>
<input
label="API URL"
hint="When using a custom provider or proxy, enter the URL of the OpenAI API."
element={<textinput state="apiUrl" />}
/>
<input
label="Model"
hint="Select the model to use for translation. We recommend picking powerful models like GPT-4 or GPT-4o."
element={
<select
state="model"
options={[
{
id: 'gpt-4',
label: 'GPT-4',
},
{
id: 'gpt-4o',
label: 'GPT-4o',
},
]}
/>
}
/>
<button
style="primary"
label="Save"
onPress={{
action: 'save',
}}
/>
</block>
);
},
});
94 changes: 94 additions & 0 deletions integrations/openai-translate/src/configureSourceComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { createComponent } from '@gitbook/runtime';

import type { OpenAITranslateRuntimeContext } from './types';

/**
* ContentKit component to configure the Translation source.
*/
export const configureSourceComponent = createComponent<
{},
{
space?: string;
language: string;
},
void,
OpenAITranslateRuntimeContext
>({
componentId: 'configureSource',
initialState: (props, _, context) => {
return {
language: 'en',
};
},
render: async (element, context) => {
const { api, environment } = context;
const { integration, installation } = environment;

if (!installation) {
throw new Error('Installation not found');
}

const {
data: { items: spaces },
} = await api.integrations.listIntegrationInstallationSpaces(
integration.name,
installation.id,
);
return (
<block>
<input
label="Source space"
hint="Select the space to translate content from."
element={
<select
state="space"
options={spaces.map((space) => ({
id: space.space,
label: space.space,
}))}
/>
}
/>
<input
label="Language"
hint="Select the language to translate content to."
element={
<select
state="language"
options={[
{ label: 'English', id: 'en' },
{ label: 'French', id: 'fr' },
{ label: 'German', id: 'de' },
{ label: 'Italian', id: 'it' },
{ label: 'Japanese', id: 'ja' },
{ label: 'Korean', id: 'ko' },
{ label: 'Portuguese', id: 'pt' },
{ label: 'Russian', id: 'ru' },
{ label: 'Spanish', id: 'es' },
Comment on lines +59 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

85 languages are supported by ChatGPT, let's add all of them! Why not restricting it to this list?

https://botpress.com/blog/list-of-languages-supported-by-chatgpt

]}
/>
}
/>
<button
style="primary"
label="Continue"
onPress={{
action: '@ui.submit',
returnValue: {
props: {
space: element.dynamicState('space'),
language: element.dynamicState('language'),
},
dependsOn: [
{
kind: 'space',
space: element.dynamicState('space'),
},
],
},
}}
/>
</block>
);
},
});
9 changes: 9 additions & 0 deletions integrations/openai-translate/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createIntegration } from '@gitbook/runtime';
import { translateContentSource } from './translateContentSource';
import { configureComponent } from './configureComponent';
import { configureSourceComponent } from './configureSourceComponent';

export default createIntegration({
contentSources: [translateContentSource],
components: [configureComponent, configureSourceComponent],
});
Loading
Loading