我们喜欢讲故事。讲故事和进行其他形式的创意写作既具有挑战性,又能带来成就感。不过,从一张空白的页面开始构建自己的故事有时会让人感到畏惧,甚至不知所措。人工智能 (AI) 生成式模型是一款非常有用的工具,可帮助您克服空白页面,构建自己的叙事。
本教程介绍了如何扩展 Wordcraft,这是一个由 Google 人与 AI 研究团队打造的 AI 赋能的短篇故事创作工具。此 Web 应用使用 Gemini API 帮助您通过生成想法、撰写故事的部分内容以及修改内容以添加更多细节,一点一点地构建故事。您可以修改 Wordcraft,使其更贴近您自己的写作风格,并构建新的写作控件,以更好地支持您的工作流。
如需观看有关该项目及其扩展方式的视频简介,包括项目开发者的深入解析,请参阅 AI 写作助理 - 利用 Google AI 构建。否则,您可以按照以下说明开始扩展项目。
项目设置
以下说明将引导您完成 Wordcraft 项目的设置,以便进行开发和测试。您需要安装必需的软件、从代码库克隆项目、运行配置安装,并设置一些环境变量。完成这些步骤后,您可以通过运行项目来测试设置。
安装必备组件
Wordcraft 项目使用 Node 和 npm 来管理软件包并运行应用。以下安装说明适用于 Linux 主机。
如需安装所需的软件,请执行以下操作:
- 按照适用于您的平台的安装说明安装
node
和npm
。
克隆并配置项目
下载项目代码,然后使用 npm
安装命令下载所需的依赖项并配置项目。您需要 git 源代码控制软件才能检索项目源代码。
如需下载和配置项目代码,请执行以下操作:
- 使用以下命令克隆 Git 代码库。
git clone https://github.com/PAIR-code/wordcraft
- 前往 Wordcraft 项目根目录。
cd wordcraft/
- 运行安装命令以下载依赖项并配置项目:
npm install
设置环境变量
设置运行 Wordcraft 代码项目所需的环境变量,尤其是 Google Gemini API 密钥。以下安装说明适用于 Linux 主机。
如需设置环境变量,请执行以下操作:
- 获取 Google Gemini API 密钥并复制密钥字符串。
- 前往 Wordcraft 项目根目录。`
cd wordcraft/
- 将 API 密钥设置为环境变量。在 Linux 主机上,请使用以下命令。
touch .env echo "API_KEY="<YOUR_API_KEY>"" > .env
测试您的设置
现在,您应该能够在设备上运行 Wordcraft 来测试项目设置。此步骤并非强制性要求,但建议您执行此操作。
如需测试安装和设置,请执行以下操作:
- 前往 Wordcraft 项目根目录。
cd wordcraft/
- 在开发模式下通过它运行项目:
npm run dev
- 在网络浏览器中,打开 Wordcraft 界面。上一个命令的输出中会显示具体地址,例如:
http://localhost:3000/
修改提示示例文本
Wordcraft 会针对每项写作辅助操作(例如 start new story 和 generate text 命令)使用一组示例为 AI 生成式模型创建提示。这些示例可指导生成式模型为您的故事生成文本,通过修改操作的示例,您可以更改输出,使其遵循不同的写作模式或风格。这种方法可以让 Wordcraft 以您想要的方式进行写作,非常简单。
以下示例展示了对 Wordcraft 中的 new_story
示例所做的修改。此修改旨在指示 AI 生成式模型使用内心独白方法编写故事开头,并使用更适合推理小说的文风。通过撰写几篇此类故事开场白示例,您可以让生成式模型遵循一般模式,但为其他主题生成开场白。
如需在 Wordcraft 中修改新的短片故事示例,请执行以下操作:
- 打开
wordcraft/app/context/json/new_story.json
文件。 - 修改示例,同时保持 JSON 文件的整体结构。以下是使用内心独白风格修改的推理小说开头示例。
[ { "topic": "scientist disappears and their research into a new technology is gone", "target": "I got the call from the chief early Tuesday morning, before I'd even had a second sip of coffee. Terrible timing. Something about a researcher disappearing from the local university. Unusual for the research lab to ask for assistance, so I headed over to main lab building." }, { "topic": "a young woman wakes up with no memory", "target": "An unfamiliar ceiling with harsh, white lights greeted my eyes as I opened them. I looked around. White walls, medical equipment, a hospital? Wait. Where am I? How did I get here?!" }, { "topic": "old man tries to recall an important task as his memories gradually fade away", "target": "What was I supposed to do today? Feels like it was important. I stared into the kitchen cabinet full of mismatched mugs, mirroring my own confusion. What was it? Like someone is...in danger? A chill shot down my spine, but the details skittered off and hid in some dark corner of my head." }, { "topic": "billionaire is found dead in a hotel room", "target": "People meet their end every day, some naturally, some unnaturally. After 17 years of working as a homicide detective in Seattle, I'd seen a lot more of the unnatural variety than most. Comes with the job, along with a hard-learned sense of what side of the line any given incident sat on. This...was murder." }, { "topic": "retired covert operative gets dragged back into an old mission", "target": "Steam rose gently off the cup of Earl Grey sitting in front of me as I sat at the cafe, pedestrians and light traffic rolling by. The city was slowly waking up around me and my perfect Paris morning routine was shaping up nicely. Then I noticed that old familiar and unwelcome tingling on the back of my neck. I was being watched." } ]
- 将更改保存到 `new_story.json` 文件。
如需测试修改后的新故事操作,请执行以下操作:
- 前往 Wordcraft 项目根目录。
cd wordcraft/
- 在开发模式下运行项目。如果该应用已在运行,您可能需要停止并重新启动该应用。
npm run dev
- 在网络浏览器中,打开 Wordcraft 界面。上一个命令的输出中会显示具体地址,例如:
http://localhost:3000/
- 前往 Wordcraft 的主菜单,然后选择开始写新故事。
- 更新新故事提示或将其更改为您想要的内容,然后选择开始新故事。
您可以使用此方法修改 Wordcraft 中的所有现有故事创作控件。尝试通过更新 wordcraft/app/context/json/
目录中的示例来更改其他短片故事控件。
创建新的手写控件
Wordcraft 应用旨在可扩展,因此您可以添加新的写作控件来提供帮助,类似于应用右侧“控件”标签页中的生成文本或重写句子按钮。进行这些修改需要付出一些努力,但您可以根据自己的工作流程和目标塑造 Wordcraft 的功能。
以下示例修改会为 Wordcraft 创建一个新的字符控件。您可以使用它在故事中引入新角色,并描述该角色的属性。此控件的底层与其他 Wordcraft 控件(例如前面讨论的开始新故事控件)相同。您需要创建一个 JSON 文件,并在其中添加一些示例,说明您希望如何介绍角色。其余更改则添加了界面和 AI 提示管理功能。
创建示例
写几个示例,说明您希望生成式模型如何介绍角色。例如,您是想像讲述者一样描述它们,还是想通过主角的经历来介绍它们?以下示例使用后一种方法,从主角的视角介绍新角色。您可以使用新的 JSON 文件添加这些示例:
如需为新控件添加示例,请执行以下操作:
- 创建
wordcraft/app/context/json/new_character.json
文件。 - 在 JSON 文件中创建示例。在本例中,每个示例都有一个
character
说明字段(表示提示文本)和一个target
字段(显示预期输出)。[ { "character": "A character who is helpful and modest.", "target": "\"You lost, buddy?\" came a voice from behind me. Turning, I discovered a man dressed in a simple but presentable outfit. Small signs of age and loose threads hinted that these clothes, and the man himself, had seen better days." }, { "character": "A character who is attractive and devious.", "target": "Stepping out of the alley a little too quickly, I collided with something solidly muscular and surprisingly delicately scented. \"Sorry.\" I managed, regaining my balance. \"Easy there, buddy, you're gonna hurt yourself,\" came the reply from a man with an almost feline grace, further reinforced by a stare that reminded me of a hunting cat assessing its potential prey." }, { "character": "A character who is old and hesitant.", "target": "\"Excuse me. Do you know the way to the train station from here?\" I looked up from my phone to see a elderly woman in a threadbare coat, purse clutched with two hands in front of her. \"I-I'm supposed to meet my nephew there. Do... do you think you can help me?\"" }, { "character": "A character who is intelligent and aloof.", "target": "Bookish. That was my immediate reaction to this person I now saw in front of me. \"You're finally here. Did you read the notes I sent you?\" The voice sat squarely in between feminine and masculine intonation. \"No, of course you didn't.\" Dismissing my answer before I'd even formulated one. Annoyance immediately flushed through me." }, { "character": "A character who is clumsy and energetic.", "target": "\"Whoa!\" was the only warning I had before someone slammed into my back, almost knocking me off my feet. \"I'm so sorry! WOOO! These skates are a RUSH!\" The apology came from a rather loud redhead wearing rollerblades, dark glasses and a very beefy-looking pair of headphones. That explained the volume of the apology." } ]
- 将更改保存到
new_character.json
文件。
创建示例后,修改 app/context/schema.ts
和 index.ts
文件,以反映此新字符控件的提示内容。
如需将示例添加到 schema.ts
文件,请执行以下操作:
- 修改
wordcraft/app/context/schema.ts
文件以添加新的字符示例数据结构。export const newStorySchema = z.object({ topic: z.string(), target: z.string(), }); // add the following: export const newCharacterSchema = z.object({ character: z.string(), target: z.string(), });
定义与这些新示例关联的操作类型。这种新类型有助于将问题示例与界面和问题构建代码相关联,您将在后续步骤中修改这些代码。
创建新操作类型
- 修改
wordcraft/app/core/shared/types.ts
文件以添加新的字符操作类型。export const enum OperationType { ... NEW_CHARACTER = 'NEW_CHARACTER', // add to list of types ... }
如需在 index.ts
文件中注册示例,请执行以下操作:
- 在
wordcraft/app/context/index.ts
文件中,导入新架构。import { continueSchema, ... newCharacterSchema // add new schema } from './schema';
- 将新的 JSON 文件作为
newCharacterJson
导入。import newCharacterJson from './json/new_character.json';
- 在应用上下文中注册新的字符示例内容。
export class WordcraftContext { constructor() { ... this.registerExamples( OperationType.NEW_CHARACTER, newCharacterSchema, newCharacterJson ); ... }
- 导出
NewCharacterExample
类型。export type NewCharacterExample = z.infer<typeof newCharacterSchema>;
构建界面
创建并注册内容生成示例后,您就可以为新控件创建界面了。此阶段的大部分工作是创建新的操作类,然后将该类注册到 Wordcraft 应用的主要代码中。
如需创建新操作,请执行以下操作:
- 在
wordcraft/app/core/operations/
目录中,使用现有操作类之一作为模板创建新的操作类。对于新字符控件,您可以复制new_story_operation.ts
类并将其重命名为new_character_operation.ts
。 - 为类命名,并通过定义至少一个
OperationSite
值来指定控件何时显示在界面中。export class NewCharacterOperation extends ChoiceOperation { static override isAvailable(operationSite: OperationSite) { return ( operationSite === OperationSite.END_OF_SECTION || operationSite === OperationSite.EMPTY_SECTION ); }
- 为操作设置
id
。static override id = OperationType.NEW_CHARACTER;
- 更新
get
和run
函数,以反映架构参数的值。此代码用于从界面获取提示文本,以便在 AI 提示中使用。private get character(): string { return NewCharacterOperation.controls.character.value; } async run() { const params = { character: this.character }; const choices = await this.getModel().newCharacter(params); this.setChoices(choices); }
- 更新了界面文本和说明。
static override getButtonLabel() { return 'introduce character'; } static override getDescription() { return 'Introduce a new character at the cursor.'; } static override controls = { character: new TextareaControl({ prefix: 'prompt', description: 'A prompt to introduce a new character.', value: 'A new character.', }), };
如需在 Wordcraft 应用中注册新操作,请执行以下操作:
- 在
wordcraft/app/core/operations/index.ts
文件中,为新操作添加导入。import {NewCharacterOperation} from './new_character_operation';
- 在同一
index.ts
文件中,为NewCharacterOperation
类添加导出内容。export { ... NewCharacterOperation, // add this class ... };
- 在
wordcraft/app/main.ts
文件中,注册新操作。const operationsService = wordcraftCore.getService(OperationsService); operationsService.registerOperations( ... Operations.NewCharacterOperation, // add new operation ... );
创建提示处理
作为创建新控件的最后一阶段,您需要创建用于处理为 AI 生成式模型生成提示和处理响应的代码。工作的主要部分是在 wordcraft/app/models/gemini/prompts/
目录中构建一个提示处理程序,该处理程序从界面获取输入,并组装要传递给生成式模型的提示。
如需为提示参数定义接口,请执行以下操作:
- 在
wordcraft/app/core/shared/interfaces.ts
文件中,为提示参数的新操作添加接口。export interface NewCharacterPromptParams { character: string; }
如需为新操作定义提示处理程序,请执行以下操作:
- 在
wordcraft/app/models/gemini/prompts/
目录中,使用现有操作类之一作为模板创建新的提示处理程序类。对于新字符控件,您可以复制new_story.ts
类并将其重命名为new_character.ts
,以此作为起点。 - 定义提示处理程序函数并导入
NewCharacterExample
类。import { NewCharacterPromptParams } from '@core/shared/interfaces'; import { NewCharacterExample, WordcraftContext } from '../../../context'; import { OperationType } from '@core/shared/types'; import { GeminiModel } from '..'; export function makePromptHandler(model: GeminiModel, context: WordcraftContext) { ... }
- 构建
generatePrompt()
函数,用于获取 AI 模型提示的界面输入。function generatePrompt(character: string) { const prefix = "Here's a character description: "; const suffix = "Introduce this character in the story."; if (character.trim() === '') { return 'Introduce a new character to the story.'; } else { return `${prefix}${model.wrap(character)}\n${suffix}`; } }
- 创建一个
getPromptContext()
函数,用于将界面输入与示例回答组合并构建完整的提示。function getPromptContext() { const examples = context.getExampleData
( OperationType.NEW_CHARACTER ); let promptContext = model.getPromptPreamble(); examples.forEach((example) => { const { character, target } = example; const prompt = generatePrompt(character); promptContext += `${prompt} ${model.wrap(target)}\n\n`; }); return promptContext; }
如需集成新的字符提示处理脚本,请执行以下操作:
- 在
wordcraft/app/models/gemini/index.ts
文件中,导入新字符操作的提示处理脚本。import {makePromptHandler as newCharacter} from './prompts/new_character';
- 为
newCharacter
提示处理程序添加替换项定义。override newCharacter = this.makePromptHandler(newCharacter);
如需将提示参数注册到模型定义,请执行以下操作:
- 在
wordcraft/app/models/model.ts
文件中,为新的NewCharacterPromptParams
接口添加导入。import { ... NewCharacterPromptParams, ... } from '@core/shared/interfaces';
- 向模型类添加了
newCharacter
提示参数。async newCharacter(params: NewCharacterPromptParams): Promise<ModelResults> { throw new Error('Not yet implemented'); }
测试新的写入控件
您的新控件应该已经可以通过 Wordcraft 界面进行测试了。请务必先检查代码是否存在编译错误,然后再继续操作。
如需测试新字符控制功能,请执行以下操作:
- 前往 Wordcraft 项目根目录。`
cd wordcraft/
- 在开发模式下运行项目:
npm run dev
- 在网络浏览器中,打开 Wordcraft 界面。上一个命令的输出中会显示具体地址,例如:
http://localhost:3000/
- 在 Wordcraft 应用中,创建新故事或打开现有故事。
- 在故事编辑区域中,将光标移至故事的末尾。右侧的“控件”标签页中应会显示引入角色控件。
- 在介绍角色字段中,输入新角色的简要说明,然后选择介绍角色按钮。
其他资源
如需详细了解 Wordcraft 项目,请参阅代码库。您可以在此拉取请求中查看本教程中所述的更改。
正式版应用
如果您打算面向大量受众群体部署自定义版 Wordcraft,请注意,您在使用 Google Gemini API 时可能会受到速率限制和其他使用限制。如果您考虑使用 Gemini API 构建生产应用(例如 Google 文档客服),请查看 Google Cloud Vertex AI 服务,以提高应用的可伸缩性和可靠性。