aidol 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("@aioia/core"),t=require("./relationship-C1gG9SeQ.js"),l=require("zod");class h extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="aidols"}getDataSchema(){return t.aidolSchema}async createAIdol(e){const a=this.apiService.buildUrl(this.resource),i=await this.apiService.request(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return t.aidolCreateResponseSchema.parse(i.data)}async getMy(e){const a=this.apiService.buildUrl(`${this.resource}/my`),i=await this.apiService.request(a,e);return{data:t.aidolSchema.array().parse(i.data)}}async generateImage(e,a){const i=this.apiService.buildUrl(`${this.resource}/images`),o=await this.apiService.request(i,{...a,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return this.validateResponse(o,t.imageGenerationResponseSchema)}}const u=l.z.object({messageId:l.z.string(),content:l.z.string()});class b extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="chatrooms"}getDataSchema(){return t.chatroomSchema}async getMessages(e,a,i){const o=new URLSearchParams;a?.limit!==void 0&&o.set("limit",a.limit.toString()),a?.offset!==void 0&&o.set("offset",a.offset.toString());const r=o.toString(),d=this.apiService.buildUrl(`${this.resource}/${e}/messages${r?`?${r}`:""}`),p=await this.apiService.request(d,i);return this.validateResponse(p,l.z.array(t.messageSchema))}async sendMessage(e,a,i){const o=this.apiService.buildUrl(`${this.resource}/${e}/messages`),r=await this.apiService.request(o,{...i,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:a,senderType:"USER"})});return this.validateResponse(r,t.messageSchema)}async generateResponse(e,a,i){const o=this.apiService.buildUrl(`${this.resource}/${e}/companions/${a}/response`),r=await this.apiService.request(o,{...i,method:"POST",headers:{"Content-Type":"application/json"}});return this.validateResponse(r,u)}}class y extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="companion-relationships"}getDataSchema(){return t.companionRelationshipSchema}async getByFromCompanionId(e){return this.getList({filters:[{field:"from_companion_id",operator:"eq",value:e}]})}async deleteOne(e){const a=`${this.apiService.buildUrl(this.resource)}/${e.id}`;return await this.apiService.request(a,{method:"DELETE"}),{data:{}}}}class T extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="companions"}getDataSchema(){return t.companionSchema}async getByAidolId(e){return this.getList({filters:[{field:"aidol_id",operator:"eq",value:e}]})}async generateImage(e,a){const i=this.apiService.buildUrl(`${this.resource}/images`),o=await this.apiService.request(i,{...a,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return this.validateResponse(o,t.imageGenerationResponseSchema)}}class S extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="aidol-highlights"}getDataSchema(){return t.aidolHighlightSchema}async getByAidolId(e){return this.getList({filters:[{field:"aidol_id",operator:"eq",value:e}]})}async getMessages(e,a){const i=this.apiService.buildUrl(`${this.resource}/${e}/messages`),o=await this.apiService.request(i,a);return{data:t.highlightMessageSchema.array().parse(o)}}}class P{constructor(e){this.apiService=e,this.resource="leads"}async create(e){const a=this.apiService.buildUrl(this.resource),i=await this.apiService.request(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return l.z.object({data:t.leadResponseSchema}).parse(i).data}}const m="aidol_chatroom_ids",C=l.z.record(l.z.string(),l.z.string()),c=()=>{if(typeof window>"u")return{};const n=localStorage.getItem(m);if(!n)return{};try{const e=JSON.parse(n),a=C.safeParse(e);return a.success?a.data:(console.warn("[LocalChatroomIdsRepository] Invalid data, resetting"),{})}catch(e){if(e instanceof SyntaxError)return console.warn("[LocalChatroomIdsRepository] Failed to parse, resetting"),{};throw e}},g=n=>{if(typeof window>"u")throw new Error("LocalChatroomIdsRepository write operations can only be called on the client side.");localStorage.setItem(m,JSON.stringify(n))},R={getChatroomId(n){return c()[n]??null},setChatroomId(n,e){const a=c();a[n]=e,g(a)},removeChatroomId(n){const e=c();delete e[n],g(e)}};function f(n,e,a){if(!n)return a;const o=n.charAt(n.length-1).charCodeAt(0);if(o<44032||o>55203)return a;const r=(o-44032)%28;return e==="으로"&&a==="로"?r===0||r===8?"로":"으로":r===0?a:e}const k={load:{group:"Failed to load group info"}},A={close:"Close",save:"Save",saved:"Saved successfully.",deleted:"Deleted successfully.",error:{save:"Failed to save",load:"Failed to load data"}},M={home:"Home",explore:"Explore",myGroup:"My Group"},v={header:"Position Assignment",title:"Assign positions to each member!",subtitle:"Tap to assign a position",unassigned:"Unassigned",MAIN_VOCAL:"Main Vocal",SUB_VOCAL:"Sub Vocal",MAIN_DANCER:"Main Dancer",SUB_DANCER:"Sub Dancer",MAIN_RAPPER:"Main Rapper",SUB_RAPPER:"Sub Rapper",assignedTo:"{{position}}({{name}})",assign:"Assign",confirm:"Plan Group",needMore:"Assign positions to {{count}} more members",error:{load:"Failed to load members",update:"Failed to assign position"}},N={title:"Debut Member Casting",infoBanner:{title:"Cast your trainees",description:"The idol characters (face, voice, video) in this content are original virtual characters created by AI and are not based on any real person, including idols and celebrities."},tabs:{boy:"Boy Group",girl:"Girl Group",mixed:"Mixed Group"},newMember:{prompt:"Can't find a trainee you like?",subPrompt:"Try casting a new member"},addMember:"New Member",abilities:{title:"Abilities",vocal:"Vocal",dance:"Dance",rap:"Rap",visual:"Visual",stamina:"Stamina",charm:"Charm"},castButton:"Cast",castComplete:{title:"Casting Complete!",description:"The trainee has joined the group",viewBoard:"View Casting Board"},error:{cast:"Failed to cast"}},I="Share",w="URL copied!",E={header:"Final Debut Lineup",title:"My Casted Trainees!",subtitle:"Tap to remove",browse:"Browse Trainees",confirm:"Confirm Debut!",needMore:"Cast {{count}} more to create a group!",delete:"Remove",deleted:"Removed successfully.",empty:{title:`Final Debut Lineup
2
- is Empty`,description:"Cast your trainees!"},error:{load:"Failed to load members.",delete:"Failed to remove."}},G={title:"Trainee Casting Complete",subtitle:"Added to the casting candidate list",remainingSlots:"Remaining Casting Slots",findNext:"Find Next Trainee",viewBoard:"View Casting Board",error:{load:"Failed to load slot information"}},$={promptPlaceholder:"How does your idol talk? Describe their vibe...",addMember:"Add Member",signed:"Signed 🥺",grade:"Grade {{grade}}",tab:{profile:"Profile",stats:"Stats"},activity:{RESTING:"Resting",PRACTICING:"Practicing",SHORT_BREAK:"Short break",RESTING_AT_HOME:"Resting at home"}},B={notFound:"Group not found",members:"Members",noMembers:"No members yet"},L={groupName:"Group Name",groupNamePlaceholder:"e.g. DREAMERS, STARLIGHT",memberName:"Member Name",memberNamePlaceholder:"e.g. Luna, Kai",concept:"Concept",selectConcept:"Select a concept",personality:"Personality",concepts:{cute:"Cute",cool:"Cool",elegant:"Elegant",powerful:"Powerful"},personalities:{cheerful:{label:"Cheerful",description:"Always bright and positive"},cool:{label:"Cool",description:"Calm and collected"},tsundere:{label:"Tsundere",description:"Cold outside, warm inside"},gentle:{label:"Gentle",description:"Kind and caring"}},step1:"Group",step2:"Members",step3:"Done",step1Title:"Create Your Group",step2Title:"Add Members",groupNameRequired:"Please enter a group name",memberNameRequired:"Please enter a member name",memberRequired:"Please add at least one member",emblem:"Emblem",emblemPromptPlaceholder:"Describe your group's emblem...",emblemRequired:"Please generate an emblem image",generate:"Generate",next:"Next",back:"Back",create:"Create",completeTitle:"Your Idol is Ready!",completeDescription:"Start chatting with your dream idol now",viewProfile:"View Profile"},H={greeting1:"Hello!",greeting2:"We are {{name}}!",greeting3:"Nice to meet you",createAnother:"Create Another Group",share:"Share Profile",banner:"Curious about this group's next move?",error:{load:"Failed to load group info"}},D={header:"Enter Email",previewTitle:`Dorm stories, practice tales
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("@aioia/core"),t=require("./relationship-C1gG9SeQ.js"),l=require("zod");class h extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="aidols"}getDataSchema(){return t.aidolSchema}async createAIdol(e){const a=this.apiService.buildUrl(this.resource),i=await this.apiService.request(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return t.aidolCreateResponseSchema.parse(i.data)}async getMy(e){const a=this.apiService.buildUrl("me/aidols"),i=await this.apiService.request(a,e);return{data:t.aidolSchema.array().parse(i.data)}}async generateImage(e,a){const i=this.apiService.buildUrl(`${this.resource}/images`),o=await this.apiService.request(i,{...a,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return this.validateResponse(o,t.imageGenerationResponseSchema)}}const u=l.z.object({messageId:l.z.string(),content:l.z.string()});class b extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="chatrooms"}getDataSchema(){return t.chatroomSchema}async getMessages(e,a,i){const o=new URLSearchParams;a?.limit!==void 0&&o.set("limit",a.limit.toString()),a?.offset!==void 0&&o.set("offset",a.offset.toString());const r=o.toString(),d=this.apiService.buildUrl(`${this.resource}/${e}/messages${r?`?${r}`:""}`),p=await this.apiService.request(d,i);return this.validateResponse(p,l.z.array(t.messageSchema))}async sendMessage(e,a,i){const o=this.apiService.buildUrl(`${this.resource}/${e}/messages`),r=await this.apiService.request(o,{...i,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:a,senderType:"USER"})});return this.validateResponse(r,t.messageSchema)}async generateResponse(e,a,i){const o=this.apiService.buildUrl(`${this.resource}/${e}/companions/${a}/response`),r=await this.apiService.request(o,{...i,method:"POST",headers:{"Content-Type":"application/json"}});return this.validateResponse(r,u)}}class y extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="companion-relationships"}getDataSchema(){return t.companionRelationshipSchema}async getByFromCompanionId(e){return this.getList({filters:[{field:"from_companion_id",operator:"eq",value:e}]})}async deleteOne(e){const a=`${this.apiService.buildUrl(this.resource)}/${e.id}`;return await this.apiService.request(a,{method:"DELETE"}),{data:{}}}}class T extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="companions"}getDataSchema(){return t.companionSchema}async getByAidolId(e){return this.getList({filters:[{field:"aidol_id",operator:"eq",value:e}]})}async generateImage(e,a){const i=this.apiService.buildUrl(`${this.resource}/images`),o=await this.apiService.request(i,{...a,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return this.validateResponse(o,t.imageGenerationResponseSchema)}}class S extends s.BaseCrudRepository{constructor(){super(...arguments),this.resource="aidol-highlights"}getDataSchema(){return t.aidolHighlightSchema}async getByAidolId(e){return this.getList({filters:[{field:"aidol_id",operator:"eq",value:e}]})}async getMessages(e,a){const i=this.apiService.buildUrl(`${this.resource}/${e}/messages`),o=await this.apiService.request(i,a);return{data:t.highlightMessageSchema.array().parse(o)}}}class P{constructor(e){this.apiService=e,this.resource="leads"}async create(e){const a=this.apiService.buildUrl(this.resource),i=await this.apiService.request(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return l.z.object({data:t.leadResponseSchema}).parse(i).data}}const m="aidol_chatroom_ids",C=l.z.record(l.z.string(),l.z.string()),c=()=>{if(typeof window>"u")return{};const n=localStorage.getItem(m);if(!n)return{};try{const e=JSON.parse(n),a=C.safeParse(e);return a.success?a.data:(console.warn("[LocalChatroomIdsRepository] Invalid data, resetting"),{})}catch(e){if(e instanceof SyntaxError)return console.warn("[LocalChatroomIdsRepository] Failed to parse, resetting"),{};throw e}},g=n=>{if(typeof window>"u")throw new Error("LocalChatroomIdsRepository write operations can only be called on the client side.");localStorage.setItem(m,JSON.stringify(n))},R={getChatroomId(n){return c()[n]??null},setChatroomId(n,e){const a=c();a[n]=e,g(a)},removeChatroomId(n){const e=c();delete e[n],g(e)}};function f(n,e,a){if(!n)return a;const o=n.charAt(n.length-1).charCodeAt(0);if(o<44032||o>55203)return a;const r=(o-44032)%28;return e==="으로"&&a==="로"?r===0||r===8?"로":"으로":r===0?a:e}const k={load:{group:"Failed to load group info"}},A={close:"Close",save:"Save",saved:"Saved successfully.",deleted:"Deleted successfully.",error:{save:"Failed to save",load:"Failed to load data"}},M={home:"Home",explore:"Explore",myGroup:"My Group"},v={header:"Position Assignment",title:"Assign positions to each member!",subtitle:"Tap to assign a position",unassigned:"Unassigned",MAIN_VOCAL:"Main Vocal",SUB_VOCAL:"Sub Vocal",MAIN_DANCER:"Main Dancer",SUB_DANCER:"Sub Dancer",MAIN_RAPPER:"Main Rapper",SUB_RAPPER:"Sub Rapper",assignedTo:"{{position}}({{name}})",assign:"Assign",confirm:"Plan Group",needMore:"Assign positions to {{count}} more members",error:{load:"Failed to load members",update:"Failed to assign position"}},N={title:"Debut Member Casting",infoBanner:{title:"Cast your trainees",description:"The idol characters (face, voice, video) in this content are original virtual characters created by AI and are not based on any real person, including idols and celebrities."},tabs:{boy:"Boy Group",girl:"Girl Group",mixed:"Mixed Group"},newMember:{prompt:"Can't find a trainee you like?",subPrompt:"Try casting a new member"},addMember:"New Member",abilities:{title:"Abilities",vocal:"Vocal",dance:"Dance",rap:"Rap",visual:"Visual",stamina:"Stamina",charm:"Charm"},castButton:"Cast",castComplete:{title:"Casting Complete!",description:"The trainee has joined the group",viewBoard:"View Casting Board"},error:{cast:"Failed to cast"}},I="Share",w="URL copied!",E={header:"Final Debut Lineup",title:"My Casted Trainees!",subtitle:"Tap to remove",browse:"Browse Trainees",confirm:"Confirm Debut!",needMore:"Cast {{count}} more to create a group!",delete:"Remove",deleted:"Removed successfully.",empty:{title:`Final Debut Lineup
2
+ is Empty`,description:"Cast your trainees!"},error:{load:"Failed to load members.",delete:"Failed to remove."}},G={title:"Trainee Casting Complete",subtitle:"Added to the casting candidate list",remainingSlots:"Remaining Casting Slots",findNext:"Find Next Trainee",viewBoard:"View Casting Board",error:{load:"Failed to load slot information"}},B={promptPlaceholder:"How does your idol talk? Describe their vibe...",addMember:"Add Member",signed:"Signed 🥺",grade:"Grade {{grade}}",tab:{profile:"Profile",stats:"Stats"},activity:{RESTING:"Resting",PRACTICING:"Practicing",SHORT_BREAK:"Short break",RESTING_AT_HOME:"Resting at home"}},L={notFound:"Group not found",members:"Members",noMembers:"No members yet"},$={groupName:"Group Name",groupNamePlaceholder:"e.g. DREAMERS, STARLIGHT",memberName:"Member Name",memberNamePlaceholder:"e.g. Luna, Kai",concept:"Concept",selectConcept:"Select a concept",personality:"Personality",concepts:{cute:"Cute",cool:"Cool",elegant:"Elegant",powerful:"Powerful"},personalities:{cheerful:{label:"Cheerful",description:"Always bright and positive"},cool:{label:"Cool",description:"Calm and collected"},tsundere:{label:"Tsundere",description:"Cold outside, warm inside"},gentle:{label:"Gentle",description:"Kind and caring"}},step1:"Group",step2:"Members",step3:"Done",step1Title:"Create Your Group",step2Title:"Add Members",groupNameRequired:"Please enter a group name",memberNameRequired:"Please enter a member name",memberRequired:"Please add at least one member",emblem:"Emblem",emblemPromptPlaceholder:"Describe your group's emblem...",emblemRequired:"Please generate an emblem image",generate:"Generate",next:"Next",back:"Back",create:"Create",completeTitle:"Your Idol is Ready!",completeDescription:"Start chatting with your dream idol now",viewProfile:"View Profile"},H={greeting1:"Hello!",greeting2:"We are {{name}}!",greeting3:"Nice to meet you",createAnother:"Create Another Group",share:"Share Profile",banner:"Curious about this group's next move?",error:{load:"Failed to load group info"}},D={header:"Enter Email",previewTitle:`Dorm stories, practice tales
3
3
  We'll send you real reviews from members!`,previewMessage:"Shouldn't you talk to your hyung more respectfully?",title:"Stay Updated",description:"Get the latest news and updates about this group via email.",emailLabel:"Email",emailPlaceholder:"example@email.com",submit:"Get Updates",submitting:"Subscribing...",success:"Successfully subscribed!",error:"Failed to subscribe. Please try again."},_={header:"Group Planning",step1Title:"Name your group",step2Title:"Create your group emblem",namePlaceholder:"e.g.) Dreamers, Starlight",promptPlaceholder:"e.g.)",generate:"Generate Image",regenerate:"Regenerate Image",emptyImage:`Generated profile
4
4
  image will
5
5
  appear here`,next:"Next",error:{load:"Failed to load group info",generate:"Failed to generate image",update:"Failed to save group planning"}},x={title:"Debut Member Casting",next:"Next",error:{update:"Failed to save.",generateImage:"Failed to generate image.",load:"Failed to load trainees."},gender:{stepTitle:"Choose a gender",FEMALE:"Female",MALE:"Male"},personality:{stepTitle:"Tell us about the personality",energy:"Energy Direction",energyLeft:"Extrovert (E)",energyRight:"Introvert (I)",perception:"Perception Style",perceptionLeft:"Sensing (S)",perceptionRight:"Intuition (N)",judgment:"Judgment Basis",judgmentLeft:"Thinking (T)",judgmentRight:"Feeling (F)",lifestyle:"Lifestyle",lifestyleLeft:"Judging (J)",lifestyleRight:"Perceiving (P)"},image:{stepTitle:"Let's create a profile photo!",promptPlaceholder:"e.g.) A girl with black hair and big eyes",generate:"Generate Image",regenerate:"Regenerate Image",placeholder:`Generated profile
