generate-magical-girl.ts 5.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { z } from "zod";
  2. import { generateWithAI, GenerationConfig } from "../../lib/ai";
  3. import { config as appConfig } from "../../lib/config";
  4. import { MainColor } from "../../lib/main-color";
  5. export const config = {
  6. runtime: 'edge',
  7. };
  8. export type MainColor = (typeof MainColor)[keyof typeof MainColor];
  9. // 定义魔法少女生成的 schema(排除 level 相关字段)
  10. const MagicalGirlGenerationSchema = z.object({
  11. flowerName: z.string().describe(`魔法少女的花名,应该与真实姓名有一定关联,如果真实姓名中有花则大概率用名字中的花名。
  12. 必须是一种花比如百合 / 丁香 / 茉莉,可以增加冷门的小众的花名概率,减少鸢尾的出现次数,大部分时候输出常用中文名,有时候可以使用英文音译为中文或者拉丁文音译为中文增加酷炫度,
  13. 但是不要出现魔法少女字样`),
  14. flowerDescription: z.string().describe("生成的 flowerName 在大众文化中的花语,大概 20 字左右,不要出现魔法少女字样"),
  15. appearance: z.object({
  16. height: z.string().describe('身高,格式如 "155cm",数据在 130cm 到 190cm 之间,减少使用 165cm,参考角色设定来生成'),
  17. weight: z.string().describe('体重,格式如 "45kg",数据在 30kg 到 60kg 之间,减少使用 48kg,参考角色设定来生成'),
  18. hairColor: z.string().describe("头发颜色,会出现渐变和挑染"),
  19. hairStyle: z.string().describe(`发型,具体到头发长度、发型样式、发饰等,可以是各种各样形状和颜色的发卡,
  20. 发挥你的想象力,符合审美即可,尽量不出现花形状的发饰,也可能是帽子、发卡、发箍之类的`),
  21. eyeColor: z.string().describe("眼睛颜色,有几率出现异瞳,比如一只蓝色一只绿色"),
  22. skinTone: z.string().describe("肤色,通常是白皙,但是偶尔会出现其他肤色,根据人物设定生成"),
  23. wearing: z.string().describe('人物身穿的服装样式,需要描述具体的颜色和式样款式,一般比较华丽,不要拘泥于花形状,符合主色调即可,其他形制在符合花语的情况下自由发挥'),
  24. specialFeature: z.string().describe("特征,一般是反映人物性格的常见表情、动作、特征等"),
  25. mainColor: z.enum(Object.values(MainColor) as [string, ...string[]]).describe(
  26. `魔法少女的主色调,请参考 hairColor 选择最接近的一项,如果 hairColor 是渐变,请选择最接近的渐变主色调`),
  27. firstPageColor: z.string().describe("根据 mainColor 产生第一个渐变色,格式以 #000000 给出"),
  28. secondPageColor: z.string().describe("根据 mainColor 产生第二个渐变色,格式以 #000000 给出"),
  29. }),
  30. spell: z.string().describe(`很酷的变身咒语,提供日语版和对应的中文翻译,使用 \n 换行,参考常见的日本魔法少女中的变身,通常 20 字到 40 字左右。
  31. - 参考格式1:
  32. "黒よりも黒く、闇よりも暗い。ここに我が真の真紅の黄金の光を託す。目覚めの時が来た。不条理な教会の腐敗した論理" \n
  33. "比黑色更黑 比黑暗更暗的漆黑 在此寄讬吾真红的金光吧 觉醒之时的到来 荒谬教会的堕落章理"`),
  34. });
  35. export type AIGeneratedMagicalGirl = z.infer<
  36. typeof MagicalGirlGenerationSchema
  37. >;
  38. // 魔法少女生成配置
  39. const magicalGirlGenerationConfig: GenerationConfig<AIGeneratedMagicalGirl, string> = {
  40. systemPrompt: appConfig.MAGICAL_GIRL_GENERATION.systemPrompt,
  41. temperature: appConfig.MAGICAL_GIRL_GENERATION.temperature,
  42. promptBuilder: (realName: string) => `请为名叫"${realName}"的人设计一个魔法少女角色。真实姓名:${realName}`,
  43. schema: MagicalGirlGenerationSchema,
  44. taskName: "生成魔法少女",
  45. maxTokens: 6000,
  46. };
  47. // 生成魔法少女的函数(使用通用函数)
  48. export async function generateMagicalGirlWithAI(
  49. realName: string
  50. ): Promise<AIGeneratedMagicalGirl> {
  51. return generateWithAI(realName, magicalGirlGenerationConfig);
  52. }
  53. async function handler(
  54. req: Request
  55. ): Promise<Response> {
  56. if (req.method !== 'POST') {
  57. return new Response(JSON.stringify({ error: 'Method not allowed' }), {
  58. status: 405,
  59. headers: { 'Content-Type': 'application/json' }
  60. });
  61. }
  62. const { name } = await req.json();
  63. if (!name || typeof name !== 'string') {
  64. return new Response(JSON.stringify({ error: 'Name is required' }), {
  65. status: 400,
  66. headers: { 'Content-Type': 'application/json' }
  67. });
  68. }
  69. try {
  70. const magicalGirl = await generateMagicalGirlWithAI(name.trim());
  71. return new Response(JSON.stringify(magicalGirl), {
  72. status: 200,
  73. headers: { 'Content-Type': 'application/json' }
  74. });
  75. } catch (error) {
  76. console.error('生成魔法少女失败:', error);
  77. return new Response(JSON.stringify({ error: '生成失败,请稍后重试' }), {
  78. status: 500,
  79. headers: { 'Content-Type': 'application/json' }
  80. });
  81. }
  82. }
  83. export default handler;