add supertonic style option

This commit is contained in:
kimpure 2026-05-20 14:29:14 +00:00
parent 2f4885305e
commit 86fa4a01d3
No known key found for this signature in database
15 changed files with 105 additions and 16 deletions

3
.gitignore vendored
View file

@ -10,5 +10,4 @@ cache
db
docker-compose.yml
target/
test.wav
target/

0
eslint.config.js Normal file
View file

View file

@ -12,7 +12,7 @@ export default defineCommand(
});
const profile = await getUserProfile(interaction.user.id);
setUserNya(interaction.user.id, !profile.nya);
await setUserNya(interaction.user.id, !profile.nya);
await interaction.editReply(profile.nya ? "냐앙..." : "냐앙!!");
}

View file

@ -0,0 +1,29 @@
import { ChatInputCommandInteraction, MessageFlags, SlashCommandSubcommandBuilder } from "discord.js";
import { defineCommand } from "../command";
import { setUserSupertonicStyle } from "../db";
import { SUPERTONIC_STYLE_LIST } from "../../env";
export default defineCommand(
new SlashCommandSubcommandBuilder()
.setName("슈퍼토닉목소리")
.setDescription("예주의 슈퍼토닉 목소리 스타일을 설정해요")
.addStringOption(option =>
option
.setName("style")
.setDescription("사용할수 있는 목소리들이에요")
.setRequired(true)
.addChoices(
...SUPERTONIC_STYLE_LIST
)
),
async (interaction: ChatInputCommandInteraction): Promise<any> => {
await interaction.deferReply({
flags: [MessageFlags.Ephemeral]
});
const style = interaction.options.getString("voice") as string;
setUserSupertonicStyle(interaction.user.id, style);
await interaction.editReply("예주의 목소리 스타일을 변경했어요!");
}
)

View file

@ -24,7 +24,7 @@ export default defineCommand(
});
const voice = interaction.options.getString("voice") as Voice;
setUserVoice(interaction.user.id, voice);
await setUserVoice(interaction.user.id, voice);
await interaction.editReply("예주의 목소리를 변경했어요!");
}

View file

@ -42,6 +42,21 @@ export async function setUserNya(userId: string, nya: boolean): Promise<void> {
});
}
export async function setUserSupertonicStyle(userId: string, style: string): Promise<void> {
await prisma.discordUserProfile.upsert({
where: {
userId: userId
},
update: {
userSupertonicStyle: style
},
create: {
userId: userId,
userSupertonicStyle: style
}
});
}
export async function setUserVoice(userId: string, voice: Voice): Promise<void> {
await prisma.discordUserProfile.upsert({
where: {
@ -52,7 +67,7 @@ export async function setUserVoice(userId: string, voice: Voice): Promise<void>
},
create: {
userId: userId,
voice: voice
voice: voice
}
});
}

View file