@@ -7,7 +7,7 @@ image will
7
7
  appear here`},complete:{nameStepTitle:"What is the name?",bioStepTitle:"Tell us this idol's story",namePlaceholder:"Enter a name",bioPlaceholder:"What journey have they been on?",button:"Complete Casting"}},K={header:"My Group",chatComingSoon:"Chat with members coming soon👋",settings:"Settings",highlights:"Highlights",empty:{title:"No groups yet",description:"Create your own AI idol group!",cta:"Create Idol"}},F={hero:{title:{line1:"Infinite Possibilities",line2:"The Birth of Idol Group"},line1:"Global fandom",line2:"casting and debuting",line3:"New AI Idol Group",line4:"Next Generation Project",cta:"Cast Trainees"},error:{create:"Failed to start."}},j={error:{load:"Failed to load highlight"}},V={title:"Season 1 Debut",chemistryButton:"Member Chemistry 💭",followButton:"Follow",highlightTab:"Highlights",follow:{header:"Follow",title:`We'll send you real stories
8
8
  from {{name}} members!`,previewMessage:"Shouldn't you talk to your hyung more respectfully?",emailPlaceholder:"Enter your email",submit:"Follow & Get Updates ✨",submitting:"Subscribing...",success:"You're now following!",error:"Failed to follow. Please try again.",loadError:"Failed to load group information"},error:{load:"Failed to load group information"}},O={infoBanner:{title:"Find a group you like!",description:"The idol characters (face, voice, video) in this content are original virtual characters created by AI and are not based on any real person, including idols and celebrities."},memberCount:"{{count}} members",error:{load:"Failed to load group list."}},q={header:"Member Chemistry",sectionTitle:"Member Chemistry Summary",sectionSubtitle:"Relationships affect chat content!",addRelationship:"Add Relationship",error:{load:"Failed to load member information"},add:{header:"Add Relationship",memberNotFound:"Member not found.",createRelationshipWith:"Create a relationship with {{name}}",selectedMemberPlaceholder:`Selected
9
9
  member here`,selectMember:"Select Member",relationshipType:"Relationship Type",types:{awkward:"Still Awkward",polite:"Polite",friendly:"Getting closer",tikitaka:"Tiki-Taka",trust:"Trust each other",emotional:"Emotionally close",bestFriend:"Best Friend",inseparable:"Inseparable"},intimacy:"Intimacy",startsAt:"Starts at <highlight>{{intimacy}}%</highlight>",relationshipNickname:"Relationship Nickname",nicknamePlaceholder:"e.g.) Squad, Besties"}},U={comingSoon:`Chat with {{name}}
10
- is coming soon!`,unlockHint:"Get closer to {{name}} to unlock other members 💖",greeting:"Chat freely with {{name}}!",placeholder:"Type a message",confirm:"OK",typing:"Typing...",thinkingLong:"Still thinking... 🥺",reload:"Reload",resend:"Resend",time:{justNow:"Just now",minutesAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",am:"AM",pm:"PM"}},J={error:k,common:A,navigation:M,position:v,casting:N,share:I,urlCopied:w,castingBoard:E,castingComplete:G,companion:$,aidol:B,creation:L,complete:H,newsletter:D,groupPlanning:_,companionCreate:x,myGroup:K,landing:F,highlight:j,group:V,groupList:O,chemistry:q,chat:U},z={load:{group:"Error al cargar la información del grupo"}},W={close:"Cerrar",save:"Guardar",saved:"Guardado correctamente.",deleted:"Eliminado correctamente.",error:{save:"Error al guardar",load:"Error al cargar los datos"}},Y={home:"Inicio",explore:"Explorar",myGroup:"Mi Grupo"},Q={header:"Asignación de Posición",title:"¡Asigna una posición a cada miembro!",subtitle:"Toca para asignar una posición",unassigned:"Sin asignar",MAIN_VOCAL:"Vocal Principal",SUB_VOCAL:"Vocal Secundario",MAIN_DANCER:"Bailarín Principal",SUB_DANCER:"Bailarín Secundario",MAIN_RAPPER:"Rapero Principal",SUB_RAPPER:"Rapero Secundario",assignedTo:"{{position}}({{name}})",assign:"Asignar",confirm:"Planificar Grupo",needMore:"Asigna posición a {{count}} miembros más",error:{load:"Error al cargar los miembros",update:"Error al asignar posición"}},X={title:"Casting de Debut",infoBanner:{title:"Haz casting a tus aprendices",description:"Los personajes idol (rostro, voz, video) de este contenido son personajes virtuales originales creados por IA y no están basados en personas reales, incluidos idols y celebridades."},tabs:{boy:"Grupo de Chicos",girl:"Grupo de Chicas",mixed:"Grupo Mixto"},newMember:{prompt:"¿No encuentras un aprendiz que te guste?",subPrompt:"Prueba a hacer casting de un nuevo miembro"},addMember:"Nuevo Miembro",abilities:{title:"Habilidades",vocal:"Vocal",dance:"Baile",rap:"Rap",visual:"Visual",stamina:"Resistencia",charm:"Carisma"},castButton:"Casting",castComplete:{title:"¡Casting Completo!",description:"El aprendiz se ha unido al grupo",viewBoard:"Ver Panel de Casting"},error:{cast:"Error al realizar el casting"}},Z="Compartir",ee="¡URL copiada!",ae={header:"Alineación Final de Debut",title:"¡Mis Trainees Elegidos!",subtitle:"Toca para eliminar",browse:"Ver Trainees",confirm:"¡Confirmar Debut!",needMore:"¡Elige {{count}} más para crear un grupo!",delete:"Eliminar",deleted:"Eliminado correctamente.",empty:{title:`La Alineación Final
10
+ is coming soon!`,unlockHint:"Get closer to {{name}} to unlock other members 💖",greeting:"Chat freely with {{name}}!",placeholder:"Type a message",confirm:"OK",typing:"Typing...",thinkingLong:"Still thinking... 🥺",reload:"Reload",resend:"Resend",time:{justNow:"Just now",minutesAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",am:"AM",pm:"PM"}},J={error:k,common:A,navigation:M,position:v,casting:N,share:I,urlCopied:w,castingBoard:E,castingComplete:G,companion:B,aidol:L,creation:$,complete:H,newsletter:D,groupPlanning:_,companionCreate:x,myGroup:K,landing:F,highlight:j,group:V,groupList:O,chemistry:q,chat:U},z={load:{group:"Error al cargar la información del grupo"}},W={close:"Cerrar",save:"Guardar",saved:"Guardado correctamente.",deleted:"Eliminado correctamente.",error:{save:"Error al guardar",load:"Error al cargar los datos"}},Y={home:"Inicio",explore:"Explorar",myGroup:"Mi Grupo"},Q={header:"Asignación de Posición",title:"¡Asigna una posición a cada miembro!",subtitle:"Toca para asignar una posición",unassigned:"Sin asignar",MAIN_VOCAL:"Vocal Principal",SUB_VOCAL:"Vocal Secundario",MAIN_DANCER:"Bailarín Principal",SUB_DANCER:"Bailarín Secundario",MAIN_RAPPER:"Rapero Principal",SUB_RAPPER:"Rapero Secundario",assignedTo:"{{position}}({{name}})",assign:"Asignar",confirm:"Planificar Grupo",needMore:"Asigna posición a {{count}} miembros más",error:{load:"Error al cargar los miembros",update:"Error al asignar posición"}},X={title:"Casting de Debut",infoBanner:{title:"Haz casting a tus aprendices",description:"Los personajes idol (rostro, voz, video) de este contenido son personajes virtuales originales creados por IA y no están basados en personas reales, incluidos idols y celebridades."},tabs:{boy:"Grupo de Chicos",girl:"Grupo de Chicas",mixed:"Grupo Mixto"},newMember:{prompt:"¿No encuentras un aprendiz que te guste?",subPrompt:"Prueba a hacer casting de un nuevo miembro"},addMember:"Nuevo Miembro",abilities:{title:"Habilidades",vocal:"Vocal",dance:"Baile",rap:"Rap",visual:"Visual",stamina:"Resistencia",charm:"Carisma"},castButton:"Casting",castComplete:{title:"¡Casting Completo!",description:"El aprendiz se ha unido al grupo",viewBoard:"Ver Panel de Casting"},error:{cast:"Error al realizar el casting"}},Z="Compartir",ee="¡URL copiada!",ae={header:"Alineación Final de Debut",title:"¡Mis Trainees Elegidos!",subtitle:"Toca para eliminar",browse:"Ver Trainees",confirm:"¡Confirmar Debut!",needMore:"¡Elige {{count}} más para crear un grupo!",delete:"Eliminar",deleted:"Eliminado correctamente.",empty:{title:`La Alineación Final
11
11
  está Vacía`,description:"¡Elige a tus trainees!"},error:{load:"Error al cargar los miembros.",delete:"Error al eliminar."}},te={title:"Casting de Trainee Completado",subtitle:"Agregado a la lista de candidatos",remainingSlots:"Slots de Casting Restantes",findNext:"Buscar Siguiente Trainee",viewBoard:"Ver Tablero de Casting",error:{load:"Error al cargar la información de slots"}},ne={promptPlaceholder:"¿Cómo habla tu idol? Describe su personalidad...",addMember:"Añadir Miembro",signed:"Firmado 🥺",grade:"Grado {{grade}}",tab:{profile:"Perfil",stats:"Estadísticas"},activity:{RESTING:"Descansando",PRACTICING:"Practicando",SHORT_BREAK:"Descanso breve",RESTING_AT_HOME:"Descansando en casa"}},ie={notFound:"Grupo no encontrado",members:"Miembros",noMembers:"Aún no hay miembros"},oe={groupName:"Nombre del Grupo",groupNamePlaceholder:"ej: DREAMERS, STARLIGHT",memberName:"Nombre del Miembro",memberNamePlaceholder:"ej: Luna, Kai",concept:"Concepto",selectConcept:"Selecciona un concepto",personality:"Personalidad",concepts:{cute:"Lindo",cool:"Genial",elegant:"Elegante",powerful:"Poderoso"},personalities:{cheerful:{label:"Alegre",description:"Siempre brillante y positivo"},cool:{label:"Genial",description:"Tranquilo y sereno"},tsundere:{label:"Tsundere",description:"Frío por fuera, cálido por dentro"},gentle:{label:"Amable",description:"Bondadoso y cariñoso"}},step1:"Grupo",step2:"Miembros",step3:"Listo",step1Title:"Crea Tu Grupo",step2Title:"Añade Miembros",groupNameRequired:"Por favor ingresa un nombre de grupo",memberNameRequired:"Por favor ingresa un nombre de miembro",memberRequired:"Por favor añade al menos un miembro",emblem:"Emblema",emblemPromptPlaceholder:"Describe el emblema de tu grupo...",emblemRequired:"Por favor genera una imagen de emblema",generate:"Generar",next:"Siguiente",back:"Atrás",create:"Crear",completeTitle:"¡Tu Idol Está Listo!",completeDescription:"Empieza a chatear con tu idol soñado ahora",viewProfile:"Ver Perfil"},re={greeting1:"¡Hola!",greeting2:"¡Somos {{name}}!",greeting3:"Encantados de conocerte",createAnother:"Crear Otro Grupo",share:"Compartir Perfil",banner:"¿Curioso sobre el próximo paso del grupo?",error:{load:"Error al cargar la información del grupo"}},le={header:"Ingresa tu Correo",previewTitle:`Historias del dormitorio debut, historias de práctica
12
12
  ¡Te enviaremos reseñas reales de los miembros!`,previewMessage:"¿No deberías hablarle con más respeto a tu hyung?",title:"Mantente Informado",description:"Recibe las últimas noticias y actualizaciones de este grupo por correo.",emailLabel:"Correo electrónico",emailPlaceholder:"ejemplo@email.com",submit:"Recibir Noticias",submitting:"Suscribiendo...",success:"¡Suscripción exitosa!",error:"Error al suscribirse. Inténtalo de nuevo."},se={header:"Planificación del Grupo",step1Title:"Nombra tu grupo",step2Title:"Crea el emblema del grupo",namePlaceholder:"ej.) Dreamers, Starlight",promptPlaceholder:"ej.)",generate:"Generar Imagen",regenerate:"Regenerar Imagen",emptyImage:`La imagen del perfil
13
13
  generada aparecerá
