mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 13:54:02 +00:00
feat(bot): add configurable household assistant behavior
This commit is contained in:
@@ -376,7 +376,9 @@ function App() {
|
||||
rentWarningDay: 17,
|
||||
utilitiesDueDay: 4,
|
||||
utilitiesReminderDay: 3,
|
||||
timezone: 'Asia/Tbilisi'
|
||||
timezone: 'Asia/Tbilisi',
|
||||
assistantContext: '',
|
||||
assistantTone: ''
|
||||
})
|
||||
const [newCategoryName, setNewCategoryName] = createSignal('')
|
||||
const [cycleForm, setCycleForm] = createSignal({
|
||||
@@ -917,7 +919,9 @@ function App() {
|
||||
rentWarningDay: payload.settings.rentWarningDay,
|
||||
utilitiesDueDay: payload.settings.utilitiesDueDay,
|
||||
utilitiesReminderDay: payload.settings.utilitiesReminderDay,
|
||||
timezone: payload.settings.timezone
|
||||
timezone: payload.settings.timezone,
|
||||
assistantContext: payload.assistantConfig.assistantContext ?? '',
|
||||
assistantTone: payload.assistantConfig.assistantTone ?? ''
|
||||
})
|
||||
setPaymentForm((current) => ({
|
||||
...current,
|
||||
@@ -1033,7 +1037,9 @@ function App() {
|
||||
rentWarningDay: demoAdminSettings.settings.rentWarningDay,
|
||||
utilitiesDueDay: demoAdminSettings.settings.utilitiesDueDay,
|
||||
utilitiesReminderDay: demoAdminSettings.settings.utilitiesReminderDay,
|
||||
timezone: demoAdminSettings.settings.timezone
|
||||
timezone: demoAdminSettings.settings.timezone,
|
||||
assistantContext: demoAdminSettings.assistantConfig.assistantContext ?? '',
|
||||
assistantTone: demoAdminSettings.assistantConfig.assistantTone ?? ''
|
||||
})
|
||||
setCycleForm((current) => ({
|
||||
...current,
|
||||
@@ -1338,12 +1344,16 @@ function App() {
|
||||
setSavingBillingSettings(true)
|
||||
|
||||
try {
|
||||
const settings = await updateMiniAppBillingSettings(initData, billingForm())
|
||||
const { settings, assistantConfig } = await updateMiniAppBillingSettings(
|
||||
initData,
|
||||
billingForm()
|
||||
)
|
||||
setAdminSettings((current) =>
|
||||
current
|
||||
? {
|
||||
...current,
|
||||
settings
|
||||
settings,
|
||||
assistantConfig
|
||||
}
|
||||
: current
|
||||
)
|
||||
@@ -2230,6 +2240,18 @@ function App() {
|
||||
timezone: value
|
||||
}))
|
||||
}
|
||||
onBillingAssistantContextChange={(value) =>
|
||||
setBillingForm((current) => ({
|
||||
...current,
|
||||
assistantContext: value
|
||||
}))
|
||||
}
|
||||
onBillingAssistantToneChange={(value) =>
|
||||
setBillingForm((current) => ({
|
||||
...current,
|
||||
assistantTone: value
|
||||
}))
|
||||
}
|
||||
onOpenAddUtilityBill={() => setAddingUtilityBillOpen(true)}
|
||||
onCloseAddUtilityBill={() => setAddingUtilityBillOpen(false)}
|
||||
onAddUtilityBill={handleAddUtilityBill}
|
||||
|
||||
@@ -203,6 +203,11 @@ export const demoAdminSettings: MiniAppAdminSettingsPayload = {
|
||||
utilitiesReminderDay: 3,
|
||||
timezone: 'Asia/Tbilisi'
|
||||
},
|
||||
assistantConfig: {
|
||||
householdId: 'demo-household',
|
||||
assistantContext: 'The household is a house in Kojori with a backyard and pine forest nearby.',
|
||||
assistantTone: 'Playful but concise'
|
||||
},
|
||||
topics: [
|
||||
{ role: 'purchase', telegramThreadId: '101', topicName: 'Purchases' },
|
||||
{ role: 'feedback', telegramThreadId: '102', topicName: 'Anonymous feedback' },
|
||||
|
||||
@@ -147,6 +147,16 @@ export const dictionary = {
|
||||
topicBound: 'Bound',
|
||||
topicUnbound: 'Unbound',
|
||||
billingSettingsTitle: 'Billing settings',
|
||||
assistantSettingsTitle: 'Bot personality',
|
||||
assistantSettingsBody:
|
||||
'Give the bot household context and a tone so replies feel grounded without getting intrusive.',
|
||||
assistantToneLabel: 'Bot mood',
|
||||
assistantTonePlaceholder: 'Playful, dry, concise, slightly sarcastic',
|
||||
assistantToneDefault: 'Default',
|
||||
assistantContextLabel: 'Household context',
|
||||
assistantContextPlaceholder:
|
||||
'The household is a house in Kojori with a backyard and pine forest nearby.',
|
||||
assistantContextEmpty: 'No custom context',
|
||||
settlementCurrency: 'Settlement currency',
|
||||
paymentBalanceAdjustmentPolicy: 'Purchase balance adjustment',
|
||||
paymentBalanceAdjustmentUtilities: 'Adjust through utilities',
|
||||
@@ -392,6 +402,15 @@ export const dictionary = {
|
||||
topicBound: 'Привязан',
|
||||
topicUnbound: 'Не привязан',
|
||||
billingSettingsTitle: 'Настройки биллинга',
|
||||
assistantSettingsTitle: 'Характер бота',
|
||||
assistantSettingsBody:
|
||||
'Задай бытовой контекст и тон, чтобы ответы бота звучали уместно и не лезли в разговор без повода.',
|
||||
assistantToneLabel: 'Настроение бота',
|
||||
assistantTonePlaceholder: 'Игривый, сухой, короткий, слегка саркастичный',
|
||||
assistantToneDefault: 'По умолчанию',
|
||||
assistantContextLabel: 'Контекст дома',
|
||||
assistantContextPlaceholder: 'Это дом в Коджори, рядом двор и сосновый лес.',
|
||||
assistantContextEmpty: 'Контекст не задан',
|
||||
settlementCurrency: 'Валюта расчёта',
|
||||
paymentBalanceAdjustmentPolicy: 'Зачёт баланса по покупкам',
|
||||
paymentBalanceAdjustmentUtilities: 'Зачитывать через коммуналку',
|
||||
|
||||
@@ -70,6 +70,12 @@ export interface MiniAppBillingSettings {
|
||||
timezone: string
|
||||
}
|
||||
|
||||
export interface MiniAppAssistantConfig {
|
||||
householdId: string
|
||||
assistantContext: string | null
|
||||
assistantTone: string | null
|
||||
}
|
||||
|
||||
export interface MiniAppUtilityCategory {
|
||||
id: string
|
||||
householdId: string
|
||||
@@ -133,6 +139,7 @@ export interface MiniAppDashboard {
|
||||
|
||||
export interface MiniAppAdminSettingsPayload {
|
||||
settings: MiniAppBillingSettings
|
||||
assistantConfig: MiniAppAssistantConfig
|
||||
topics: readonly MiniAppTopicBinding[]
|
||||
categories: readonly MiniAppUtilityCategory[]
|
||||
members: readonly MiniAppMember[]
|
||||
@@ -380,6 +387,7 @@ export async function fetchMiniAppAdminSettings(
|
||||
ok: boolean
|
||||
authorized?: boolean
|
||||
settings?: MiniAppBillingSettings
|
||||
assistantConfig?: MiniAppAssistantConfig
|
||||
topics?: MiniAppTopicBinding[]
|
||||
categories?: MiniAppUtilityCategory[]
|
||||
members?: MiniAppMember[]
|
||||
@@ -391,6 +399,7 @@ export async function fetchMiniAppAdminSettings(
|
||||
!response.ok ||
|
||||
!payload.authorized ||
|
||||
!payload.settings ||
|
||||
!payload.assistantConfig ||
|
||||
!payload.topics ||
|
||||
!payload.categories ||
|
||||
!payload.members ||
|
||||
@@ -401,6 +410,7 @@ export async function fetchMiniAppAdminSettings(
|
||||
|
||||
return {
|
||||
settings: payload.settings,
|
||||
assistantConfig: payload.assistantConfig,
|
||||
topics: payload.topics,
|
||||
categories: payload.categories,
|
||||
members: payload.members,
|
||||
@@ -420,8 +430,13 @@ export async function updateMiniAppBillingSettings(
|
||||
utilitiesDueDay: number
|
||||
utilitiesReminderDay: number
|
||||
timezone: string
|
||||
assistantContext?: string
|
||||
assistantTone?: string
|
||||
}
|
||||
): Promise<MiniAppBillingSettings> {
|
||||
): Promise<{
|
||||
settings: MiniAppBillingSettings
|
||||
assistantConfig: MiniAppAssistantConfig
|
||||
}> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/settings/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -437,14 +452,18 @@ export async function updateMiniAppBillingSettings(
|
||||
ok: boolean
|
||||
authorized?: boolean
|
||||
settings?: MiniAppBillingSettings
|
||||
assistantConfig?: MiniAppAssistantConfig
|
||||
error?: string
|
||||
}
|
||||
|
||||
if (!response.ok || !payload.authorized || !payload.settings) {
|
||||
if (!response.ok || !payload.authorized || !payload.settings || !payload.assistantConfig) {
|
||||
throw new Error(payload.error ?? 'Failed to update billing settings')
|
||||
}
|
||||
|
||||
return payload.settings
|
||||
return {
|
||||
settings: payload.settings,
|
||||
assistantConfig: payload.assistantConfig
|
||||
}
|
||||
}
|
||||
|
||||
export async function upsertMiniAppUtilityCategory(
|
||||
|
||||
@@ -37,6 +37,8 @@ type BillingForm = {
|
||||
utilitiesDueDay: number
|
||||
utilitiesReminderDay: number
|
||||
timezone: string
|
||||
assistantContext: string
|
||||
assistantTone: string
|
||||
}
|
||||
|
||||
type CycleForm = {
|
||||
@@ -121,6 +123,8 @@ type Props = {
|
||||
onBillingUtilitiesDueDayChange: (value: number | null) => void
|
||||
onBillingUtilitiesReminderDayChange: (value: number | null) => void
|
||||
onBillingTimezoneChange: (value: string) => void
|
||||
onBillingAssistantContextChange: (value: string) => void
|
||||
onBillingAssistantToneChange: (value: string) => void
|
||||
onOpenAddUtilityBill: () => void
|
||||
onCloseAddUtilityBill: () => void
|
||||
onAddUtilityBill: () => Promise<void>
|
||||
@@ -260,23 +264,22 @@ export function HouseScreen(props: Props) {
|
||||
|
||||
<article class="balance-item">
|
||||
<header>
|
||||
<strong>{props.copy.billingSettingsTitle ?? ''}</strong>
|
||||
<span>{props.billingForm.settlementCurrency}</span>
|
||||
<strong>{props.copy.assistantSettingsTitle ?? ''}</strong>
|
||||
<span>
|
||||
{props.billingForm.assistantTone || (props.copy.assistantToneDefault ?? '')}
|
||||
</span>
|
||||
</header>
|
||||
<p>
|
||||
{props.billingForm.paymentBalanceAdjustmentPolicy === 'utilities'
|
||||
? props.copy.paymentBalanceAdjustmentUtilities
|
||||
: props.billingForm.paymentBalanceAdjustmentPolicy === 'rent'
|
||||
? props.copy.paymentBalanceAdjustmentRent
|
||||
: props.copy.paymentBalanceAdjustmentSeparate}
|
||||
</p>
|
||||
<p>{props.copy.assistantSettingsBody ?? ''}</p>
|
||||
<div class="ledger-compact-card__meta">
|
||||
<span class="mini-chip">
|
||||
{props.copy.rentAmount ?? ''}: {props.billingForm.rentAmountMajor || '—'}{' '}
|
||||
{props.billingForm.rentCurrency}
|
||||
{props.copy.assistantToneLabel ?? ''}:{' '}
|
||||
{props.billingForm.assistantTone || props.copy.assistantToneDefault || '—'}
|
||||
</span>
|
||||
<span class="mini-chip mini-chip--muted">
|
||||
{props.copy.timezone ?? ''}: {props.billingForm.timezone}
|
||||
{props.copy.assistantContextLabel ?? ''}:{' '}
|
||||
{props.billingForm.assistantContext.trim().length > 0
|
||||
? props.billingForm.assistantContext.trim().slice(0, 80)
|
||||
: (props.copy.assistantContextEmpty ?? '')}
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-toolbar">
|
||||
@@ -514,6 +517,27 @@ export function HouseScreen(props: Props) {
|
||||
onInput={(event) => props.onBillingTimezoneChange(event.currentTarget.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={props.copy.assistantToneLabel ?? ''} wide>
|
||||
<input
|
||||
value={props.billingForm.assistantTone}
|
||||
maxlength="160"
|
||||
placeholder={props.copy.assistantTonePlaceholder ?? ''}
|
||||
onInput={(event) =>
|
||||
props.onBillingAssistantToneChange(event.currentTarget.value)
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={props.copy.assistantContextLabel ?? ''} wide>
|
||||
<textarea
|
||||
rows="6"
|
||||
maxlength="1200"
|
||||
placeholder={props.copy.assistantContextPlaceholder ?? ''}
|
||||
value={props.billingForm.assistantContext}
|
||||
onInput={(event) =>
|
||||
props.onBillingAssistantContextChange(event.currentTarget.value)
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</Modal>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user