@ -3,6 +3,7 @@ import { getUserProfile, hasGuildReadChannel } from "../db";
import { defineEvent } from "../event";
import { playVoice, PlayVoiceOptions } from "../tts";
import { Voice } from "../../db/generated/prisma/enums";
import { SUPERTONIC_DEFAULT_VOICE } from "../../env";
export default defineEvent("messageCreate", async (message) => {
if (message.author.bot)
@ -20,7 +21,7 @@ export default defineEvent("messageCreate", async (message) => {
let content = message.cleanContent;
let voice: Voice | null = null
let options: PlayVoiceOptions | undefined = undefined;
let options: PlayVoiceOptions = {};
let matched: RegExpMatchArray | null = null;
if (content.startsWith("$t ")) {
voice = "TypeCast";
@ -28,15 +29,18 @@ export default defineEvent("messageCreate", async (message) => {
voice = "Papago";
} else if (matched = content.match(/^\$s(\S*) /)) {
voice = "Supertonic";
let style: string | undefined = undefined
if (matched[1].length) {
style = matched[1]
options.supertonicStyleId = matched[1]
}
options = { supertonicStyleId: style };
} else if (content.match(/^\$\s/)) {
return;
}
if (profile.userSupertonicStyle.length) {
options.supertonicStyleId ??= profile.userSupertonicStyle;
}
options.supertonicStyleId ??= SUPERTONIC_DEFAULT_VOICE;
if (voice) {
content = content.replace(/^\$\S+\s+/, "")
} else {

View file

@ -99,7 +99,6 @@ export async function playVoice(
throw new Error(`Unknown voice type: ${voice}`);
}
VoiceQueue.fromConnection(connection).enqueue(
TTSModelBase.bufferToAudioResource(voiceBuffer)
);
@ -112,7 +111,7 @@ export async function playVoice(
export async function skipCurrentVoice(guild: Guild): Promise<boolean> {
let connection = await getOrCreateVoiceConnection(guild);
if (!connection)
throw new Error("Yaeju is not joined VoiceChat");
throw new Error("YaejuNyang is not joined VoiceChat");
const vqueue = VoiceQueue.fromConnection(connection);
if (vqueue.hasNext()) {

View file

@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = {
"clientVersion": "7.3.0",
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
"activeProvider": "postgresql",
"inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../packages/db/generated/prisma\"\n specifying = [\"prismaSchemaFolder\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel DiscordUserProfile {\n id String @id @default(cuid())\n userId String @unique\n voice Voice @default(Papago)\n nya Boolean @default(false)\n canTypecast Boolean @default(false)\n}\n\nmodel DiscordGuildProfile {\n id String @id @default(cuid())\n guildId String @unique\n readChannel String[] @default([])\n}\n\nenum Voice {\n TypeCast\n Papago\n Supertonic\n}\n",
"inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../packages/db/generated/prisma\"\n specifying = [\"prismaSchemaFolder\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel DiscordUserProfile {\n id String @id @default(cuid())\n userId String @unique\n voice Voice @default(Papago)\n nya Boolean @default(false)\n canTypecast Boolean @default(false)\n userSupertonicStyle String @default(\"\")\n}\n\nmodel DiscordGuildProfile {\n id String @id @default(cuid())\n guildId String @unique\n readChannel String[] @default([])\n}\n\nenum Voice {\n TypeCast\n Papago\n Supertonic\n}\n",
"runtimeDataModel": {
"models": {},
"enums": {},
@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = {
}
}
config.runtimeDataModel = JSON.parse("{\"models\":{\"DiscordUserProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"voice\",\"kind\":\"enum\",\"type\":\"Voice\"},{\"name\":\"nya\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"canTypecast\",\"kind\":\"scalar\",\"type\":\"Boolean\"}],\"dbName\":null},\"DiscordGuildProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"guildId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"readChannel\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
config.runtimeDataModel = JSON.parse("{\"models\":{\"DiscordUserProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"voice\",\"kind\":\"enum\",\"type\":\"Voice\"},{\"name\":\"nya\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"canTypecast\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"userSupertonicStyle\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null},\"DiscordGuildProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"guildId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"readChannel\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
const { Buffer } = await import('node:buffer')

View file

@ -597,7 +597,8 @@ export const DiscordUserProfileScalarFieldEnum = {
userId: 'userId',
voice: 'voice',
nya: 'nya',
canTypecast: 'canTypecast'
canTypecast: 'canTypecast',
userSupertonicStyle: 'userSupertonicStyle'
} as const
export type DiscordUserProfileScalarFieldEnum = (typeof DiscordUserProfileScalarFieldEnum)[keyof typeof DiscordUserProfileScalarFieldEnum]

View file

@ -76,7 +76,8 @@ export const DiscordUserProfileScalarFieldEnum = {
userId: 'userId',
voice: 'voice',
nya: 'nya',
canTypecast: 'canTypecast'
canTypecast: 'canTypecast',
userSupertonicStyle: 'userSupertonicStyle'
} as const
export type DiscordUserProfileScalarFieldEnum = (typeof DiscordUserProfileScalarFieldEnum)[keyof typeof DiscordUserProfileScalarFieldEnum]

View file

@ -30,6 +30,7 @@ export type DiscordUserProfileMinAggregateOutputType = {
voice: $Enums.Voice | null
nya: boolean | null
canTypecast: boolean | null
userSupertonicStyle: string | null
}
export type DiscordUserProfileMaxAggregateOutputType = {
@ -38,6 +39,7 @@ export type DiscordUserProfileMaxAggregateOutputType = {
voice: $Enums.Voice | null
nya: boolean | null
canTypecast: boolean | null
userSupertonicStyle: string | null
}
export type DiscordUserProfileCountAggregateOutputType = {
@ -46,6 +48,7 @@ export type DiscordUserProfileCountAggregateOutputType = {
voice: number
nya: number
canTypecast: number
userSupertonicStyle: number
_all: number
}
@ -56,6 +59,7 @@ export type DiscordUserProfileMinAggregateInputType = {
voice?: true
nya?: true
canTypecast?: true
userSupertonicStyle?: true
}
export type DiscordUserProfileMaxAggregateInputType = {
@ -64,6 +68,7 @@ export type DiscordUserProfileMaxAggregateInputType = {
voice?: true
nya?: true
canTypecast?: true
userSupertonicStyle?: true
}
export type DiscordUserProfileCountAggregateInputType = {
@ -72,6 +77,7 @@ export type DiscordUserProfileCountAggregateInputType = {
voice?: true
nya?: true
canTypecast?: true
userSupertonicStyle?: true
_all?: true
}
@ -153,6 +159,7 @@ export type DiscordUserProfileGroupByOutputType = {
voice: $Enums.Voice
nya: boolean
canTypecast: boolean
userSupertonicStyle: string
_count: DiscordUserProfileCountAggregateOutputType | null
_min: DiscordUserProfileMinAggregateOutputType | null
_max: DiscordUserProfileMaxAggregateOutputType | null
@ -182,6 +189,7 @@ export type DiscordUserProfileWhereInput = {
voice?: Prisma.EnumVoiceFilter<"DiscordUserProfile"> | $Enums.Voice
nya?: Prisma.BoolFilter<"DiscordUserProfile"> | boolean
canTypecast?: Prisma.BoolFilter<"DiscordUserProfile"> | boolean
userSupertonicStyle?: Prisma.StringFilter<"DiscordUserProfile"> | string
}
export type DiscordUserProfileOrderByWithRelationInput = {
@ -190,6 +198,7 @@ export type DiscordUserProfileOrderByWithRelationInput = {
voice?: Prisma.SortOrder
nya?: Prisma.SortOrder
canTypecast?: Prisma.SortOrder
userSupertonicStyle?: Prisma.SortOrder
}
export type DiscordUserProfileWhereUniqueInput = Prisma.AtLeast<{
@ -201,6 +210,7 @@ export type DiscordUserProfileWhereUniqueInput = Prisma.AtLeast<{
voice?: Prisma.EnumVoiceFilter<"DiscordUserProfile"> | $Enums.Voice
nya?: Prisma.BoolFilter<"DiscordUserProfile"> | boolean
canTypecast?: Prisma.BoolFilter<"DiscordUserProfile"> | boolean
userSupertonicStyle?: Prisma.StringFilter<"DiscordUserProfile"> | string
}, "id" | "userId">
export type DiscordUserProfileOrderByWithAggregationInput = {
@ -209,6 +219,7 @@ export type DiscordUserProfileOrderByWithAggregationInput = {
voice?: Prisma.SortOrder
nya?: Prisma.SortOrder
canTypecast?: Prisma.SortOrder
userSupertonicStyle?: Prisma.SortOrder
_count?: Prisma.DiscordUserProfileCountOrderByAggregateInput
_max?: Prisma.DiscordUserProfileMaxOrderByAggregateInput
_min?: Prisma.DiscordUserProfileMinOrderByAggregateInput
@ -223,6 +234,7 @@ export type DiscordUserProfileScalarWhereWithAggregatesInput = {
voice?: Prisma.EnumVoiceWithAggregatesFilter<"DiscordUserProfile"> | $Enums.Voice
nya?: Prisma.BoolWithAggregatesFilter<"DiscordUserProfile"> | boolean
canTypecast?: Prisma.BoolWithAggregatesFilter<"DiscordUserProfile"> | boolean
userSupertonicStyle?: Prisma.StringWithAggregatesFilter<"DiscordUserProfile"> | string
}
export type DiscordUserProfileCreateInput = {
@ -231,6 +243,7 @@ export type DiscordUserProfileCreateInput = {
voice?: $Enums.Voice
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: string
}
export type DiscordUserProfileUncheckedCreateInput = {
@ -239,6 +252,7 @@ export type DiscordUserProfileUncheckedCreateInput = {
voice?: $Enums.Voice
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: string
}
export type DiscordUserProfileUpdateInput = {
@ -247,6 +261,7 @@ export type DiscordUserProfileUpdateInput = {
voice?: Prisma.EnumVoiceFieldUpdateOperationsInput | $Enums.Voice
nya?: Prisma.BoolFieldUpdateOperationsInput | boolean
canTypecast?: Prisma.BoolFieldUpdateOperationsInput | boolean
userSupertonicStyle?: Prisma.StringFieldUpdateOperationsInput | string
}
export type DiscordUserProfileUncheckedUpdateInput = {
@ -255,6 +270,7 @@ export type DiscordUserProfileUncheckedUpdateInput = {
voice?: Prisma.EnumVoiceFieldUpdateOperationsInput | $Enums.Voice
nya?: Prisma.BoolFieldUpdateOperationsInput | boolean
canTypecast?: Prisma.BoolFieldUpdateOperationsInput | boolean
userSupertonicStyle?: Prisma.StringFieldUpdateOperationsInput | string
}
export type DiscordUserProfileCreateManyInput = {
@ -263,6 +279,7 @@ export type DiscordUserProfileCreateManyInput = {
voice?: $Enums.Voice
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: string
}
export type DiscordUserProfileUpdateManyMutationInput = {
@ -271,6 +288,7 @@ export type DiscordUserProfileUpdateManyMutationInput = {
voice?: Prisma.EnumVoiceFieldUpdateOperationsInput | $Enums.Voice
nya?: Prisma.BoolFieldUpdateOperationsInput | boolean
canTypecast?: Prisma.BoolFieldUpdateOperationsInput | boolean
userSupertonicStyle?: Prisma.StringFieldUpdateOperationsInput | string
}
export type DiscordUserProfileUncheckedUpdateManyInput = {
@ -279,6 +297,7 @@ export type DiscordUserProfileUncheckedUpdateManyInput = {
voice?: Prisma.EnumVoiceFieldUpdateOperationsInput | $Enums.Voice
nya?: Prisma.BoolFieldUpdateOperationsInput | boolean
canTypecast?: Prisma.BoolFieldUpdateOperationsInput | boolean
userSupertonicStyle?: Prisma.StringFieldUpdateOperationsInput | string
}
export type DiscordUserProfileCountOrderByAggregateInput = {
@ -287,6 +306,7 @@ export type DiscordUserProfileCountOrderByAggregateInput = {
voice?: Prisma.SortOrder
nya?: Prisma.SortOrder
canTypecast?: Prisma.SortOrder
userSupertonicStyle?: Prisma.SortOrder
}
export type DiscordUserProfileMaxOrderByAggregateInput = {
@ -295,6 +315,7 @@ export type DiscordUserProfileMaxOrderByAggregateInput = {
voice?: Prisma.SortOrder
nya?: Prisma.SortOrder
canTypecast?: Prisma.SortOrder
userSupertonicStyle?: Prisma.SortOrder
}
export type DiscordUserProfileMinOrderByAggregateInput = {
@ -303,6 +324,7 @@ export type DiscordUserProfileMinOrderByAggregateInput = {
voice?: Prisma.SortOrder
nya?: Prisma.SortOrder
canTypecast?: Prisma.SortOrder
userSupertonicStyle?: Prisma.SortOrder
}
export type StringFieldUpdateOperationsInput = {
@ -325,6 +347,7 @@ export type DiscordUserProfileSelect<ExtArgs extends runtime.Types.Extensions.In
voice?: boolean
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: boolean
}, ExtArgs["result"]["discordUserProfile"]>
export type DiscordUserProfileSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
@ -333,6 +356,7 @@ export type DiscordUserProfileSelectCreateManyAndReturn<ExtArgs extends runtime.
voice?: boolean
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: boolean
}, ExtArgs["result"]["discordUserProfile"]>
export type DiscordUserProfileSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
@ -341,6 +365,7 @@ export type DiscordUserProfileSelectUpdateManyAndReturn<ExtArgs extends runtime.
voice?: boolean
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: boolean
}, ExtArgs["result"]["discordUserProfile"]>
export type DiscordUserProfileSelectScalar = {
@ -349,9 +374,10 @@ export type DiscordUserProfileSelectScalar = {
voice?: boolean
nya?: boolean
canTypecast?: boolean
userSupertonicStyle?: boolean
}
export type DiscordUserProfileOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "voice" | "nya" | "canTypecast", ExtArgs["result"]["discordUserProfile"]>
export type DiscordUserProfileOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "voice" | "nya" | "canTypecast" | "userSupertonicStyle", ExtArgs["result"]["discordUserProfile"]>
export type $DiscordUserProfilePayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "DiscordUserProfile"
@ -362,6 +388,7 @@ export type $DiscordUserProfilePayload<ExtArgs extends runtime.Types.Extensions.
voice: $Enums.Voice
nya: boolean
canTypecast: boolean
userSupertonicStyle: string
}, ExtArgs["result"]["discordUserProfile"]>
composites: {}
}
@ -790,6 +817,7 @@ export interface DiscordUserProfileFieldRefs {
readonly voice: Prisma.FieldRef<"DiscordUserProfile", 'Voice'>
readonly nya: Prisma.FieldRef<"DiscordUserProfile", 'Boolean'>
readonly canTypecast: Prisma.FieldRef<"DiscordUserProfile", 'Boolean'>
readonly userSupertonicStyle: Prisma.FieldRef<"DiscordUserProfile", 'String'>
}

View file

@ -7,3 +7,13 @@ export const APPLICATION_ID = process.env.APPLICATION_ID as string;
export const GUILD_ID = process.env.GUILD_ID as string;
export const TYPECAST_TOKENS = (process.env.TYPECAST_TOKEN as string).split(",");
export const DATABASE_URL = process.env.DATABASE_URL as string;
export const SUPERTONIC_DEFAULT_VOICE = (process.env.SUPERTONIC_DEFAULT_VOICE as string | undefined) ?? "Q1";
export const SUPERTONIC_STYLE_LIST: { name: string, value: string }[] = (()=>{
const defaultValue = [
{ name: "여성1", value: "F1" },
];
try {
return JSON.parse(process.env.SUPERTONIC_STYLE_LIST ?? "null") as any ?? defaultValue
} catch {}
return defaultValue;
})();

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "DiscordUserProfile" ADD COLUMN "userSupertonicStyle" TEXT NOT NULL DEFAULT '';

View file

@ -14,6 +14,7 @@ model DiscordUserProfile {
voice Voice @default(Papago)
nya Boolean @default(false)
canTypecast Boolean @default(false)
userSupertonicStyle String @default("")
}
model DiscordGuildProfile {