@@ -20,12 +20,12 @@ se abrirá pronto!`,unlockHint:"Acércate más a {{name}} para conocer a otros m
20
20
  Masih Kosong`,description:"Yuk pilih trainee!"},error:{load:"Gagal memuat info anggota.",delete:"Gagal menghapus."}},Me={title:"Casting Trainee Selesai",subtitle:"Ditambahkan ke daftar kandidat casting",remainingSlots:"Slot Casting Tersisa",findNext:"Cari Trainee Berikutnya",viewBoard:"Lihat Papan Casting",error:{load:"Gagal memuat informasi slot"}},ve={promptPlaceholder:"Gimana idol kamu ngobrol? Ceritain kepribadiannya...",addMember:"Tambah Anggota",signed:"Sudah Dikontrak 🥺",grade:"Grade {{grade}}",tab:{profile:"Profil",stats:"Statistik"},activity:{RESTING:"Istirahat",PRACTICING:"Berlatih",SHORT_BREAK:"Istirahat sebentar",RESTING_AT_HOME:"Istirahat di rumah"}},Ne={notFound:"Grup tidak ditemukan",members:"Anggota",noMembers:"Belum ada anggota"},Ie={groupName:"Nama Grup",groupNamePlaceholder:"cth: DREAMERS, STARLIGHT",memberName:"Nama Anggota",memberNamePlaceholder:"cth: Luna, Kai",concept:"Konsep",selectConcept:"Pilih konsep",personality:"Kepribadian",concepts:{cute:"Imut",cool:"Keren",elegant:"Elegan",powerful:"Kuat"},personalities:{cheerful:{label:"Ceria",description:"Selalu cerah dan positif"},cool:{label:"Keren",description:"Tenang dan kalem"},tsundere:{label:"Tsundere",description:"Dingin di luar, hangat di dalam"},gentle:{label:"Lembut",description:"Baik hati dan perhatian"}},step1:"Grup",step2:"Anggota",step3:"Selesai",step1Title:"Buat Grup Kamu",step2Title:"Tambah Anggota",groupNameRequired:"Masukkan nama grup",memberNameRequired:"Masukkan nama anggota",memberRequired:"Tambahkan minimal satu anggota",emblem:"Emblem",emblemPromptPlaceholder:"Deskripsikan emblem grup kamu...",emblemRequired:"Buat gambar emblem dulu",generate:"Buat",next:"Lanjut",back:"Kembali",create:"Buat",completeTitle:"Idol Kamu Siap!",completeDescription:"Langsung ngobrol sama idol impianmu sekarang",viewProfile:"Lihat Profil"},we={greeting1:"Halo!",greeting2:"Kami {{name}}!",greeting3:"Senang berkenalan",createAnother:"Buat Grup Lain",share:"Bagikan Profil",banner:"Penasaran dengan langkah selanjutnya grup ini?",error:{load:"Gagal memuat info grup"}},Ee={header:"Masukkan Email",previewTitle:`Cerita asrama debut, cerita latihan
21
21
  Kami akan kirimkan ulasan nyata dari para anggota!`,previewMessage:"Bukankah kamu harus bicara lebih sopan ke kakak?",title:"Dapatkan Info Terbaru",description:"Terima berita dan update terbaru tentang grup ini via email.",emailLabel:"Email",emailPlaceholder:"contoh@email.com",submit:"Terima Kabar",submitting:"Mendaftar...",success:"Berhasil berlangganan!",error:"Gagal berlangganan. Coba lagi."},Ge={header:"Perencanaan Grup",step1Title:"Beri nama grupmu",step2Title:"Buat emblem grup",namePlaceholder:"cth.) Dreamers, Starlight",promptPlaceholder:"cth.)",generate:"Buat Gambar",regenerate:"Buat Ulang Gambar",emptyImage:`Gambar profil
22
22
  yang dibuat akan
23
- muncul di sini`,next:"Selanjutnya",error:{load:"Gagal memuat info grup",generate:"Gagal membuat gambar",update:"Gagal menyimpan perencanaan grup"}},$e={title:"Casting Member Debut",next:"Lanjut",error:{update:"Gagal menyimpan.",generateImage:"Gagal membuat gambar.",load:"Gagal memuat daftar trainee."},gender:{stepTitle:"Pilih jenis kelamin",FEMALE:"Perempuan",MALE:"Laki-laki"},personality:{stepTitle:"Ceritakan kepribadiannya",energy:"Arah Energi",energyLeft:"Ekstrovert (E)",energyRight:"Introvert (I)",perception:"Gaya Persepsi",perceptionLeft:"Sensing (S)",perceptionRight:"Intuisi (N)",judgment:"Dasar Penilaian",judgmentLeft:"Pemikiran (T)",judgmentRight:"Perasaan (F)",lifestyle:"Gaya Hidup",lifestyleLeft:"Penilaian (J)",lifestyleRight:"Persepsi (P)"},image:{stepTitle:"Yuk buat foto profil!",promptPlaceholder:"cth) Gadis berambut hitam dengan mata besar",generate:"Buat Gambar",regenerate:"Buat Ulang Gambar",placeholder:`Gambar profil
23
+ muncul di sini`,next:"Selanjutnya",error:{load:"Gagal memuat info grup",generate:"Gagal membuat gambar",update:"Gagal menyimpan perencanaan grup"}},Be={title:"Casting Member Debut",next:"Lanjut",error:{update:"Gagal menyimpan.",generateImage:"Gagal membuat gambar.",load:"Gagal memuat daftar trainee."},gender:{stepTitle:"Pilih jenis kelamin",FEMALE:"Perempuan",MALE:"Laki-laki"},personality:{stepTitle:"Ceritakan kepribadiannya",energy:"Arah Energi",energyLeft:"Ekstrovert (E)",energyRight:"Introvert (I)",perception:"Gaya Persepsi",perceptionLeft:"Sensing (S)",perceptionRight:"Intuisi (N)",judgment:"Dasar Penilaian",judgmentLeft:"Pemikiran (T)",judgmentRight:"Perasaan (F)",lifestyle:"Gaya Hidup",lifestyleLeft:"Penilaian (J)",lifestyleRight:"Persepsi (P)"},image:{stepTitle:"Yuk buat foto profil!",promptPlaceholder:"cth) Gadis berambut hitam dengan mata besar",generate:"Buat Gambar",regenerate:"Buat Ulang Gambar",placeholder:`Gambar profil
24
24
  yang dibuat
25
- akan muncul di sini`},complete:{nameStepTitle:"Siapa namanya?",bioStepTitle:"Ceritakan kisah idol ini",namePlaceholder:"Masukkan nama",bioPlaceholder:"Perjalanan apa yang telah dilalui?",button:"Selesai Casting"}},Be={header:"Grup Saya",chatComingSoon:"Chat dengan member segera hadir👋",settings:"Pengaturan",highlights:"Sorotan",empty:{title:"Belum ada grup",description:"Buat grup idol AI-mu sendiri!",cta:"Buat Idol"}},Le={hero:{title:{line1:"Kemungkinan Tak Terbatas",line2:"Kelahiran Grup Idol"},line1:"Fandom global",line2:"casting dan mendebut",line3:"Grup Idol AI Baru",line4:"Proyek Generasi Berikutnya",cta:"Casting Trainee"},error:{create:"Gagal memulai."}},He={error:{load:"Gagal memuat highlight"}},De={title:"Debut Musim 1",chemistryButton:"Kimia Antar Anggota 💭",followButton:"Ikuti",highlightTab:"Sorotan",follow:{header:"Ikuti",title:`Kami akan mengirimkan cerita nyata
25
+ akan muncul di sini`},complete:{nameStepTitle:"Siapa namanya?",bioStepTitle:"Ceritakan kisah idol ini",namePlaceholder:"Masukkan nama",bioPlaceholder:"Perjalanan apa yang telah dilalui?",button:"Selesai Casting"}},Le={header:"Grup Saya",chatComingSoon:"Chat dengan member segera hadir👋",settings:"Pengaturan",highlights:"Sorotan",empty:{title:"Belum ada grup",description:"Buat grup idol AI-mu sendiri!",cta:"Buat Idol"}},$e={hero:{title:{line1:"Kemungkinan Tak Terbatas",line2:"Kelahiran Grup Idol"},line1:"Fandom global",line2:"casting dan mendebut",line3:"Grup Idol AI Baru",line4:"Proyek Generasi Berikutnya",cta:"Casting Trainee"},error:{create:"Gagal memulai."}},He={error:{load:"Gagal memuat highlight"}},De={title:"Debut Musim 1",chemistryButton:"Kimia Antar Anggota 💭",followButton:"Ikuti",highlightTab:"Sorotan",follow:{header:"Ikuti",title:`Kami akan mengirimkan cerita nyata
26
26
  dari anggota {{name}}!`,previewMessage:"Bukankah seharusnya kamu bicara lebih sopan pada hyung?",emailPlaceholder:"Masukkan email Anda",submit:"Ikuti & Dapatkan Info ✨",submitting:"Berlangganan...",success:"Anda sekarang mengikuti!",error:"Gagal mengikuti. Silakan coba lagi.",loadError:"Gagal memuat informasi grup"},error:{load:"Gagal memuat informasi grup"}},_e={infoBanner:{title:"Temukan grup yang kamu suka!",description:"Karakter idol (wajah, suara, video) dalam konten ini adalah karakter virtual asli yang dibuat oleh AI dan tidak berdasarkan orang nyata, termasuk idol dan selebriti."},memberCount:"{{count}} anggota",error:{load:"Gagal memuat daftar grup."}},xe={header:"Kimia Antar Anggota",sectionTitle:"Ringkasan Kimia Anggota",sectionSubtitle:"Hubungan memengaruhi konten obrolan!",addRelationship:"Tambah Hubungan",error:{load:"Gagal memuat informasi anggota"},add:{header:"Tambah Hubungan",memberNotFound:"Anggota tidak ditemukan.",createRelationshipWith:"Buat hubungan dengan {{name}}",selectedMemberPlaceholder:`Anggota
27
27
  terpilih`,selectMember:"Pilih Anggota",relationshipType:"Jenis Hubungan",types:{awkward:"Masih Canggung",polite:"Sopan",friendly:"Mulai akrab",tikitaka:"Tiki-Taka",trust:"Saling percaya",emotional:"Dekat secara emosional",bestFriend:"Sahabat",inseparable:"Tak Terpisahkan"},intimacy:"Keintiman",startsAt:"Mulai dari <highlight>{{intimacy}}%</highlight>",relationshipNickname:"Nama Panggilan Hubungan",nicknamePlaceholder:"cth.) Squad, Besties"}},Ke={comingSoon:`Obrolan dengan {{name}}
28
- akan segera dibuka!`,unlockHint:"Berteman lebih dekat dengan {{name}} untuk bertemu anggota lain 💖",greeting:"Ngobrol bebas dengan {{name}}!",placeholder:"Ketik pesan",confirm:"OK",typing:"Mengetik...",thinkingLong:"Masih berpikir 🥺",reload:"Muat ulang",resend:"Kirim ulang",time:{justNow:"Baru saja",minutesAgo:"{{count}} menit lalu",hoursAgo:"{{count}} jam lalu",am:"AM",pm:"PM"}},Fe={error:Te,common:Se,navigation:Pe,position:Ce,casting:Re,share:fe,urlCopied:ke,castingBoard:Ae,castingComplete:Me,companion:ve,aidol:Ne,creation:Ie,complete:we,newsletter:Ee,groupPlanning:Ge,companionCreate:$e,myGroup:Be,landing:Le,highlight:He,group:De,groupList:_e,chemistry:xe,chat:Ke},je={load:{group:"グループ情報の読み込みに失敗しました"}},Ve={close:"閉じる",save:"保存",saved:"保存しました。",deleted:"削除しました。",error:{save:"保存に失敗しました",load:"データの読み込みに失敗しました"}},Oe={home:"ホーム",explore:"発見",myGroup:"マイグループ"},qe={header:"ポジション配置",title:"メンバーにポジションを配置しよう!",subtitle:"タップしてポジションを配置できます",unassigned:"未配置",MAIN_VOCAL:"メインボーカル",SUB_VOCAL:"サブボーカル",MAIN_DANCER:"メインダンサー",SUB_DANCER:"サブダンサー",MAIN_RAPPER:"メインラッパー",SUB_RAPPER:"サブラッパー",assignedTo:"{{position}}({{name}})",assign:"配置する",confirm:"グループを企画する",needMore:"あと{{count}}人のポジションを配置してください",error:{load:"メンバー一覧の読み込みに失敗しました",update:"ポジションの配置に失敗しました"}},Ue={title:"デビューメンバーキャスティング",infoBanner:{title:"練習生をキャスティングしましょう",description:"本コンテンツのアイドルキャラクター(顔・声・映像)はAIで制作されたオリジナルの仮想人物であり、実在の人物(アイドル/芸能人を含む)に基づいていません。"},tabs:{boy:"ボーイグループ",girl:"ガールグループ",mixed:"混合グループ"},newMember:{prompt:"お気に入りの練習生がいませんか?",subPrompt:"新しいメンバーをキャスティングしてみましょう"},addMember:"新メンバー",abilities:{title:"能力値",vocal:"ボーカル",dance:"ダンス",rap:"ラップ",visual:"ビジュアル",stamina:"スタミナ",charm:"魅力"},castButton:"キャスティング",castComplete:{title:"キャスティング完了!",description:"練習生がグループに合流しました",viewBoard:"キャスティングボードを見る"},error:{cast:"キャスティングに失敗しました"}},Je="共有",ze="URLがコピーされました!",We={header:"最終デビュー組ラインナップ",title:"私がキャスティングした練習生!",subtitle:"タップして削除できます",browse:"練習生を見る",confirm:"デビュー組確定!",needMore:"あと{{count}}人キャスティングするとグループが作れます!",delete:"削除",deleted:"削除されました。",empty:{title:`最終デビュー組ラインナップが
28
+ akan segera dibuka!`,unlockHint:"Berteman lebih dekat dengan {{name}} untuk bertemu anggota lain 💖",greeting:"Ngobrol bebas dengan {{name}}!",placeholder:"Ketik pesan",confirm:"OK",typing:"Mengetik...",thinkingLong:"Masih berpikir 🥺",reload:"Muat ulang",resend:"Kirim ulang",time:{justNow:"Baru saja",minutesAgo:"{{count}} menit lalu",hoursAgo:"{{count}} jam lalu",am:"AM",pm:"PM"}},Fe={error:Te,common:Se,navigation:Pe,position:Ce,casting:Re,share:fe,urlCopied:ke,castingBoard:Ae,castingComplete:Me,companion:ve,aidol:Ne,creation:Ie,complete:we,newsletter:Ee,groupPlanning:Ge,companionCreate:Be,myGroup:Le,landing:$e,highlight:He,group:De,groupList:_e,chemistry:xe,chat:Ke},je={load:{group:"グループ情報の読み込みに失敗しました"}},Ve={close:"閉じる",save:"保存",saved:"保存しました。",deleted:"削除しました。",error:{save:"保存に失敗しました",load:"データの読み込みに失敗しました"}},Oe={home:"ホーム",explore:"発見",myGroup:"マイグループ"},qe={header:"ポジション配置",title:"メンバーにポジションを配置しよう!",subtitle:"タップしてポジションを配置できます",unassigned:"未配置",MAIN_VOCAL:"メインボーカル",SUB_VOCAL:"サブボーカル",MAIN_DANCER:"メインダンサー",SUB_DANCER:"サブダンサー",MAIN_RAPPER:"メインラッパー",SUB_RAPPER:"サブラッパー",assignedTo:"{{position}}({{name}})",assign:"配置する",confirm:"グループを企画する",needMore:"あと{{count}}人のポジションを配置してください",error:{load:"メンバー一覧の読み込みに失敗しました",update:"ポジションの配置に失敗しました"}},Ue={title:"デビューメンバーキャスティング",infoBanner:{title:"練習生をキャスティングしましょう",description:"本コンテンツのアイドルキャラクター(顔・声・映像)はAIで制作されたオリジナルの仮想人物であり、実在の人物(アイドル/芸能人を含む)に基づいていません。"},tabs:{boy:"ボーイグループ",girl:"ガールグループ",mixed:"混合グループ"},newMember:{prompt:"お気に入りの練習生がいませんか?",subPrompt:"新しいメンバーをキャスティングしてみましょう"},addMember:"新メンバー",abilities:{title:"能力値",vocal:"ボーカル",dance:"ダンス",rap:"ラップ",visual:"ビジュアル",stamina:"スタミナ",charm:"魅力"},castButton:"キャスティング",castComplete:{title:"キャスティング完了!",description:"練習生がグループに合流しました",viewBoard:"キャスティングボードを見る"},error:{cast:"キャスティングに失敗しました"}},Je="共有",ze="URLがコピーされました!",We={header:"最終デビュー組ラインナップ",title:"私がキャスティングした練習生!",subtitle:"タップして削除できます",browse:"練習生を見る",confirm:"デビュー組確定!",needMore:"あと{{count}}人キャスティングするとグループが作れます!",delete:"削除",deleted:"削除されました。",empty:{title:`最終デビュー組ラインナップが
29
29
  空です`,description:"アイドルをキャスティングしてみよう!"},error:{load:"メンバー情報の読み込みに失敗しました。",delete:"削除に失敗しました。"}},Ye={title:"練習生キャスティング完了",subtitle:"候補リストに追加されました",remainingSlots:"残りキャスティングスロット",findNext:"次の練習生を探す",viewBoard:"キャスティングボードを見る",error:{load:"スロット情報の読み込みに失敗しました"}},Qe={promptPlaceholder:"どんな話し方をする?性格を教えてね...",addMember:"メンバー追加",signed:"契約完了 🥺",grade:"{{grade}} ランク",tab:{profile:"プロフィール",stats:"能力値"},activity:{RESTING:"休憩中",PRACTICING:"練習中",SHORT_BREAK:"小休憩中",RESTING_AT_HOME:"自宅で休憩中"}},Xe={notFound:"グループが見つかりません",members:"メンバー",noMembers:"まだメンバーがいません"},Ze={groupName:"グループ名",groupNamePlaceholder:"例: DREAMERS, STARLIGHT",memberName:"メンバー名",memberNamePlaceholder:"例: ルナ, カイ",concept:"コンセプト",selectConcept:"コンセプトを選択",personality:"性格",concepts:{cute:"キュート",cool:"クール",elegant:"エレガント",powerful:"パワフル"},personalities:{cheerful:{label:"明るい",description:"いつも元気でポジティブ"},cool:{label:"クール",description:"冷静で落ち着いている"},tsundere:{label:"ツンデレ",description:"外は冷たく中は温かい"},gentle:{label:"優しい",description:"親切で思いやりがある"}},step1:"グループ",step2:"メンバー",step3:"完了",step1Title:"グループを作ろう",step2Title:"メンバーを追加",groupNameRequired:"グループ名を入力してください",memberNameRequired:"メンバー名を入力してください",memberRequired:"メンバーを1人以上追加してください",emblem:"エンブレム",emblemPromptPlaceholder:"グループのエンブレムを説明してください...",emblemRequired:"エンブレム画像を生成してください",generate:"生成",next:"次へ",back:"戻る",create:"作成",completeTitle:"アイドル完成!",completeDescription:"さっそく推しと会話しよう",viewProfile:"プロフィールを見る"},ea={greeting1:"こんにちは!",greeting2:"{{name}}です!",greeting3:"よろしくお願いします",createAnother:"別のグループを作成",share:"プロフィールを共有",banner:"このグループの次の動きが気になりますか?",error:{load:"グループ情報の読み込みに失敗しました"}},aa={header:"メールアドレス入力",previewTitle:`デビュー組の寮話、練習話
30
30
  メンバーのリアルな声を
31
31
  お届けします!`,previewMessage:"先輩にそんな言い方しちゃダメじゃない?",title:"最新情報を受け取る",description:"このグループの最新ニュースやアップデートをメールで受け取りましょう。",emailLabel:"メールアドレス",emailPlaceholder:"example@email.com",submit:"ニュースを受け取る",submitting:"購読中...",success:"購読が完了しました!",error:"購読に失敗しました。もう一度お試しください。"},ta={header:"グループ企画",step1Title:"グループの名前を決めてください",step2Title:"グループのエンブレムを作成してください",namePlaceholder:"例)ドリーマーズ、スターライト",promptPlaceholder:"例)",generate:"画像生成",regenerate:"画像再生成",emptyImage:`生成されたプロフィール
@@ -42,9 +42,9 @@ akan segera dibuka!`,unlockHint:"Berteman lebih dekat dengan {{name}} untuk bert
42
42
  표시돼요`,next:"다음",error:{load:"그룹 정보를 불러오지 못했습니다",generate:"이미지 생성에 실패했습니다",update:"그룹 기획 저장에 실패했습니다"}},va={title:"데뷔 멤버 캐스팅",next:"다음",error:{update:"저장에 실패했습니다.",generateImage:"이미지 생성에 실패했습니다.",load:"연습생 목록을 불러오는데 실패했습니다."},gender:{stepTitle:"성별을 정해주세요",FEMALE:"여성",MALE:"남성"},personality:{stepTitle:"성격을 알려주세요",energy:"에너지 방향",energyLeft:"외향 (E)",energyRight:"내향 (I)",perception:"정보 인식 방식",perceptionLeft:"직관 (S)",perceptionRight:"감각 (N)",judgment:"판단 기준",judgmentLeft:"사고 (T)",judgmentRight:"감정 (F)",lifestyle:"생활 방식",lifestyleLeft:"인식형 (J)",lifestyleRight:"판단형 (P)"},image:{stepTitle:"프로필 사진을 만들어볼까요?",promptPlaceholder:"예) 검은 머리에 큰 눈을 가진 소녀",generate:"이미지 생성",regenerate:"이미지 재생성",placeholder:`생성된 프로필
43
43
  이미지가
44
44
  표시돼요`},complete:{nameStepTitle:"이름은 무엇인가요?",bioStepTitle:"이 아이돌의 서사를 알려주세요",namePlaceholder:"이름을 입력해주세요",bioPlaceholder:"어떤 시간을 보냈나요?",button:"캐스팅 완료"}},Na={header:"내 그룹",chatComingSoon:"멤버들과 채팅 준비중👋",settings:"설정",highlights:"하이라이트",empty:{title:"아직 만든 그룹이 없어요",description:"나만의 AI 아이돌 그룹을 만들어보세요!",cta:"아이돌 만들기"}},Ia={hero:{title:{line1:"무한한 가능성의",line2:"아이돌 그룹의 탄생"},line1:"글로벌 팬덤이",line2:"직접 캐스팅하고 데뷔시키는",line3:"신인 AI 아이돌 그룹",line4:"넥스트 제너레이션 프로젝트",cta:"연습생 캐스팅하기"},error:{create:"시작에 실패했습니다."}},wa={error:{load:"하이라이트를 불러오지 못했습니다"}},Ea={title:"시즌1 데뷔조",chemistryButton:"멤버 간 케미 💭",followButton:"팔로우",highlightTab:"하이라이트",follow:{header:"팔로우",title:`{{name}} 멤버들의
45
- 리얼한 이야기를 보내드려요!`,previewMessage:"형한테 그런식으로 말하면 안되지 않을까?",emailPlaceholder:"이메일을 입력해주세요",submit:"팔로잉 하고 소식 받기 ✨",submitting:"구독 중...",success:"팔로잉이 완료되었습니다!",error:"팔로잉에 실패했습니다. 다시 시도해주세요.",loadError:"그룹 정보를 불러오지 못했습니다"},error:{load:"그룹 정보를 불러오지 못했습니다"}},Ga={infoBanner:{title:"원하는 그룹을 찾아보세요!",description:"본 콘텐츠의 아이돌 캐릭터(얼굴·음성·영상)는 AI로 제작된 오리지널 가상 인물이며, 실존 인물(아이돌/연예인 포함)을 기반으로 하지 않습니다."},memberCount:"{{count}}인조",error:{load:"그룹 목록을 불러오지 못했습니다."}},$a={header:"멤버 간 케미",sectionTitle:"멤버와의 케미 정리",sectionSubtitle:"관계성은 채팅 내용에 영향을 줘요!",addRelationship:"관계성 추가",error:{load:"멤버 정보를 불러오지 못했습니다"},add:{header:"관계성 추가",memberNotFound:"멤버를 찾을 수 없습니다.",createRelationshipWith:"{{name}}{{particle}}의 관계를 만들어주세요",selectedMemberPlaceholder:`선택된
46
- 멤버 표시`,selectMember:"멤버 선택",relationshipType:"관계 유형",types:{awkward:"아직 어색해요",polite:"예의를 차려요",friendly:"조금 친해요",tikitaka:"티키타카",trust:"서로 신뢰해요",emotional:"정서적으로 의지해요",bestFriend:"찐친",inseparable:"항상 함께해요"},intimacy:"친밀도",startsAt:"<highlight>{{intimacy}}%</highlight>에서 시작",relationshipNickname:"관계 별칭",nicknamePlaceholder:"예)동갑즈, 멍멍즈"}},Ba={comingSoon:`{{name}}{{particle}}의 대화는
47
- 곧 열릴 예정이에요!`,unlockHint:"{{name}}{{particle}} 더 친해지면 다른 멤버들도 만날 수 있어요💖",greeting:"{{name}}{{particle}} 자유롭게 대화 나눠보세요!",placeholder:"내용을 입력하세요",confirm:"확인",typing:"작성중...",thinkingLong:"생각이 조금 길어졌어요🥺",reload:"다시 불러오기",resend:"재전송",time:{justNow:"방금 전",minutesAgo:"{{count}}분 전",hoursAgo:"{{count}}시간 전",am:"오전",pm:"오후"}},La={error:da,common:pa,navigation:ha,position:ua,casting:ba,share:ya,urlCopied:Ta,castingBoard:Sa,castingComplete:Pa,companion:Ca,aidol:Ra,creation:fa,complete:ka,newsletter:Aa,groupPlanning:Ma,companionCreate:va,myGroup:Na,landing:Ia,highlight:wa,group:Ea,groupList:Ga,chemistry:$a,chat:Ba},Ha={load:{group:"ไม่สามารถโหลดข้อมูลกลุ่ม"}},Da={close:"ปิด",save:"บันทึก",saved:"บันทึกสำเร็จแล้ว",deleted:"ลบสำเร็จแล้ว",error:{save:"ไม่สามารถบันทึก",load:"ไม่สามารถโหลดข้อมูล"}},_a={home:"หน้าหลัก",explore:"สำรวจ",myGroup:"กลุ่มของฉัน"},xa={header:"กำหนดตำแหน่ง",title:"กำหนดตำแหน่งให้สมาชิกแต่ละคน!",subtitle:"แตะเพื่อกำหนดตำแหน่ง",unassigned:"ยังไม่กำหนด",MAIN_VOCAL:"เมนโวคอล",SUB_VOCAL:"ซับโวคอล",MAIN_DANCER:"เมนแดนเซอร์",SUB_DANCER:"ซับแดนเซอร์",MAIN_RAPPER:"เมนแร็ปเปอร์",SUB_RAPPER:"ซับแร็ปเปอร์",assignedTo:"{{position}}({{name}})",assign:"กำหนด",confirm:"วางแผนกลุ่ม",needMore:"กำหนดตำแหน่งอีก {{count}} คน",error:{load:"ไม่สามารถโหลดรายชื่อสมาชิก",update:"ไม่สามารถกำหนดตำแหน่ง"}},Ka={title:"แคสติ้งสมาชิกเดบิวต์",infoBanner:{title:"แคสต์เทรนนี่ของคุณ",description:"ตัวละครไอดอล (ใบหน้า เสียง วิดีโอ) ในเนื้อหานี้เป็นตัวละครเสมือนจริงต้นฉบับที่สร้างด้วย AI และไม่ได้อิงจากบุคคลจริง รวมถึงไอดอลและคนดัง"},tabs:{boy:"บอยกรุ๊ป",girl:"เกิร์ลกรุ๊ป",mixed:"กรุ๊ปผสม"},newMember:{prompt:"ไม่มีเทรนนี่ที่ถูกใจเหรอ?",subPrompt:"ลองแคสต์สมาชิกใหม่สิ"},addMember:"สมาชิกใหม่",abilities:{title:"ความสามารถ",vocal:"ร้อง",dance:"เต้น",rap:"แร็พ",visual:"วิชวล",stamina:"ความอดทน",charm:"เสน่ห์"},castButton:"แคสติ้ง",castComplete:{title:"แคสติ้งสำเร็จ!",description:"เทรนนี่ได้เข้าร่วมกลุ่มแล้ว",viewBoard:"ดูบอร์ดแคสติ้ง"},error:{cast:"การแคสต์ล้มเหลว"}},Fa="แชร์",ja="คัดลอก URL แล้ว!",Va={header:"รายชื่อเดบิวต์สุดท้าย",title:"เทรนนี่ที่ฉันเลือก!",subtitle:"แตะเพื่อลบ",browse:"ดูเทรนนี่",confirm:"ยืนยันเดบิวต์!",needMore:"เลือกอีก {{count}} คนเพื่อสร้างกลุ่ม!",delete:"ลบ",deleted:"ลบสำเร็จแล้ว",empty:{title:`รายชื่อเดบิวต์สุดท้าย
45
+ 리얼한 이야기를 보내드려요!`,previewMessage:"형한테 그런식으로 말하면 안되지 않을까?",emailPlaceholder:"이메일을 입력해주세요",submit:"팔로잉 하고 소식 받기 ✨",submitting:"구독 중...",success:"팔로잉이 완료되었습니다!",error:"팔로잉에 실패했습니다. 다시 시도해주세요.",loadError:"그룹 정보를 불러오지 못했습니다"},error:{load:"그룹 정보를 불러오지 못했습니다"}},Ga={infoBanner:{title:"원하는 그룹을 찾아보세요!",description:"본 콘텐츠의 아이돌 캐릭터(얼굴·음성·영상)는 AI로 제작된 오리지널 가상 인물이며, 실존 인물(아이돌/연예인 포함)을 기반으로 하지 않습니다."},memberCount:"{{count}}인조",error:{load:"그룹 목록을 불러오지 못했습니다."}},Ba={header:"멤버 간 케미",sectionTitle:"멤버와의 케미 정리",sectionSubtitle:"관계성은 채팅 내용에 영향을 줘요!",addRelationship:"관계성 추가",error:{load:"멤버 정보를 불러오지 못했습니다"},add:{header:"관계성 추가",memberNotFound:"멤버를 찾을 수 없습니다.",createRelationshipWith:"{{name}}{{particle}}의 관계를 만들어주세요",selectedMemberPlaceholder:`선택된
46
+ 멤버 표시`,selectMember:"멤버 선택",relationshipType:"관계 유형",types:{awkward:"아직 어색해요",polite:"예의를 차려요",friendly:"조금 친해요",tikitaka:"티키타카",trust:"서로 신뢰해요",emotional:"정서적으로 의지해요",bestFriend:"찐친",inseparable:"항상 함께해요"},intimacy:"친밀도",startsAt:"<highlight>{{intimacy}}%</highlight>에서 시작",relationshipNickname:"관계 별칭",nicknamePlaceholder:"예)동갑즈, 멍멍즈"}},La={comingSoon:`{{name}}{{particle}}의 대화는
47
+ 곧 열릴 예정이에요!`,unlockHint:"{{name}}{{particle}} 더 친해지면 다른 멤버들도 만날 수 있어요💖",greeting:"{{name}}{{particle}} 자유롭게 대화 나눠보세요!",placeholder:"내용을 입력하세요",confirm:"확인",typing:"작성중...",thinkingLong:"생각이 조금 길어졌어요🥺",reload:"다시 불러오기",resend:"재전송",time:{justNow:"방금 전",minutesAgo:"{{count}}분 전",hoursAgo:"{{count}}시간 전",am:"오전",pm:"오후"}},$a={error:da,common:pa,navigation:ha,position:ua,casting:ba,share:ya,urlCopied:Ta,castingBoard:Sa,castingComplete:Pa,companion:Ca,aidol:Ra,creation:fa,complete:ka,newsletter:Aa,groupPlanning:Ma,companionCreate:va,myGroup:Na,landing:Ia,highlight:wa,group:Ea,groupList:Ga,chemistry:Ba,chat:La},Ha={load:{group:"ไม่สามารถโหลดข้อมูลกลุ่ม"}},Da={close:"ปิด",save:"บันทึก",saved:"บันทึกสำเร็จแล้ว",deleted:"ลบสำเร็จแล้ว",error:{save:"ไม่สามารถบันทึก",load:"ไม่สามารถโหลดข้อมูล"}},_a={home:"หน้าหลัก",explore:"สำรวจ",myGroup:"กลุ่มของฉัน"},xa={header:"กำหนดตำแหน่ง",title:"กำหนดตำแหน่งให้สมาชิกแต่ละคน!",subtitle:"แตะเพื่อกำหนดตำแหน่ง",unassigned:"ยังไม่กำหนด",MAIN_VOCAL:"เมนโวคอล",SUB_VOCAL:"ซับโวคอล",MAIN_DANCER:"เมนแดนเซอร์",SUB_DANCER:"ซับแดนเซอร์",MAIN_RAPPER:"เมนแร็ปเปอร์",SUB_RAPPER:"ซับแร็ปเปอร์",assignedTo:"{{position}}({{name}})",assign:"กำหนด",confirm:"วางแผนกลุ่ม",needMore:"กำหนดตำแหน่งอีก {{count}} คน",error:{load:"ไม่สามารถโหลดรายชื่อสมาชิก",update:"ไม่สามารถกำหนดตำแหน่ง"}},Ka={title:"แคสติ้งสมาชิกเดบิวต์",infoBanner:{title:"แคสต์เทรนนี่ของคุณ",description:"ตัวละครไอดอล (ใบหน้า เสียง วิดีโอ) ในเนื้อหานี้เป็นตัวละครเสมือนจริงต้นฉบับที่สร้างด้วย AI และไม่ได้อิงจากบุคคลจริง รวมถึงไอดอลและคนดัง"},tabs:{boy:"บอยกรุ๊ป",girl:"เกิร์ลกรุ๊ป",mixed:"กรุ๊ปผสม"},newMember:{prompt:"ไม่มีเทรนนี่ที่ถูกใจเหรอ?",subPrompt:"ลองแคสต์สมาชิกใหม่สิ"},addMember:"สมาชิกใหม่",abilities:{title:"ความสามารถ",vocal:"ร้อง",dance:"เต้น",rap:"แร็พ",visual:"วิชวล",stamina:"ความอดทน",charm:"เสน่ห์"},castButton:"แคสติ้ง",castComplete:{title:"แคสติ้งสำเร็จ!",description:"เทรนนี่ได้เข้าร่วมกลุ่มแล้ว",viewBoard:"ดูบอร์ดแคสติ้ง"},error:{cast:"การแคสต์ล้มเหลว"}},Fa="แชร์",ja="คัดลอก URL แล้ว!",Va={header:"รายชื่อเดบิวต์สุดท้าย",title:"เทรนนี่ที่ฉันเลือก!",subtitle:"แตะเพื่อลบ",browse:"ดูเทรนนี่",confirm:"ยืนยันเดบิวต์!",needMore:"เลือกอีก {{count}} คนเพื่อสร้างกลุ่ม!",delete:"ลบ",deleted:"ลบสำเร็จแล้ว",empty:{title:`รายชื่อเดบิวต์สุดท้าย
48
48
  ยังว่างอยู่`,description:"ไปเลือกเทรนนี่กันเถอะ!"},error:{load:"ไม่สามารถโหลดข้อมูลสมาชิกได้",delete:"ลบไม่สำเร็จ"}},Oa={title:"แคสติ้งเทรนนี่เสร็จสิ้น",subtitle:"เพิ่มเข้าสู่รายชื่อผู้สมัครแล้ว",remainingSlots:"สล็อตแคสติ้งที่เหลือ",findNext:"หาเทรนนี่คนถัดไป",viewBoard:"ดูบอร์ดแคสติ้ง",error:{load:"ไม่สามารถโหลดข้อมูลสล็อตได้"}},qa={promptPlaceholder:"ไอดอลของคุณพูดยังไง? บรรยายบุคลิกสักนิด...",addMember:"เพิ่มสมาชิก",signed:"เซ็นสัญญาแล้ว 🥺",grade:"เกรด {{grade}}",tab:{profile:"โปรไฟล์",stats:"สถิติ"},activity:{RESTING:"พักผ่อน",PRACTICING:"ฝึกซ้อม",SHORT_BREAK:"พักเบรก",RESTING_AT_HOME:"พักที่บ้าน"}},Ua={notFound:"ไม่พบกลุ่ม",members:"สมาชิก",noMembers:"ยังไม่มีสมาชิก"},Ja={groupName:"ชื่อกลุ่ม",groupNamePlaceholder:"เช่น: DREAMERS, STARLIGHT",memberName:"ชื่อสมาชิก",memberNamePlaceholder:"เช่น: Luna, Kai",concept:"คอนเซ็ปต์",selectConcept:"เลือกคอนเซ็ปต์",personality:"บุคลิกภาพ",concepts:{cute:"น่ารัก",cool:"เท่",elegant:"สง่างาม",powerful:"ทรงพลัง"},personalities:{cheerful:{label:"ร่าเริง",description:"สดใสและเป็นบวกเสมอ"},cool:{label:"เท่",description:"สงบและเยือกเย็น"},tsundere:{label:"ซึนเดเระ",description:"ภายนอกเย็นชา ภายในอบอุ่น"},gentle:{label:"อ่อนโยน",description:"ใจดีและเอาใจใส่"}},step1:"กลุ่ม",step2:"สมาชิก",step3:"เสร็จ",step1Title:"สร้างกลุ่มของคุณ",step2Title:"เพิ่มสมาชิก",groupNameRequired:"กรุณาใส่ชื่อกลุ่ม",memberNameRequired:"กรุณาใส่ชื่อสมาชิก",memberRequired:"กรุณาเพิ่มสมาชิกอย่างน้อย 1 คน",emblem:"ตราสัญลักษณ์",emblemPromptPlaceholder:"อธิบายตราสัญลักษณ์กลุ่ม...",emblemRequired:"กรุณาสร้างภาพตราสัญลักษณ์",generate:"สร้าง",next:"ถัดไป",back:"กลับ",create:"สร้าง",completeTitle:"ไอดอลพร้อมแล้ว!",completeDescription:"เริ่มแชทกับไอดอลในฝันของคุณได้เลย",viewProfile:"ดูโปรไฟล์"},za={greeting1:"สวัสดี!",greeting2:"เราคือ {{name}}!",greeting3:"ยินดีที่ได้รู้จัก",createAnother:"สร้างกลุ่มใหม่",share:"แชร์โปรไฟล์",banner:"อยากรู้ก้าวต่อไปของกลุ่มนี้ไหม?",error:{load:"ไม่สามารถโหลดข้อมูลกลุ่ม"}},Wa={header:"ใส่อีเมล",previewTitle:`เรื่องหอพักเดบิวต์ เรื่องฝึกซ้อม
49
49
  เราจะส่งรีวิวจริงจากสมาชิกให้คุณ!`,previewMessage:"พูดกับพี่แบบนั้นไม่ดีนะ?",title:"รับข่าวสาร",description:"รับข่าวสารและอัปเดตล่าสุดเกี่ยวกับกลุ่มนี้ทางอีเมล",emailLabel:"อีเมล",emailPlaceholder:"example@email.com",submit:"รับข่าวสาร",submitting:"กำลังสมัคร...",success:"สมัครสำเร็จ!",error:"สมัครไม่สำเร็จ กรุณาลองอีกครั้ง"},Ya={header:"วางแผนกลุ่ม",step1Title:"ตั้งชื่อกลุ่มของคุณ",step2Title:"สร้างสัญลักษณ์กลุ่ม",namePlaceholder:"เช่น) Dreamers, Starlight",promptPlaceholder:"เช่น)",generate:"สร้างภาพ",regenerate:"สร้างภาพใหม่",emptyImage:`ภาพโปรไฟล์
50
50
  ที่สร้างขึ้นจะ
@@ -62,7 +62,7 @@ profile na larawan
62
62
  ay lalabas dito`},complete:{nameStepTitle:"Ano ang pangalan?",bioStepTitle:"Sabihin ang kwento ng idol na ito",namePlaceholder:"Maglagay ng pangalan",bioPlaceholder:"Anong paglalakbay ang naranasan?",button:"Kumpletuhin ang Casting"}},Rt={header:"Aking Grupo",chatComingSoon:"Chat sa mga miyembro, malapit na👋",settings:"Mga Setting",highlights:"Mga Highlight",empty:{title:"Wala pang grupo",description:"Gumawa ng sarili mong AI idol group!",cta:"Gumawa ng Idol"}},ft={hero:{title:{line1:"Walang Hanggang Posibilidad",line2:"Ang Kapanganakan ng Idol Group"},line1:"Ang global fandom",line2:"nagca-casting at nagde-debut",line3:"Bagong AI Idol Group",line4:"Next Generation Project",cta:"Mag-cast ng Trainee"},error:{create:"Hindi masimulan."}},kt={error:{load:"Hindi ma-load ang highlight"}},At={title:"Season 1 Debut",chemistryButton:"Chemistry ng mga Miyembro 💭",followButton:"Sundan",highlightTab:"Mga Highlight",follow:{header:"Sundan",title:`Magpapadala kami ng mga totoong kwento
63
63
  mula sa mga miyembro ng {{name}}!`,previewMessage:"Hindi ba dapat mas magalang kang makipag-usap sa hyung mo?",emailPlaceholder:"Ilagay ang iyong email",submit:"Sundan at Makatanggap ng Balita ✨",submitting:"Nagsu-subscribe...",success:"Sinusundan mo na!",error:"Hindi ma-follow. Subukan muli.",loadError:"Hindi na-load ang impormasyon ng grupo"},error:{load:"Hindi ma-load ang impormasyon ng grupo"}},Mt={infoBanner:{title:"Humanap ng grupo na gusto mo!",description:"Ang mga idol character (mukha, boses, video) sa content na ito ay orihinal na virtual character na ginawa ng AI at hindi batay sa totoong tao, kabilang ang mga idol at celebrity."},memberCount:"{{count}} miyembro",error:{load:"Hindi na-load ang listahan ng grupo."}},vt={header:"Chemistry ng mga Miyembro",sectionTitle:"Buod ng Chemistry",sectionSubtitle:"Nakakaapekto ang relasyon sa nilalaman ng chat!",addRelationship:"Magdagdag ng Relasyon",error:{load:"Hindi na-load ang impormasyon ng miyembro"},add:{header:"Magdagdag ng Relasyon",memberNotFound:"Hindi nahanap ang miyembro.",createRelationshipWith:"Gumawa ng relasyon kay {{name}}",selectedMemberPlaceholder:`Napiling
64
64
  miyembro dito`,selectMember:"Pumili ng Miyembro",relationshipType:"Uri ng Relasyon",types:{awkward:"Medyo Awkward Pa",polite:"Magalang",friendly:"Nagiging malapit",tikitaka:"Tiki-Taka",trust:"Nagtitiwala sa isa't isa",emotional:"Malapit sa damdamin",bestFriend:"Pinakamatalik na Kaibigan",inseparable:"Hindi Mapaghiwalay"},intimacy:"Intimacy",startsAt:"Nagsisimula sa <highlight>{{intimacy}}%</highlight>",relationshipNickname:"Palayaw ng Relasyon",nicknamePlaceholder:"hal.) Squad, Besties"}},Nt={comingSoon:`Ang chat kay {{name}} ay
65
- malapit nang magbukas!`,unlockHint:"Maging mas malapit kay {{name}} para makilala ang ibang miyembro 💖",greeting:"Makipag-chat nang malaya kay {{name}}!",placeholder:"Mag-type ng mensahe",confirm:"OK",typing:"Nagta-type...",thinkingLong:"Medyo tumagal ang pag-iisip 🥺",reload:"I-reload",resend:"Ipadala muli",time:{justNow:"Ngayon lang",minutesAgo:"{{count}} min ang nakalipas",hoursAgo:"{{count}} oras ang nakalipas",am:"AM",pm:"PM"}},It={error:rt,common:lt,navigation:st,position:ct,casting:gt,share:mt,urlCopied:dt,castingBoard:pt,castingComplete:ht,companion:ut,aidol:bt,creation:yt,complete:Tt,newsletter:St,groupPlanning:Pt,companionCreate:Ct,myGroup:Rt,landing:ft,highlight:kt,group:At,groupList:Mt,chemistry:vt,chat:Nt},wt={load:{group:"Không thể tải thông tin nhóm"}},Et={close:"Đóng",save:"Lưu",saved:"Đã lưu thành công.",deleted:"Đã xóa thành công.",error:{save:"Không thể lưu",load:"Không thể tải dữ liệu"}},Gt={home:"Trang chủ",explore:"Khám phá",myGroup:"Nhóm của tôi"},$t={header:"Phân Công Vị Trí",title:"Phân công vị trí cho từng thành viên!",subtitle:"Nhấn để phân công vị trí",unassigned:"Chưa phân công",MAIN_VOCAL:"Main Vocal",SUB_VOCAL:"Sub Vocal",MAIN_DANCER:"Main Dancer",SUB_DANCER:"Sub Dancer",MAIN_RAPPER:"Main Rapper",SUB_RAPPER:"Sub Rapper",assignedTo:"{{position}}({{name}})",assign:"Phân công",confirm:"Lên kế hoạch nhóm",needMore:"Phân công vị trí cho {{count}} thành viên nữa",error:{load:"Không thể tải danh sách thành viên",update:"Không thể phân công vị trí"}},Bt={title:"Casting Thành Viên Debut",infoBanner:{title:"Hãy casting thực tập sinh",description:"Các nhân vật idol (khuôn mặt, giọng nói, video) trong nội dung này là nhân vật ảo nguyên bản được tạo bởi AI và không dựa trên người thật, bao gồm idol và người nổi tiếng."},tabs:{boy:"Nhóm Nam",girl:"Nhóm Nữ",mixed:"Nhóm Hỗn hợp"},newMember:{prompt:"Không tìm thấy thực tập sinh yêu thích?",subPrompt:"Hãy thử casting thành viên mới"},addMember:"Thành Viên Mới",abilities:{title:"Năng lực",vocal:"Vocal",dance:"Dance",rap:"Rap",visual:"Visual",stamina:"Thể lực",charm:"Sức hút"},castButton:"Casting",castComplete:{title:"Casting Hoàn Tất!",description:"Thực tập sinh đã gia nhập nhóm",viewBoard:"Xem Bảng Casting"},error:{cast:"Casting thất bại"}},Lt="Chia sẻ",Ht="Đã sao chép URL!",Dt={header:"Đội Hình Ra Mắt",title:"Thực Tập Sinh Tôi Đã Chọn!",subtitle:"Nhấn để xóa",browse:"Xem Thực Tập Sinh",confirm:"Xác Nhận Ra Mắt!",needMore:"Chọn thêm {{count}} để tạo nhóm!",delete:"Xóa",deleted:"Đã xóa thành công.",empty:{title:`Đội Hình Ra Mắt
65
+ malapit nang magbukas!`,unlockHint:"Maging mas malapit kay {{name}} para makilala ang ibang miyembro 💖",greeting:"Makipag-chat nang malaya kay {{name}}!",placeholder:"Mag-type ng mensahe",confirm:"OK",typing:"Nagta-type...",thinkingLong:"Medyo tumagal ang pag-iisip 🥺",reload:"I-reload",resend:"Ipadala muli",time:{justNow:"Ngayon lang",minutesAgo:"{{count}} min ang nakalipas",hoursAgo:"{{count}} oras ang nakalipas",am:"AM",pm:"PM"}},It={error:rt,common:lt,navigation:st,position:ct,casting:gt,share:mt,urlCopied:dt,castingBoard:pt,castingComplete:ht,companion:ut,aidol:bt,creation:yt,complete:Tt,newsletter:St,groupPlanning:Pt,companionCreate:Ct,myGroup:Rt,landing:ft,highlight:kt,group:At,groupList:Mt,chemistry:vt,chat:Nt},wt={load:{group:"Không thể tải thông tin nhóm"}},Et={close:"Đóng",save:"Lưu",saved:"Đã lưu thành công.",deleted:"Đã xóa thành công.",error:{save:"Không thể lưu",load:"Không thể tải dữ liệu"}},Gt={home:"Trang chủ",explore:"Khám phá",myGroup:"Nhóm của tôi"},Bt={header:"Phân Công Vị Trí",title:"Phân công vị trí cho từng thành viên!",subtitle:"Nhấn để phân công vị trí",unassigned:"Chưa phân công",MAIN_VOCAL:"Main Vocal",SUB_VOCAL:"Sub Vocal",MAIN_DANCER:"Main Dancer",SUB_DANCER:"Sub Dancer",MAIN_RAPPER:"Main Rapper",SUB_RAPPER:"Sub Rapper",assignedTo:"{{position}}({{name}})",assign:"Phân công",confirm:"Lên kế hoạch nhóm",needMore:"Phân công vị trí cho {{count}} thành viên nữa",error:{load:"Không thể tải danh sách thành viên",update:"Không thể phân công vị trí"}},Lt={title:"Casting Thành Viên Debut",infoBanner:{title:"Hãy casting thực tập sinh",description:"Các nhân vật idol (khuôn mặt, giọng nói, video) trong nội dung này là nhân vật ảo nguyên bản được tạo bởi AI và không dựa trên người thật, bao gồm idol và người nổi tiếng."},tabs:{boy:"Nhóm Nam",girl:"Nhóm Nữ",mixed:"Nhóm Hỗn hợp"},newMember:{prompt:"Không tìm thấy thực tập sinh yêu thích?",subPrompt:"Hãy thử casting thành viên mới"},addMember:"Thành Viên Mới",abilities:{title:"Năng lực",vocal:"Vocal",dance:"Dance",rap:"Rap",visual:"Visual",stamina:"Thể lực",charm:"Sức hút"},castButton:"Casting",castComplete:{title:"Casting Hoàn Tất!",description:"Thực tập sinh đã gia nhập nhóm",viewBoard:"Xem Bảng Casting"},error:{cast:"Casting thất bại"}},$t="Chia sẻ",Ht="Đã sao chép URL!",Dt={header:"Đội Hình Ra Mắt",title:"Thực Tập Sinh Tôi Đã Chọn!",subtitle:"Nhấn để xóa",browse:"Xem Thực Tập Sinh",confirm:"Xác Nhận Ra Mắt!",needMore:"Chọn thêm {{count}} để tạo nhóm!",delete:"Xóa",deleted:"Đã xóa thành công.",empty:{title:`Đội Hình Ra Mắt
66
66
  Đang Trống`,description:"Hãy chọn thực tập sinh!"},error:{load:"Không thể tải thông tin thành viên.",delete:"Xóa thất bại."}},_t={title:"Casting Thực Tập Sinh Hoàn Tất",subtitle:"Đã thêm vào danh sách ứng viên casting",remainingSlots:"Slot Casting Còn Lại",findNext:"Tìm Thực Tập Sinh Tiếp",viewBoard:"Xem Bảng Casting",error:{load:"Không thể tải thông tin slot"}},xt={promptPlaceholder:"Idol của bạn nói chuyện như thế nào? Mô tả tính cách...",addMember:"Thêm Thành Viên",signed:"Đã ký hợp đồng 🥺",grade:"Hạng {{grade}}",tab:{profile:"Hồ sơ",stats:"Chỉ số"},activity:{RESTING:"Đang nghỉ",PRACTICING:"Đang tập",SHORT_BREAK:"Nghỉ ngắn",RESTING_AT_HOME:"Nghỉ ở nhà"}},Kt={notFound:"Không tìm thấy nhóm",members:"Thành Viên",noMembers:"Chưa có thành viên"},Ft={groupName:"Tên Nhóm",groupNamePlaceholder:"vd: DREAMERS, STARLIGHT",memberName:"Tên Thành Viên",memberNamePlaceholder:"vd: Luna, Kai",concept:"Concept",selectConcept:"Chọn concept",personality:"Tính Cách",concepts:{cute:"Dễ thương",cool:"Ngầu",elegant:"Thanh lịch",powerful:"Mạnh mẽ"},personalities:{cheerful:{label:"Vui vẻ",description:"Luôn tươi sáng và tích cực"},cool:{label:"Ngầu",description:"Bình tĩnh và điềm đạm"},tsundere:{label:"Tsundere",description:"Lạnh lùng bên ngoài, ấm áp bên trong"},gentle:{label:"Dịu dàng",description:"Tốt bụng và quan tâm"}},step1:"Nhóm",step2:"Thành Viên",step3:"Xong",step1Title:"Tạo Nhóm",step2Title:"Thêm Thành Viên",groupNameRequired:"Vui lòng nhập tên nhóm",memberNameRequired:"Vui lòng nhập tên thành viên",memberRequired:"Vui lòng thêm ít nhất một thành viên",emblem:"Biểu tượng",emblemPromptPlaceholder:"Mô tả biểu tượng nhóm...",emblemRequired:"Vui lòng tạo hình biểu tượng",generate:"Tạo",next:"Tiếp",back:"Quay lại",create:"Tạo",completeTitle:"Idol Đã Sẵn Sàng!",completeDescription:"Bắt đầu trò chuyện với idol mơ ước ngay",viewProfile:"Xem Hồ Sơ"},jt={greeting1:"Xin chào!",greeting2:"Chúng tôi là {{name}}!",greeting3:"Rất vui được gặp bạn",createAnother:"Tạo Nhóm Khác",share:"Chia Sẻ Hồ Sơ",banner:"Tò mò về bước tiếp theo của nhóm?",error:{load:"Không thể tải thông tin nhóm"}},Vt={header:"Nhập Email",previewTitle:`Chuyện ký túc xá debut, chuyện tập luyện
67
67
  Chúng tôi sẽ gửi bạn những câu chuyện thật từ các thành viên!`,previewMessage:"Em nói chuyện với anh như vậy có được không?",title:"Nhận Tin Tức",description:"Nhận tin tức và cập nhật mới nhất về nhóm này qua email.",emailLabel:"Email",emailPlaceholder:"vidu@email.com",submit:"Nhận Tin",submitting:"Đang đăng ký...",success:"Đăng ký thành công!",error:"Đăng ký thất bại. Vui lòng thử lại."},Ot={header:"Lập Kế Hoạch Nhóm",step1Title:"Đặt tên cho nhóm của bạn",step2Title:"Tạo biểu tượng nhóm",namePlaceholder:"vd.) Dreamers, Starlight",promptPlaceholder:"vd.)",generate:"Tạo Hình Ảnh",regenerate:"Tạo Lại Hình Ảnh",emptyImage:`Hình ảnh profile
68
68
  được tạo sẽ
@@ -71,7 +71,7 @@ hiển thị ở đây`,next:"Tiếp Theo",error:{load:"Không thể tải thôn
71
71
  hiển thị ở đây`},complete:{nameStepTitle:"Tên là gì?",bioStepTitle:"Kể cho chúng tôi câu chuyện của idol này",namePlaceholder:"Nhập tên",bioPlaceholder:"Đã trải qua hành trình gì?",button:"Hoàn Thành Tuyển Chọn"}},Ut={header:"Nhóm Của Tôi",chatComingSoon:"Chat với thành viên sắp ra mắt👋",settings:"Cài đặt",highlights:"Điểm nổi bật",empty:{title:"Chưa có nhóm nào",description:"Tạo nhóm idol AI của riêng bạn!",cta:"Tạo Idol"}},Jt={hero:{title:{line1:"Khả Năng Vô Hạn",line2:"Sự Ra Đời Của Nhóm Idol"},line1:"Fandom toàn cầu",line2:"tuyển chọn và ra mắt",line3:"Nhóm Idol AI Mới",line4:"Dự Án Thế Hệ Tiếp Theo",cta:"Tuyển Thực Tập Sinh"},error:{create:"Không thể bắt đầu."}},zt={error:{load:"Không thể tải highlight"}},Wt={title:"Ra Mắt Mùa 1",chemistryButton:"Phản Ứng Hóa Học Giữa Thành Viên 💭",followButton:"Theo dõi",highlightTab:"Nổi bật",follow:{header:"Theo dõi",title:`Chúng tôi sẽ gửi cho bạn những câu chuyện thật
72
72
  từ các thành viên {{name}}!`,previewMessage:"Không nên nói chuyện với anh như vậy chứ?",emailPlaceholder:"Nhập email của bạn",submit:"Theo dõi & Nhận tin tức ✨",submitting:"Đang đăng ký...",success:"Bạn đã theo dõi thành công!",error:"Theo dõi thất bại. Vui lòng thử lại.",loadError:"Không thể tải thông tin nhóm"},error:{load:"Không thể tải thông tin nhóm"}},Yt={infoBanner:{title:"Tìm nhóm bạn thích!",description:"Các nhân vật idol (khuôn mặt, giọng nói, video) trong nội dung này là nhân vật ảo nguyên bản được tạo bởi AI và không dựa trên người thật, bao gồm idol và người nổi tiếng."},memberCount:"{{count}} thành viên",error:{load:"Không thể tải danh sách nhóm."}},Qt={header:"Phản Ứng Hóa Học Giữa Thành Viên",sectionTitle:"Tóm Tắt Mối Quan Hệ",sectionSubtitle:"Mối quan hệ ảnh hưởng đến nội dung trò chuyện!",addRelationship:"Thêm Mối Quan Hệ",error:{load:"Không thể tải thông tin thành viên"},add:{header:"Thêm Mối Quan Hệ",memberNotFound:"Không tìm thấy thành viên.",createRelationshipWith:"Tạo mối quan hệ với {{name}}",selectedMemberPlaceholder:`Thành viên
73
73
  đã chọn`,selectMember:"Chọn Thành Viên",relationshipType:"Loại Quan Hệ",types:{awkward:"Còn Ngại",polite:"Lịch Sự",friendly:"Đang thân hơn",tikitaka:"Ăn Ý",trust:"Tin tưởng nhau",emotional:"Gần gũi về cảm xúc",bestFriend:"Bạn Thân Nhất",inseparable:"Không Thể Tách Rời"},intimacy:"Độ Thân Mật",startsAt:"Bắt đầu từ <highlight>{{intimacy}}%</highlight>",relationshipNickname:"Biệt Danh Quan Hệ",nicknamePlaceholder:"vd) Đồng trang lứa, Cặp đôi"}},Xt={comingSoon:`Cuộc trò chuyện với {{name}}
74
- sắp được mở!`,unlockHint:"Thân hơn với {{name}} để gặp các thành viên khác 💖",greeting:"Trò chuyện thoải mái với {{name}}!",placeholder:"Nhập tin nhắn",confirm:"OK",typing:"Đang nhập...",thinkingLong:"Cần thêm chút thời gian để suy nghĩ 🥺",reload:"Tải lại",resend:"Gửi lại",time:{justNow:"Vừa xong",minutesAgo:"{{count}} phút trước",hoursAgo:"{{count}} giờ trước",am:"SA",pm:"CH"}},Zt={error:wt,common:Et,navigation:Gt,position:$t,casting:Bt,share:Lt,urlCopied:Ht,castingBoard:Dt,castingComplete:_t,companion:xt,aidol:Kt,creation:Ft,complete:jt,newsletter:Vt,groupPlanning:Ot,companionCreate:qt,myGroup:Ut,landing:Jt,highlight:zt,group:Wt,groupList:Yt,chemistry:Qt,chat:Xt},en={load:{group:"无法加载组合信息"}},an={close:"关闭",save:"保存",saved:"保存成功。",deleted:"删除成功。",error:{save:"保存失败",load:"无法加载数据"}},tn={home:"首页",explore:"发现",myGroup:"我的组合"},nn={header:"位置分配",title:"给每位成员分配位置!",subtitle:"点击分配位置",unassigned:"未分配",MAIN_VOCAL:"主唱",SUB_VOCAL:"副唱",MAIN_DANCER:"主舞",SUB_DANCER:"副舞",MAIN_RAPPER:"主说唱",SUB_RAPPER:"副说唱",assignedTo:"{{position}}({{name}})",assign:"分配",confirm:"规划组合",needMore:"还需分配{{count}}人的位置",error:{load:"加载成员列表失败",update:"位置分配失败"}},on={title:"出道成员选拔",infoBanner:{title:"选拔你的练习生",description:"本内容中的偶像角色(面部、声音、视频)是由AI制作的原创虚拟人物,不基于任何真实人物,包括偶像和艺人。"},tabs:{boy:"男团",girl:"女团",mixed:"混合团"},newMember:{prompt:"没有喜欢的练习生吗?",subPrompt:"试试选拔新成员"},addMember:"新成员",abilities:{title:"能力值",vocal:"声乐",dance:"舞蹈",rap:"说唱",visual:"颜值",stamina:"体力",charm:"魅力"},castButton:"选秀",castComplete:{title:"选秀完成!",description:"练习生已加入组合",viewBoard:"查看选秀面板"},error:{cast:"选角失败"}},rn="分享",ln="URL已复制!",sn={header:"最终出道阵容",title:"我选中的练习生!",subtitle:"点击可删除",browse:"浏览练习生",confirm:"确认出道!",needMore:"再选{{count}}人就可以创建组合了!",delete:"删除",deleted:"已删除。",empty:{title:`最终出道阵容
74
+ sắp được mở!`,unlockHint:"Thân hơn với {{name}} để gặp các thành viên khác 💖",greeting:"Trò chuyện thoải mái với {{name}}!",placeholder:"Nhập tin nhắn",confirm:"OK",typing:"Đang nhập...",thinkingLong:"Cần thêm chút thời gian để suy nghĩ 🥺",reload:"Tải lại",resend:"Gửi lại",time:{justNow:"Vừa xong",minutesAgo:"{{count}} phút trước",hoursAgo:"{{count}} giờ trước",am:"SA",pm:"CH"}},Zt={error:wt,common:Et,navigation:Gt,position:Bt,casting:Lt,share:$t,urlCopied:Ht,castingBoard:Dt,castingComplete:_t,companion:xt,aidol:Kt,creation:Ft,complete:jt,newsletter:Vt,groupPlanning:Ot,companionCreate:qt,myGroup:Ut,landing:Jt,highlight:zt,group:Wt,groupList:Yt,chemistry:Qt,chat:Xt},en={load:{group:"无法加载组合信息"}},an={close:"关闭",save:"保存",saved:"保存成功。",deleted:"删除成功。",error:{save:"保存失败",load:"无法加载数据"}},tn={home:"首页",explore:"发现",myGroup:"我的组合"},nn={header:"位置分配",title:"给每位成员分配位置!",subtitle:"点击分配位置",unassigned:"未分配",MAIN_VOCAL:"主唱",SUB_VOCAL:"副唱",MAIN_DANCER:"主舞",SUB_DANCER:"副舞",MAIN_RAPPER:"主说唱",SUB_RAPPER:"副说唱",assignedTo:"{{position}}({{name}})",assign:"分配",confirm:"规划组合",needMore:"还需分配{{count}}人的位置",error:{load:"加载成员列表失败",update:"位置分配失败"}},on={title:"出道成员选拔",infoBanner:{title:"选拔你的练习生",description:"本内容中的偶像角色(面部、声音、视频)是由AI制作的原创虚拟人物,不基于任何真实人物,包括偶像和艺人。"},tabs:{boy:"男团",girl:"女团",mixed:"混合团"},newMember:{prompt:"没有喜欢的练习生吗?",subPrompt:"试试选拔新成员"},addMember:"新成员",abilities:{title:"能力值",vocal:"声乐",dance:"舞蹈",rap:"说唱",visual:"颜值",stamina:"体力",charm:"魅力"},castButton:"选秀",castComplete:{title:"选秀完成!",description:"练习生已加入组合",viewBoard:"查看选秀面板"},error:{cast:"选角失败"}},rn="分享",ln="URL已复制!",sn={header:"最终出道阵容",title:"我选中的练习生!",subtitle:"点击可删除",browse:"浏览练习生",confirm:"确认出道!",needMore:"再选{{count}}人就可以创建组合了!",delete:"删除",deleted:"已删除。",empty:{title:`最终出道阵容
75
75
  为空`,description:"去选一些练习生吧!"},error:{load:"加载成员信息失败。",delete:"删除失败。"}},cn={title:"练习生选秀完成",subtitle:"已添加到候选名单",remainingSlots:"剩余选秀名额",findNext:"寻找下一位练习生",viewBoard:"查看选秀板",error:{load:"无法加载名额信息"}},gn={promptPlaceholder:"你的偶像怎么说话?描述一下性格...",addMember:"添加成员",signed:"已签约 🥺",grade:"{{grade}} 级",tab:{profile:"简介",stats:"能力值"},activity:{RESTING:"休息中",PRACTICING:"练习中",SHORT_BREAK:"短暂休息",RESTING_AT_HOME:"在家休息"}},mn={notFound:"找不到该组合",members:"成员",noMembers:"暂无成员"},dn={groupName:"组合名",groupNamePlaceholder:"例如: DREAMERS, STARLIGHT",memberName:"成员名",memberNamePlaceholder:"例如: Luna, Kai",concept:"概念",selectConcept:"选择概念",personality:"性格",concepts:{cute:"可爱",cool:"酷",elegant:"优雅",powerful:"有力"},personalities:{cheerful:{label:"开朗",description:"总是阳光积极"},cool:{label:"冷酷",description:"冷静沉着"},tsundere:{label:"傲娇",description:"外冷内热"},gentle:{label:"温柔",description:"善良体贴"}},step1:"组合",step2:"成员",step3:"完成",step1Title:"创建组合",step2Title:"添加成员",groupNameRequired:"请输入组合名",memberNameRequired:"请输入成员名",memberRequired:"请至少添加一名成员",emblem:"徽章",emblemPromptPlaceholder:"描述你的组合徽章...",emblemRequired:"请生成徽章图片",generate:"生成",next:"下一步",back:"上一步",create:"创建",completeTitle:"偶像创建完成!",completeDescription:"现在就和你的梦想偶像聊天吧",viewProfile:"查看资料"},pn={greeting1:"你好!",greeting2:"我们是{{name}}!",greeting3:"请多多关照",createAnother:"创建其他组合",share:"分享资料",banner:"想知道这个组合的下一步吗?",error:{load:"无法加载组合信息"}},hn={header:"输入邮箱",previewTitle:`出道组宿舍趣事、练习趣事
76
76
  成员们的真实后记发送给你!`,previewMessage:"你这样跟哥哥说话不好吧?",title:"获取最新消息",description:"通过邮件接收该组合的最新消息和更新。",emailLabel:"邮箱",emailPlaceholder:"example@email.com",submit:"接收消息",submitting:"订阅中...",success:"订阅成功!",error:"订阅失败,请重试。"},un={header:"组合规划",step1Title:"为你的组合起名",step2Title:"创建组合徽章",namePlaceholder:"例)Dreamers、Starlight",promptPlaceholder:"例)",generate:"生成图片",regenerate:"重新生成图片",emptyImage:`生成的头像
77
77
  将显示
@@ -80,5 +80,5 @@ sắp được mở!`,unlockHint:"Thân hơn với {{name}} để gặp các th
80
80
  显示`},complete:{nameStepTitle:"叫什么名字?",bioStepTitle:"告诉我们这位偶像的故事",namePlaceholder:"请输入名字",bioPlaceholder:"经历了怎样的时光?",button:"完成选角"}},yn={header:"我的组合",chatComingSoon:"与成员聊天即将上线👋",settings:"设置",highlights:"精彩集锦",empty:{title:"还没有创建的组合",description:"创建属于你的AI偶像组合吧!",cta:"创建偶像"}},Tn={hero:{title:{line1:"无限可能性的",line2:"偶像团体诞生"},line1:"全球粉丝",line2:"亲自选角并出道",line3:"新人AI偶像团体",line4:"下一代项目",cta:"选拔练习生"},error:{create:"启动失败。"}},Sn={error:{load:"无法加载精彩集锦"}},Pn={title:"第一季出道组",chemistryButton:"成员间默契 💭",followButton:"关注",highlightTab:"精彩集锦",follow:{header:"关注",title:`我们会向您发送
81
81
  {{name}}成员们的真实故事!`,previewMessage:"你不应该那样跟哥哥说话吧?",emailPlaceholder:"请输入您的邮箱",submit:"关注并接收动态 ✨",submitting:"订阅中...",success:"关注成功!",error:"关注失败,请重试。",loadError:"加载群组信息失败"},error:{load:"加载群组信息失败"}},Cn={infoBanner:{title:"找到你喜欢的组合吧!",description:"本内容中的偶像角色(面部、声音、视频)是由AI制作的原创虚拟人物,不基于任何真实人物,包括偶像和艺人。"},memberCount:"{{count}}人组",error:{load:"无法加载群组列表。"}},Rn={header:"成员间默契",sectionTitle:"成员关系整理",sectionSubtitle:"关系会影响聊天内容!",addRelationship:"添加关系",error:{load:"无法加载成员信息"},add:{header:"添加关系",memberNotFound:"找不到成员。",createRelationshipWith:"创建与{{name}}的关系",selectedMemberPlaceholder:`已选择的
82
82
  成员显示`,selectMember:"选择成员",relationshipType:"关系类型",types:{awkward:"还很尴尬",polite:"有礼貌",friendly:"渐渐熟悉",tikitaka:"默契十足",trust:"互相信任",emotional:"情感上的依靠",bestFriend:"最好的朋友",inseparable:"形影不离"},intimacy:"亲密度",startsAt:"从<highlight>{{intimacy}}%</highlight>开始",relationshipNickname:"关系别名",nicknamePlaceholder:"例)同龄组、闺蜜组"}},fn={comingSoon:`与{{name}}的聊天
83
- 即将开放!`,unlockHint:"和{{name}}更亲近就能遇到其他成员 💖",greeting:"和{{name}}自由聊天吧!",placeholder:"输入消息",confirm:"确认",typing:"正在输入...",thinkingLong:"想得有点久了 🥺",reload:"重新加载",resend:"重新发送",time:{justNow:"刚刚",minutesAgo:"{{count}}分钟前",hoursAgo:"{{count}}小时前",am:"上午",pm:"下午"}},kn={error:en,common:an,navigation:tn,position:nn,casting:on,share:rn,urlCopied:ln,castingBoard:sn,castingComplete:cn,companion:gn,aidol:mn,creation:dn,complete:pn,newsletter:hn,groupPlanning:un,companionCreate:bn,myGroup:yn,landing:Tn,highlight:Sn,group:Pn,groupList:Cn,chemistry:Rn,chat:fn},An="aidol",Mn={en:J,es:ye,id:Fe,ja:ma,ko:La,th:ot,tl:It,vi:Zt,zh:kn};exports.INTIMACY_TO_RELATIONSHIP_TYPE=t.INTIMACY_TO_RELATIONSHIP_TYPE;exports.RELATIONSHIP_TYPE_TO_INTIMACY=t.RELATIONSHIP_TYPE_TO_INTIMACY;exports.SenderType=t.SenderType;exports.aidolHighlightSchema=t.aidolHighlightSchema;exports.aidolSchema=t.aidolSchema;exports.chatroomSchema=t.chatroomSchema;exports.companionRelationshipSchema=t.companionRelationshipSchema;exports.companionSchema=t.companionSchema;exports.highlightMessageSchema=t.highlightMessageSchema;exports.imageGenerationResponseSchema=t.imageGenerationResponseSchema;exports.isCompanion=t.isCompanion;exports.isUser=t.isUser;exports.messageSchema=t.messageSchema;exports.AIDOL_NS=An;exports.AIdolRepository=h;exports.ChatroomRepository=b;exports.CompanionRelationshipRepository=y;exports.CompanionRepository=T;exports.HighlightRepository=S;exports.LeadsRepository=P;exports.LocalChatroomIdsRepository=R;exports.aidolTranslations=Mn;exports.getParticle=f;
83
+ 即将开放!`,unlockHint:"和{{name}}更亲近就能遇到其他成员 💖",greeting:"和{{name}}自由聊天吧!",placeholder:"输入消息",confirm:"确认",typing:"正在输入...",thinkingLong:"想得有点久了 🥺",reload:"重新加载",resend:"重新发送",time:{justNow:"刚刚",minutesAgo:"{{count}}分钟前",hoursAgo:"{{count}}小时前",am:"上午",pm:"下午"}},kn={error:en,common:an,navigation:tn,position:nn,casting:on,share:rn,urlCopied:ln,castingBoard:sn,castingComplete:cn,companion:gn,aidol:mn,creation:dn,complete:pn,newsletter:hn,groupPlanning:un,companionCreate:bn,myGroup:yn,landing:Tn,highlight:Sn,group:Pn,groupList:Cn,chemistry:Rn,chat:fn},An="aidol",Mn={en:J,es:ye,id:Fe,ja:ma,ko:$a,th:ot,tl:It,vi:Zt,zh:kn};exports.INTIMACY_TO_RELATIONSHIP_TYPE=t.INTIMACY_TO_RELATIONSHIP_TYPE;exports.RELATIONSHIP_TYPE_TO_INTIMACY=t.RELATIONSHIP_TYPE_TO_INTIMACY;exports.SenderType=t.SenderType;exports.aidolHighlightSchema=t.aidolHighlightSchema;exports.aidolSchema=t.aidolSchema;exports.chatroomSchema=t.chatroomSchema;exports.companionRelationshipSchema=t.companionRelationshipSchema;exports.companionSchema=t.companionSchema;exports.highlightMessageSchema=t.highlightMessageSchema;exports.imageGenerationResponseSchema=t.imageGenerationResponseSchema;exports.isCompanion=t.isCompanion;exports.isUser=t.isUser;exports.messageSchema=t.messageSchema;exports.AIDOL_NS=An;exports.AIdolRepository=h;exports.ChatroomRepository=b;exports.CompanionRelationshipRepository=y;exports.CompanionRepository=T;exports.HighlightRepository=S;exports.LeadsRepository=P;exports.LocalChatroomIdsRepository=R;exports.aidolTranslations=Mn;exports.getParticle=f;
84
84
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/repositories/AIdolRepository.ts","../src/repositories/ChatroomRepository.ts","../src/repositories/CompanionRelationshipRepository.ts","../src/repositories/CompanionRepository.ts","../src/repositories/HighlightRepository.ts","../src/repositories/LeadsRepository.ts","../src/repositories/LocalChatroomIdsRepository.ts","../src/lib/koreanParticle.ts","../src/i18n/translations.ts"],"sourcesContent":["import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n AIdol,\n AIdolCreate,\n AIdolCreateResponse,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport {\n aidolCreateResponseSchema,\n aidolSchema,\n imageGenerationResponseSchema,\n} from \"../schemas\";\n\nexport class AIdolRepository extends BaseCrudRepository<AIdol> {\n readonly resource = \"aidols\";\n\n protected getDataSchema() {\n return aidolSchema;\n }\n\n async createAIdol(variables: AIdolCreate): Promise<AIdolCreateResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const raw = (await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(variables),\n })) as { data: unknown };\n return aidolCreateResponseSchema.parse(raw.data);\n }\n\n async getMy(fetchOptions?: RequestInit): Promise<{ data: AIdol[] }> {\n const url = this.apiService.buildUrl(`${this.resource}/my`);\n const raw = (await this.apiService.request(url, fetchOptions)) as {\n data: unknown[];\n total: number;\n };\n return { data: aidolSchema.array().parse(raw.data) };\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\nimport { z } from \"zod\";\n\nimport {\n chatroomSchema,\n messageSchema,\n type Chatroom,\n type Message,\n} from \"../schemas\";\n\n/**\n * Response schema for generate AI response endpoint\n */\nconst generateResponseSchema = z.object({\n messageId: z.string(),\n content: z.string(),\n});\n\nexport interface GenerateResponse {\n messageId: string;\n content: string;\n}\n\n/**\n * Repository for Chatroom entities\n * Handles chatroom CRUD and message operations\n */\nexport class ChatroomRepository extends BaseCrudRepository<Chatroom> {\n readonly resource = \"chatrooms\";\n\n protected getDataSchema() {\n return chatroomSchema;\n }\n\n /**\n * Get messages from a chatroom\n * GET /chatrooms/{id}/messages\n */\n async getMessages(\n chatroomId: string,\n options?: { limit?: number; offset?: number },\n fetchOptions?: RequestInit,\n ): Promise<Message[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) {\n params.set(\"limit\", options.limit.toString());\n }\n if (options?.offset !== undefined) {\n params.set(\"offset\", options.offset.toString());\n }\n\n const queryString = params.toString();\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages${queryString ? `?${queryString}` : \"\"}`,\n );\n\n const rawResponse = await this.apiService.request(url, fetchOptions);\n return this.validateResponse(rawResponse, z.array(messageSchema));\n }\n\n /**\n * Send a message to a chatroom\n * POST /chatrooms/{id}/messages\n *\n * Anonymous ID is automatically sent via httpOnly cookie.\n *\n * @param chatroomId - The chatroom ID\n * @param content - The message content\n * @param fetchOptions - Optional fetch options\n */\n async sendMessage(\n chatroomId: string,\n content: string,\n fetchOptions?: RequestInit,\n ): Promise<Message> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, senderType: \"USER\" }),\n });\n\n return this.validateResponse(rawResponse, messageSchema);\n }\n\n /**\n * Generate AI response for a chatroom with a specific companion\n * POST /chatrooms/{id}/companions/{companionId}/response\n */\n async generateResponse(\n chatroomId: string,\n companionId: string,\n fetchOptions?: RequestInit,\n ): Promise<GenerateResponse> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/companions/${companionId}/response`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n return this.validateResponse(rawResponse, generateResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { CompanionRelationship } from \"../schemas\";\nimport { companionRelationshipSchema } from \"../schemas\";\n\nexport class CompanionRelationshipRepository extends BaseCrudRepository<CompanionRelationship> {\n readonly resource = \"companion-relationships\";\n\n protected getDataSchema() {\n return companionRelationshipSchema;\n }\n\n async getByFromCompanionId(fromCompanionId: string) {\n return this.getList({\n filters: [\n { field: \"from_companion_id\", operator: \"eq\", value: fromCompanionId },\n ],\n });\n }\n\n async deleteOne(params: {\n id: string | number;\n }): Promise<{ data: CompanionRelationship }> {\n const url = `${this.apiService.buildUrl(this.resource)}/${params.id}`;\n await this.apiService.request(url, { method: \"DELETE\" });\n return { data: {} as CompanionRelationship };\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n Companion,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport { companionSchema, imageGenerationResponseSchema } from \"../schemas\";\n\n/** CRUD operations use BaseCrudRepository (wrapped { data: T } responses) */\nexport class CompanionRepository extends BaseCrudRepository<Companion> {\n readonly resource = \"companions\";\n\n protected getDataSchema() {\n return companionSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { AIdolHighlight, HighlightMessage } from \"../schemas\";\nimport { aidolHighlightSchema, highlightMessageSchema } from \"../schemas\";\n\nexport class HighlightRepository extends BaseCrudRepository<AIdolHighlight> {\n readonly resource = \"aidol-highlights\";\n\n protected getDataSchema() {\n return aidolHighlightSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async getMessages(\n highlightId: string,\n fetchOptions?: RequestInit,\n ): Promise<{ data: HighlightMessage[] }> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${highlightId}/messages`,\n );\n const raw = await this.apiService.request(url, fetchOptions);\n return { data: highlightMessageSchema.array().parse(raw) };\n }\n}\n","import { z } from \"zod\";\n\nimport type { LeadRequest, LeadResponse } from \"@/schemas\";\nimport { leadResponseSchema } from \"@/schemas\";\nimport type { ApiService } from \"@/services/ApiService\";\n\nexport class LeadsRepository {\n private readonly resource = \"leads\";\n\n constructor(private readonly apiService: ApiService) {}\n\n async create(request: LeadRequest): Promise<LeadResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const response = await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n\n const wrapped = z.object({ data: leadResponseSchema }).parse(response);\n return wrapped.data;\n }\n}\n","import { z } from \"zod\";\n\nconst STORAGE_KEY = \"aidol_chatroom_ids\";\nconst schema = z.record(z.string(), z.string());\n\nconst readStorage = (): Record<string, string> => {\n if (typeof window === \"undefined\") return {};\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return {};\n\n try {\n const parsed = JSON.parse(stored);\n const result = schema.safeParse(parsed);\n if (result.success) {\n return result.data;\n }\n console.warn(`[LocalChatroomIdsRepository] Invalid data, resetting`);\n return {};\n } catch (error) {\n if (error instanceof SyntaxError) {\n console.warn(`[LocalChatroomIdsRepository] Failed to parse, resetting`);\n return {};\n }\n throw error;\n }\n};\n\nconst writeStorage = (data: Record<string, string>): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\n \"LocalChatroomIdsRepository write operations can only be called on the client side.\",\n );\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n};\n\n/**\n * Repository for managing chatroom IDs in localStorage.\n * Maps companionId to chatroomId for persistence across sessions.\n */\nexport const LocalChatroomIdsRepository = {\n getChatroomId(companionId: string): string | null {\n const data = readStorage();\n return data[companionId] ?? null;\n },\n\n setChatroomId(companionId: string, chatroomId: string): void {\n const data = readStorage();\n data[companionId] = chatroomId;\n writeStorage(data);\n },\n\n removeChatroomId(companionId: string): void {\n const data = readStorage();\n delete data[companionId];\n writeStorage(data);\n },\n};\n","// 한글의 마지막 글자를 기준으로 적절한 조사를 반환하는 함수\n// words: 조사 적용 대상 단어\n// withFinalConsonant: 받침이 있을 때 사용할 조사\n// withoutFinalConsonant: 받침이 없을 때 사용할 조사\n// 예: getParticle(\"민준\", \"과\", \"와\") => \"과\"\nexport function getParticle(\n word: string,\n withFinalConsonant: string,\n withoutFinalConsonant: string,\n): string {\n if (!word) return withoutFinalConsonant;\n\n const lastChar = word.charAt(word.length - 1);\n const code = lastChar.charCodeAt(0);\n\n // 한글 유니코드 범위 = 0xAC00 ~ 0xD7A3\n if (code < 0xac00 || code > 0xd7a3) {\n return withoutFinalConsonant;\n }\n\n // 받침 여부 (code - 0xAC00) % 28 !== 0 이면 받침 있음\n const finalConsonantIndex = (code - 0xac00) % 28;\n\n // '로/으로' 예외 처리\n if (withFinalConsonant === \"으로\" && withoutFinalConsonant === \"로\") {\n return finalConsonantIndex === 0 || finalConsonantIndex === 8\n ? \"로\"\n : \"으로\"; // 8 = ㄹ\n }\n\n return finalConsonantIndex === 0 ? withoutFinalConsonant : withFinalConsonant;\n}\n","/**\n * Server-safe exports for aidol translations.\n *\n * This module exports only JSON resources and constants,\n * avoiding React-specific code that would break SSR.\n */\n\nimport en from \"./locales/en/aidol.json\";\nimport es from \"./locales/es/aidol.json\";\nimport id from \"./locales/id/aidol.json\";\nimport ja from \"./locales/ja/aidol.json\";\nimport ko from \"./locales/ko/aidol.json\";\nimport th from \"./locales/th/aidol.json\";\nimport tl from \"./locales/tl/aidol.json\";\nimport vi from \"./locales/vi/aidol.json\";\nimport zh from \"./locales/zh/aidol.json\";\n\n/** AIdol namespace */\nexport const AIDOL_NS = \"aidol\";\n\n/**\n * Translation resources for the aidol namespace.\n * Use with i18next.addResourceBundle(lang, 'aidol', translations)\n *\n * @example\n * import { aidolTranslations, AIDOL_NS } from 'aidol/locale';\n *\n * // Add to existing i18n instance\n * Object.entries(aidolTranslations).forEach(([lang, resources]) => {\n * i18n.addResourceBundle(lang, AIDOL_NS, resources);\n * });\n */\nexport const aidolTranslations = {\n en,\n es,\n id,\n ja,\n ko,\n th,\n tl,\n vi,\n zh,\n};\n"],"names":["AIdolRepository","BaseCrudRepository","aidolSchema","variables","url","raw","aidolCreateResponseSchema","fetchOptions","request","rawResponse","imageGenerationResponseSchema","generateResponseSchema","z","ChatroomRepository","chatroomSchema","chatroomId","options","params","queryString","messageSchema","content","companionId","CompanionRelationshipRepository","companionRelationshipSchema","fromCompanionId","CompanionRepository","companionSchema","aidolId","HighlightRepository","aidolHighlightSchema","highlightId","highlightMessageSchema","LeadsRepository","apiService","response","leadResponseSchema","STORAGE_KEY","schema","readStorage","stored","parsed","result","error","writeStorage","data","LocalChatroomIdsRepository","getParticle","word","withFinalConsonant","withoutFinalConsonant","code","finalConsonantIndex","AIDOL_NS","aidolTranslations","en","es","id","ja","ko","th","tl","vi","zh"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/repositories/AIdolRepository.ts","../src/repositories/ChatroomRepository.ts","../src/repositories/CompanionRelationshipRepository.ts","../src/repositories/CompanionRepository.ts","../src/repositories/HighlightRepository.ts","../src/repositories/LeadsRepository.ts","../src/repositories/LocalChatroomIdsRepository.ts","../src/lib/koreanParticle.ts","../src/i18n/translations.ts"],"sourcesContent":["import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n AIdol,\n AIdolCreate,\n AIdolCreateResponse,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport {\n aidolCreateResponseSchema,\n aidolSchema,\n imageGenerationResponseSchema,\n} from \"../schemas\";\n\nexport class AIdolRepository extends BaseCrudRepository<AIdol> {\n readonly resource = \"aidols\";\n\n protected getDataSchema() {\n return aidolSchema;\n }\n\n async createAIdol(variables: AIdolCreate): Promise<AIdolCreateResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const raw = (await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(variables),\n })) as { data: unknown };\n return aidolCreateResponseSchema.parse(raw.data);\n }\n\n async getMy(fetchOptions?: RequestInit): Promise<{ data: AIdol[] }> {\n const url = this.apiService.buildUrl(\"me/aidols\");\n const raw = (await this.apiService.request(url, fetchOptions)) as {\n data: unknown[];\n total: number;\n };\n return { data: aidolSchema.array().parse(raw.data) };\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\nimport { z } from \"zod\";\n\nimport {\n chatroomSchema,\n messageSchema,\n type Chatroom,\n type Message,\n} from \"../schemas\";\n\n/**\n * Response schema for generate AI response endpoint\n */\nconst generateResponseSchema = z.object({\n messageId: z.string(),\n content: z.string(),\n});\n\nexport interface GenerateResponse {\n messageId: string;\n content: string;\n}\n\n/**\n * Repository for Chatroom entities\n * Handles chatroom CRUD and message operations\n */\nexport class ChatroomRepository extends BaseCrudRepository<Chatroom> {\n readonly resource = \"chatrooms\";\n\n protected getDataSchema() {\n return chatroomSchema;\n }\n\n /**\n * Get messages from a chatroom\n * GET /chatrooms/{id}/messages\n */\n async getMessages(\n chatroomId: string,\n options?: { limit?: number; offset?: number },\n fetchOptions?: RequestInit,\n ): Promise<Message[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) {\n params.set(\"limit\", options.limit.toString());\n }\n if (options?.offset !== undefined) {\n params.set(\"offset\", options.offset.toString());\n }\n\n const queryString = params.toString();\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages${queryString ? `?${queryString}` : \"\"}`,\n );\n\n const rawResponse = await this.apiService.request(url, fetchOptions);\n return this.validateResponse(rawResponse, z.array(messageSchema));\n }\n\n /**\n * Send a message to a chatroom\n * POST /chatrooms/{id}/messages\n *\n * Anonymous ID is automatically sent via httpOnly cookie.\n *\n * @param chatroomId - The chatroom ID\n * @param content - The message content\n * @param fetchOptions - Optional fetch options\n */\n async sendMessage(\n chatroomId: string,\n content: string,\n fetchOptions?: RequestInit,\n ): Promise<Message> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, senderType: \"USER\" }),\n });\n\n return this.validateResponse(rawResponse, messageSchema);\n }\n\n /**\n * Generate AI response for a chatroom with a specific companion\n * POST /chatrooms/{id}/companions/{companionId}/response\n */\n async generateResponse(\n chatroomId: string,\n companionId: string,\n fetchOptions?: RequestInit,\n ): Promise<GenerateResponse> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/companions/${companionId}/response`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n return this.validateResponse(rawResponse, generateResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { CompanionRelationship } from \"../schemas\";\nimport { companionRelationshipSchema } from \"../schemas\";\n\nexport class CompanionRelationshipRepository extends BaseCrudRepository<CompanionRelationship> {\n readonly resource = \"companion-relationships\";\n\n protected getDataSchema() {\n return companionRelationshipSchema;\n }\n\n async getByFromCompanionId(fromCompanionId: string) {\n return this.getList({\n filters: [\n { field: \"from_companion_id\", operator: \"eq\", value: fromCompanionId },\n ],\n });\n }\n\n async deleteOne(params: {\n id: string | number;\n }): Promise<{ data: CompanionRelationship }> {\n const url = `${this.apiService.buildUrl(this.resource)}/${params.id}`;\n await this.apiService.request(url, { method: \"DELETE\" });\n return { data: {} as CompanionRelationship };\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n Companion,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport { companionSchema, imageGenerationResponseSchema } from \"../schemas\";\n\n/** CRUD operations use BaseCrudRepository (wrapped { data: T } responses) */\nexport class CompanionRepository extends BaseCrudRepository<Companion> {\n readonly resource = \"companions\";\n\n protected getDataSchema() {\n return companionSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { AIdolHighlight, HighlightMessage } from \"../schemas\";\nimport { aidolHighlightSchema, highlightMessageSchema } from \"../schemas\";\n\nexport class HighlightRepository extends BaseCrudRepository<AIdolHighlight> {\n readonly resource = \"aidol-highlights\";\n\n protected getDataSchema() {\n return aidolHighlightSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async getMessages(\n highlightId: string,\n fetchOptions?: RequestInit,\n ): Promise<{ data: HighlightMessage[] }> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${highlightId}/messages`,\n );\n const raw = await this.apiService.request(url, fetchOptions);\n return { data: highlightMessageSchema.array().parse(raw) };\n }\n}\n","import { z } from \"zod\";\n\nimport type { LeadRequest, LeadResponse } from \"@/schemas\";\nimport { leadResponseSchema } from \"@/schemas\";\nimport type { ApiService } from \"@/services/ApiService\";\n\nexport class LeadsRepository {\n private readonly resource = \"leads\";\n\n constructor(private readonly apiService: ApiService) {}\n\n async create(request: LeadRequest): Promise<LeadResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const response = await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n\n const wrapped = z.object({ data: leadResponseSchema }).parse(response);\n return wrapped.data;\n }\n}\n","import { z } from \"zod\";\n\nconst STORAGE_KEY = \"aidol_chatroom_ids\";\nconst schema = z.record(z.string(), z.string());\n\nconst readStorage = (): Record<string, string> => {\n if (typeof window === \"undefined\") return {};\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return {};\n\n try {\n const parsed = JSON.parse(stored);\n const result = schema.safeParse(parsed);\n if (result.success) {\n return result.data;\n }\n console.warn(`[LocalChatroomIdsRepository] Invalid data, resetting`);\n return {};\n } catch (error) {\n if (error instanceof SyntaxError) {\n console.warn(`[LocalChatroomIdsRepository] Failed to parse, resetting`);\n return {};\n }\n throw error;\n }\n};\n\nconst writeStorage = (data: Record<string, string>): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\n \"LocalChatroomIdsRepository write operations can only be called on the client side.\",\n );\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n};\n\n/**\n * Repository for managing chatroom IDs in localStorage.\n * Maps companionId to chatroomId for persistence across sessions.\n */\nexport const LocalChatroomIdsRepository = {\n getChatroomId(companionId: string): string | null {\n const data = readStorage();\n return data[companionId] ?? null;\n },\n\n setChatroomId(companionId: string, chatroomId: string): void {\n const data = readStorage();\n data[companionId] = chatroomId;\n writeStorage(data);\n },\n\n removeChatroomId(companionId: string): void {\n const data = readStorage();\n delete data[companionId];\n writeStorage(data);\n },\n};\n","// 한글의 마지막 글자를 기준으로 적절한 조사를 반환하는 함수\n// words: 조사 적용 대상 단어\n// withFinalConsonant: 받침이 있을 때 사용할 조사\n// withoutFinalConsonant: 받침이 없을 때 사용할 조사\n// 예: getParticle(\"민준\", \"과\", \"와\") => \"과\"\nexport function getParticle(\n word: string,\n withFinalConsonant: string,\n withoutFinalConsonant: string,\n): string {\n if (!word) return withoutFinalConsonant;\n\n const lastChar = word.charAt(word.length - 1);\n const code = lastChar.charCodeAt(0);\n\n // 한글 유니코드 범위 = 0xAC00 ~ 0xD7A3\n if (code < 0xac00 || code > 0xd7a3) {\n return withoutFinalConsonant;\n }\n\n // 받침 여부 (code - 0xAC00) % 28 !== 0 이면 받침 있음\n const finalConsonantIndex = (code - 0xac00) % 28;\n\n // '로/으로' 예외 처리\n if (withFinalConsonant === \"으로\" && withoutFinalConsonant === \"로\") {\n return finalConsonantIndex === 0 || finalConsonantIndex === 8\n ? \"로\"\n : \"으로\"; // 8 = ㄹ\n }\n\n return finalConsonantIndex === 0 ? withoutFinalConsonant : withFinalConsonant;\n}\n","/**\n * Server-safe exports for aidol translations.\n *\n * This module exports only JSON resources and constants,\n * avoiding React-specific code that would break SSR.\n */\n\nimport en from \"./locales/en/aidol.json\";\nimport es from \"./locales/es/aidol.json\";\nimport id from \"./locales/id/aidol.json\";\nimport ja from \"./locales/ja/aidol.json\";\nimport ko from \"./locales/ko/aidol.json\";\nimport th from \"./locales/th/aidol.json\";\nimport tl from \"./locales/tl/aidol.json\";\nimport vi from \"./locales/vi/aidol.json\";\nimport zh from \"./locales/zh/aidol.json\";\n\n/** AIdol namespace */\nexport const AIDOL_NS = \"aidol\";\n\n/**\n * Translation resources for the aidol namespace.\n * Use with i18next.addResourceBundle(lang, 'aidol', translations)\n *\n * @example\n * import { aidolTranslations, AIDOL_NS } from 'aidol/locale';\n *\n * // Add to existing i18n instance\n * Object.entries(aidolTranslations).forEach(([lang, resources]) => {\n * i18n.addResourceBundle(lang, AIDOL_NS, resources);\n * });\n */\nexport const aidolTranslations = {\n en,\n es,\n id,\n ja,\n ko,\n th,\n tl,\n vi,\n zh,\n};\n"],"names":["AIdolRepository","BaseCrudRepository","aidolSchema","variables","url","raw","aidolCreateResponseSchema","fetchOptions","request","rawResponse","imageGenerationResponseSchema","generateResponseSchema","z","ChatroomRepository","chatroomSchema","chatroomId","options","params","queryString","messageSchema","content","companionId","CompanionRelationshipRepository","companionRelationshipSchema","fromCompanionId","CompanionRepository","companionSchema","aidolId","HighlightRepository","aidolHighlightSchema","highlightId","highlightMessageSchema","LeadsRepository","apiService","response","leadResponseSchema","STORAGE_KEY","schema","readStorage","stored","parsed","result","error","writeStorage","data","LocalChatroomIdsRepository","getParticle","word","withFinalConsonant","withoutFinalConsonant","code","finalConsonantIndex","AIDOL_NS","aidolTranslations","en","es","id","ja","ko","th","tl","vi","zh"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ class wn extends l {
18
18
  return b.parse(n.data);
19
19
  }
20
20
  async getMy(e) {
21
- const a = this.apiService.buildUrl(`${this.resource}/my`), n = await this.apiService.request(a, e);
21
+ const a = this.apiService.buildUrl("me/aidols"), n = await this.apiService.request(a, e);
22
22
  return { data: g.array().parse(n.data) };
23
23
  }
24
24
  async generateImage(e, a) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/repositories/AIdolRepository.ts","../src/repositories/ChatroomRepository.ts","../src/repositories/CompanionRelationshipRepository.ts","../src/repositories/CompanionRepository.ts","../src/repositories/HighlightRepository.ts","../src/repositories/LeadsRepository.ts","../src/repositories/LocalChatroomIdsRepository.ts","../src/lib/koreanParticle.ts","../src/i18n/translations.ts"],"sourcesContent":["import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n AIdol,\n AIdolCreate,\n AIdolCreateResponse,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport {\n aidolCreateResponseSchema,\n aidolSchema,\n imageGenerationResponseSchema,\n} from \"../schemas\";\n\nexport class AIdolRepository extends BaseCrudRepository<AIdol> {\n readonly resource = \"aidols\";\n\n protected getDataSchema() {\n return aidolSchema;\n }\n\n async createAIdol(variables: AIdolCreate): Promise<AIdolCreateResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const raw = (await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(variables),\n })) as { data: unknown };\n return aidolCreateResponseSchema.parse(raw.data);\n }\n\n async getMy(fetchOptions?: RequestInit): Promise<{ data: AIdol[] }> {\n const url = this.apiService.buildUrl(`${this.resource}/my`);\n const raw = (await this.apiService.request(url, fetchOptions)) as {\n data: unknown[];\n total: number;\n };\n return { data: aidolSchema.array().parse(raw.data) };\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\nimport { z } from \"zod\";\n\nimport {\n chatroomSchema,\n messageSchema,\n type Chatroom,\n type Message,\n} from \"../schemas\";\n\n/**\n * Response schema for generate AI response endpoint\n */\nconst generateResponseSchema = z.object({\n messageId: z.string(),\n content: z.string(),\n});\n\nexport interface GenerateResponse {\n messageId: string;\n content: string;\n}\n\n/**\n * Repository for Chatroom entities\n * Handles chatroom CRUD and message operations\n */\nexport class ChatroomRepository extends BaseCrudRepository<Chatroom> {\n readonly resource = \"chatrooms\";\n\n protected getDataSchema() {\n return chatroomSchema;\n }\n\n /**\n * Get messages from a chatroom\n * GET /chatrooms/{id}/messages\n */\n async getMessages(\n chatroomId: string,\n options?: { limit?: number; offset?: number },\n fetchOptions?: RequestInit,\n ): Promise<Message[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) {\n params.set(\"limit\", options.limit.toString());\n }\n if (options?.offset !== undefined) {\n params.set(\"offset\", options.offset.toString());\n }\n\n const queryString = params.toString();\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages${queryString ? `?${queryString}` : \"\"}`,\n );\n\n const rawResponse = await this.apiService.request(url, fetchOptions);\n return this.validateResponse(rawResponse, z.array(messageSchema));\n }\n\n /**\n * Send a message to a chatroom\n * POST /chatrooms/{id}/messages\n *\n * Anonymous ID is automatically sent via httpOnly cookie.\n *\n * @param chatroomId - The chatroom ID\n * @param content - The message content\n * @param fetchOptions - Optional fetch options\n */\n async sendMessage(\n chatroomId: string,\n content: string,\n fetchOptions?: RequestInit,\n ): Promise<Message> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, senderType: \"USER\" }),\n });\n\n return this.validateResponse(rawResponse, messageSchema);\n }\n\n /**\n * Generate AI response for a chatroom with a specific companion\n * POST /chatrooms/{id}/companions/{companionId}/response\n */\n async generateResponse(\n chatroomId: string,\n companionId: string,\n fetchOptions?: RequestInit,\n ): Promise<GenerateResponse> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/companions/${companionId}/response`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n return this.validateResponse(rawResponse, generateResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { CompanionRelationship } from \"../schemas\";\nimport { companionRelationshipSchema } from \"../schemas\";\n\nexport class CompanionRelationshipRepository extends BaseCrudRepository<CompanionRelationship> {\n readonly resource = \"companion-relationships\";\n\n protected getDataSchema() {\n return companionRelationshipSchema;\n }\n\n async getByFromCompanionId(fromCompanionId: string) {\n return this.getList({\n filters: [\n { field: \"from_companion_id\", operator: \"eq\", value: fromCompanionId },\n ],\n });\n }\n\n async deleteOne(params: {\n id: string | number;\n }): Promise<{ data: CompanionRelationship }> {\n const url = `${this.apiService.buildUrl(this.resource)}/${params.id}`;\n await this.apiService.request(url, { method: \"DELETE\" });\n return { data: {} as CompanionRelationship };\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n Companion,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport { companionSchema, imageGenerationResponseSchema } from \"../schemas\";\n\n/** CRUD operations use BaseCrudRepository (wrapped { data: T } responses) */\nexport class CompanionRepository extends BaseCrudRepository<Companion> {\n readonly resource = \"companions\";\n\n protected getDataSchema() {\n return companionSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { AIdolHighlight, HighlightMessage } from \"../schemas\";\nimport { aidolHighlightSchema, highlightMessageSchema } from \"../schemas\";\n\nexport class HighlightRepository extends BaseCrudRepository<AIdolHighlight> {\n readonly resource = \"aidol-highlights\";\n\n protected getDataSchema() {\n return aidolHighlightSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async getMessages(\n highlightId: string,\n fetchOptions?: RequestInit,\n ): Promise<{ data: HighlightMessage[] }> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${highlightId}/messages`,\n );\n const raw = await this.apiService.request(url, fetchOptions);\n return { data: highlightMessageSchema.array().parse(raw) };\n }\n}\n","import { z } from \"zod\";\n\nimport type { LeadRequest, LeadResponse } from \"@/schemas\";\nimport { leadResponseSchema } from \"@/schemas\";\nimport type { ApiService } from \"@/services/ApiService\";\n\nexport class LeadsRepository {\n private readonly resource = \"leads\";\n\n constructor(private readonly apiService: ApiService) {}\n\n async create(request: LeadRequest): Promise<LeadResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const response = await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n\n const wrapped = z.object({ data: leadResponseSchema }).parse(response);\n return wrapped.data;\n }\n}\n","import { z } from \"zod\";\n\nconst STORAGE_KEY = \"aidol_chatroom_ids\";\nconst schema = z.record(z.string(), z.string());\n\nconst readStorage = (): Record<string, string> => {\n if (typeof window === \"undefined\") return {};\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return {};\n\n try {\n const parsed = JSON.parse(stored);\n const result = schema.safeParse(parsed);\n if (result.success) {\n return result.data;\n }\n console.warn(`[LocalChatroomIdsRepository] Invalid data, resetting`);\n return {};\n } catch (error) {\n if (error instanceof SyntaxError) {\n console.warn(`[LocalChatroomIdsRepository] Failed to parse, resetting`);\n return {};\n }\n throw error;\n }\n};\n\nconst writeStorage = (data: Record<string, string>): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\n \"LocalChatroomIdsRepository write operations can only be called on the client side.\",\n );\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n};\n\n/**\n * Repository for managing chatroom IDs in localStorage.\n * Maps companionId to chatroomId for persistence across sessions.\n */\nexport const LocalChatroomIdsRepository = {\n getChatroomId(companionId: string): string | null {\n const data = readStorage();\n return data[companionId] ?? null;\n },\n\n setChatroomId(companionId: string, chatroomId: string): void {\n const data = readStorage();\n data[companionId] = chatroomId;\n writeStorage(data);\n },\n\n removeChatroomId(companionId: string): void {\n const data = readStorage();\n delete data[companionId];\n writeStorage(data);\n },\n};\n","// 한글의 마지막 글자를 기준으로 적절한 조사를 반환하는 함수\n// words: 조사 적용 대상 단어\n// withFinalConsonant: 받침이 있을 때 사용할 조사\n// withoutFinalConsonant: 받침이 없을 때 사용할 조사\n// 예: getParticle(\"민준\", \"과\", \"와\") => \"과\"\nexport function getParticle(\n word: string,\n withFinalConsonant: string,\n withoutFinalConsonant: string,\n): string {\n if (!word) return withoutFinalConsonant;\n\n const lastChar = word.charAt(word.length - 1);\n const code = lastChar.charCodeAt(0);\n\n // 한글 유니코드 범위 = 0xAC00 ~ 0xD7A3\n if (code < 0xac00 || code > 0xd7a3) {\n return withoutFinalConsonant;\n }\n\n // 받침 여부 (code - 0xAC00) % 28 !== 0 이면 받침 있음\n const finalConsonantIndex = (code - 0xac00) % 28;\n\n // '로/으로' 예외 처리\n if (withFinalConsonant === \"으로\" && withoutFinalConsonant === \"로\") {\n return finalConsonantIndex === 0 || finalConsonantIndex === 8\n ? \"로\"\n : \"으로\"; // 8 = ㄹ\n }\n\n return finalConsonantIndex === 0 ? withoutFinalConsonant : withFinalConsonant;\n}\n","/**\n * Server-safe exports for aidol translations.\n *\n * This module exports only JSON resources and constants,\n * avoiding React-specific code that would break SSR.\n */\n\nimport en from \"./locales/en/aidol.json\";\nimport es from \"./locales/es/aidol.json\";\nimport id from \"./locales/id/aidol.json\";\nimport ja from \"./locales/ja/aidol.json\";\nimport ko from \"./locales/ko/aidol.json\";\nimport th from \"./locales/th/aidol.json\";\nimport tl from \"./locales/tl/aidol.json\";\nimport vi from \"./locales/vi/aidol.json\";\nimport zh from \"./locales/zh/aidol.json\";\n\n/** AIdol namespace */\nexport const AIDOL_NS = \"aidol\";\n\n/**\n * Translation resources for the aidol namespace.\n * Use with i18next.addResourceBundle(lang, 'aidol', translations)\n *\n * @example\n * import { aidolTranslations, AIDOL_NS } from 'aidol/locale';\n *\n * // Add to existing i18n instance\n * Object.entries(aidolTranslations).forEach(([lang, resources]) => {\n * i18n.addResourceBundle(lang, AIDOL_NS, resources);\n * });\n */\nexport const aidolTranslations = {\n en,\n es,\n id,\n ja,\n ko,\n th,\n tl,\n vi,\n zh,\n};\n"],"names":["AIdolRepository","BaseCrudRepository","aidolSchema","variables","url","raw","aidolCreateResponseSchema","fetchOptions","request","rawResponse","imageGenerationResponseSchema","generateResponseSchema","z","ChatroomRepository","chatroomSchema","chatroomId","options","params","queryString","messageSchema","content","companionId","CompanionRelationshipRepository","companionRelationshipSchema","fromCompanionId","CompanionRepository","companionSchema","aidolId","HighlightRepository","aidolHighlightSchema","highlightId","highlightMessageSchema","LeadsRepository","apiService","response","leadResponseSchema","STORAGE_KEY","schema","readStorage","stored","parsed","result","error","writeStorage","data","LocalChatroomIdsRepository","getParticle","word","withFinalConsonant","withoutFinalConsonant","code","finalConsonantIndex","AIDOL_NS","aidolTranslations","en","es","id","ja","ko","th","tl","vi","zh"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/repositories/AIdolRepository.ts","../src/repositories/ChatroomRepository.ts","../src/repositories/CompanionRelationshipRepository.ts","../src/repositories/CompanionRepository.ts","../src/repositories/HighlightRepository.ts","../src/repositories/LeadsRepository.ts","../src/repositories/LocalChatroomIdsRepository.ts","../src/lib/koreanParticle.ts","../src/i18n/translations.ts"],"sourcesContent":["import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n AIdol,\n AIdolCreate,\n AIdolCreateResponse,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport {\n aidolCreateResponseSchema,\n aidolSchema,\n imageGenerationResponseSchema,\n} from \"../schemas\";\n\nexport class AIdolRepository extends BaseCrudRepository<AIdol> {\n readonly resource = \"aidols\";\n\n protected getDataSchema() {\n return aidolSchema;\n }\n\n async createAIdol(variables: AIdolCreate): Promise<AIdolCreateResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const raw = (await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(variables),\n })) as { data: unknown };\n return aidolCreateResponseSchema.parse(raw.data);\n }\n\n async getMy(fetchOptions?: RequestInit): Promise<{ data: AIdol[] }> {\n const url = this.apiService.buildUrl(\"me/aidols\");\n const raw = (await this.apiService.request(url, fetchOptions)) as {\n data: unknown[];\n total: number;\n };\n return { data: aidolSchema.array().parse(raw.data) };\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\nimport { z } from \"zod\";\n\nimport {\n chatroomSchema,\n messageSchema,\n type Chatroom,\n type Message,\n} from \"../schemas\";\n\n/**\n * Response schema for generate AI response endpoint\n */\nconst generateResponseSchema = z.object({\n messageId: z.string(),\n content: z.string(),\n});\n\nexport interface GenerateResponse {\n messageId: string;\n content: string;\n}\n\n/**\n * Repository for Chatroom entities\n * Handles chatroom CRUD and message operations\n */\nexport class ChatroomRepository extends BaseCrudRepository<Chatroom> {\n readonly resource = \"chatrooms\";\n\n protected getDataSchema() {\n return chatroomSchema;\n }\n\n /**\n * Get messages from a chatroom\n * GET /chatrooms/{id}/messages\n */\n async getMessages(\n chatroomId: string,\n options?: { limit?: number; offset?: number },\n fetchOptions?: RequestInit,\n ): Promise<Message[]> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) {\n params.set(\"limit\", options.limit.toString());\n }\n if (options?.offset !== undefined) {\n params.set(\"offset\", options.offset.toString());\n }\n\n const queryString = params.toString();\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages${queryString ? `?${queryString}` : \"\"}`,\n );\n\n const rawResponse = await this.apiService.request(url, fetchOptions);\n return this.validateResponse(rawResponse, z.array(messageSchema));\n }\n\n /**\n * Send a message to a chatroom\n * POST /chatrooms/{id}/messages\n *\n * Anonymous ID is automatically sent via httpOnly cookie.\n *\n * @param chatroomId - The chatroom ID\n * @param content - The message content\n * @param fetchOptions - Optional fetch options\n */\n async sendMessage(\n chatroomId: string,\n content: string,\n fetchOptions?: RequestInit,\n ): Promise<Message> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/messages`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, senderType: \"USER\" }),\n });\n\n return this.validateResponse(rawResponse, messageSchema);\n }\n\n /**\n * Generate AI response for a chatroom with a specific companion\n * POST /chatrooms/{id}/companions/{companionId}/response\n */\n async generateResponse(\n chatroomId: string,\n companionId: string,\n fetchOptions?: RequestInit,\n ): Promise<GenerateResponse> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${chatroomId}/companions/${companionId}/response`,\n );\n\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n return this.validateResponse(rawResponse, generateResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { CompanionRelationship } from \"../schemas\";\nimport { companionRelationshipSchema } from \"../schemas\";\n\nexport class CompanionRelationshipRepository extends BaseCrudRepository<CompanionRelationship> {\n readonly resource = \"companion-relationships\";\n\n protected getDataSchema() {\n return companionRelationshipSchema;\n }\n\n async getByFromCompanionId(fromCompanionId: string) {\n return this.getList({\n filters: [\n { field: \"from_companion_id\", operator: \"eq\", value: fromCompanionId },\n ],\n });\n }\n\n async deleteOne(params: {\n id: string | number;\n }): Promise<{ data: CompanionRelationship }> {\n const url = `${this.apiService.buildUrl(this.resource)}/${params.id}`;\n await this.apiService.request(url, { method: \"DELETE\" });\n return { data: {} as CompanionRelationship };\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type {\n Companion,\n ImageGenerationRequest,\n ImageGenerationResponse,\n} from \"../schemas\";\nimport { companionSchema, imageGenerationResponseSchema } from \"../schemas\";\n\n/** CRUD operations use BaseCrudRepository (wrapped { data: T } responses) */\nexport class CompanionRepository extends BaseCrudRepository<Companion> {\n readonly resource = \"companions\";\n\n protected getDataSchema() {\n return companionSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async generateImage(\n request: ImageGenerationRequest,\n fetchOptions?: RequestInit,\n ): Promise<ImageGenerationResponse> {\n const url = this.apiService.buildUrl(`${this.resource}/images`);\n const rawResponse = await this.apiService.request(url, {\n ...fetchOptions,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n return this.validateResponse(rawResponse, imageGenerationResponseSchema);\n }\n}\n","import { BaseCrudRepository } from \"@aioia/core\";\n\nimport type { AIdolHighlight, HighlightMessage } from \"../schemas\";\nimport { aidolHighlightSchema, highlightMessageSchema } from \"../schemas\";\n\nexport class HighlightRepository extends BaseCrudRepository<AIdolHighlight> {\n readonly resource = \"aidol-highlights\";\n\n protected getDataSchema() {\n return aidolHighlightSchema;\n }\n\n async getByAidolId(aidolId: string) {\n return this.getList({\n filters: [{ field: \"aidol_id\", operator: \"eq\", value: aidolId }],\n });\n }\n\n async getMessages(\n highlightId: string,\n fetchOptions?: RequestInit,\n ): Promise<{ data: HighlightMessage[] }> {\n const url = this.apiService.buildUrl(\n `${this.resource}/${highlightId}/messages`,\n );\n const raw = await this.apiService.request(url, fetchOptions);\n return { data: highlightMessageSchema.array().parse(raw) };\n }\n}\n","import { z } from \"zod\";\n\nimport type { LeadRequest, LeadResponse } from \"@/schemas\";\nimport { leadResponseSchema } from \"@/schemas\";\nimport type { ApiService } from \"@/services/ApiService\";\n\nexport class LeadsRepository {\n private readonly resource = \"leads\";\n\n constructor(private readonly apiService: ApiService) {}\n\n async create(request: LeadRequest): Promise<LeadResponse> {\n const url = this.apiService.buildUrl(this.resource);\n const response = await this.apiService.request(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n\n const wrapped = z.object({ data: leadResponseSchema }).parse(response);\n return wrapped.data;\n }\n}\n","import { z } from \"zod\";\n\nconst STORAGE_KEY = \"aidol_chatroom_ids\";\nconst schema = z.record(z.string(), z.string());\n\nconst readStorage = (): Record<string, string> => {\n if (typeof window === \"undefined\") return {};\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return {};\n\n try {\n const parsed = JSON.parse(stored);\n const result = schema.safeParse(parsed);\n if (result.success) {\n return result.data;\n }\n console.warn(`[LocalChatroomIdsRepository] Invalid data, resetting`);\n return {};\n } catch (error) {\n if (error instanceof SyntaxError) {\n console.warn(`[LocalChatroomIdsRepository] Failed to parse, resetting`);\n return {};\n }\n throw error;\n }\n};\n\nconst writeStorage = (data: Record<string, string>): void => {\n if (typeof window === \"undefined\") {\n throw new Error(\n \"LocalChatroomIdsRepository write operations can only be called on the client side.\",\n );\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n};\n\n/**\n * Repository for managing chatroom IDs in localStorage.\n * Maps companionId to chatroomId for persistence across sessions.\n */\nexport const LocalChatroomIdsRepository = {\n getChatroomId(companionId: string): string | null {\n const data = readStorage();\n return data[companionId] ?? null;\n },\n\n setChatroomId(companionId: string, chatroomId: string): void {\n const data = readStorage();\n data[companionId] = chatroomId;\n writeStorage(data);\n },\n\n removeChatroomId(companionId: string): void {\n const data = readStorage();\n delete data[companionId];\n writeStorage(data);\n },\n};\n","// 한글의 마지막 글자를 기준으로 적절한 조사를 반환하는 함수\n// words: 조사 적용 대상 단어\n// withFinalConsonant: 받침이 있을 때 사용할 조사\n// withoutFinalConsonant: 받침이 없을 때 사용할 조사\n// 예: getParticle(\"민준\", \"과\", \"와\") => \"과\"\nexport function getParticle(\n word: string,\n withFinalConsonant: string,\n withoutFinalConsonant: string,\n): string {\n if (!word) return withoutFinalConsonant;\n\n const lastChar = word.charAt(word.length - 1);\n const code = lastChar.charCodeAt(0);\n\n // 한글 유니코드 범위 = 0xAC00 ~ 0xD7A3\n if (code < 0xac00 || code > 0xd7a3) {\n return withoutFinalConsonant;\n }\n\n // 받침 여부 (code - 0xAC00) % 28 !== 0 이면 받침 있음\n const finalConsonantIndex = (code - 0xac00) % 28;\n\n // '로/으로' 예외 처리\n if (withFinalConsonant === \"으로\" && withoutFinalConsonant === \"로\") {\n return finalConsonantIndex === 0 || finalConsonantIndex === 8\n ? \"로\"\n : \"으로\"; // 8 = ㄹ\n }\n\n return finalConsonantIndex === 0 ? withoutFinalConsonant : withFinalConsonant;\n}\n","/**\n * Server-safe exports for aidol translations.\n *\n * This module exports only JSON resources and constants,\n * avoiding React-specific code that would break SSR.\n */\n\nimport en from \"./locales/en/aidol.json\";\nimport es from \"./locales/es/aidol.json\";\nimport id from \"./locales/id/aidol.json\";\nimport ja from \"./locales/ja/aidol.json\";\nimport ko from \"./locales/ko/aidol.json\";\nimport th from \"./locales/th/aidol.json\";\nimport tl from \"./locales/tl/aidol.json\";\nimport vi from \"./locales/vi/aidol.json\";\nimport zh from \"./locales/zh/aidol.json\";\n\n/** AIdol namespace */\nexport const AIDOL_NS = \"aidol\";\n\n/**\n * Translation resources for the aidol namespace.\n * Use with i18next.addResourceBundle(lang, 'aidol', translations)\n *\n * @example\n * import { aidolTranslations, AIDOL_NS } from 'aidol/locale';\n *\n * // Add to existing i18n instance\n * Object.entries(aidolTranslations).forEach(([lang, resources]) => {\n * i18n.addResourceBundle(lang, AIDOL_NS, resources);\n * });\n */\nexport const aidolTranslations = {\n en,\n es,\n id,\n ja,\n ko,\n th,\n tl,\n vi,\n zh,\n};\n"],"names":["AIdolRepository","BaseCrudRepository","aidolSchema","variables","url","raw","aidolCreateResponseSchema","fetchOptions","request","rawResponse","imageGenerationResponseSchema","generateResponseSchema","z","ChatroomRepository","chatroomSchema","chatroomId","options","params","queryString","messageSchema","content","companionId","CompanionRelationshipRepository","companionRelationshipSchema","fromCompanionId","CompanionRepository","companionSchema","aidolId","HighlightRepository","aidolHighlightSchema","highlightId","highlightMessageSchema","LeadsRepository","apiService","response","leadResponseSchema","STORAGE_KEY","schema","readStorage","stored","parsed","result","error","writeStorage","data","LocalChatroomIdsRepository","getParticle","word","withFinalConsonant","withoutFinalConsonant","code","finalConsonantIndex","AIDOL_NS","aidolTranslations","en","es","id","ja","ko","th","tl","vi","zh"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aidol",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "React components for AIdol - Create and chat with your own AI idol group",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",