feat: 角色视觉体系(头像按角色取)+ 时间注入(loop 每轮当前时间)
【角色视觉体系(红线:每个角色自己的头像/背景,绝不串用昔涟)】
- persona.go:Persona 加 Visual{avatar, chatBackground{landscape,portrait}} + DefaultAvatar;每个角色各自配。
- cyrene.yaml:昔涟配 avatar(3F-Q-Happy-1) + chatBackground(横/竖屏)。
- PersonaStore 加 Persona(id);PersonaSummary 加 avatar/chatBackground;collectPersonas 按角色取
Persona(id) 视觉(无视觉→空,前端回退默认占位,绝不串角色)。
- 前端:types PersonaRecord 加 avatar/chatBackground;persona.ts personaAvatar(p)=p?.avatar||默认占位
(殊无昔涟 fallback);store 加 currentPersona;App 挂载 fetchPersonas 取默认角色;
TopBar/chat 头像改 personaAvatar(currentPersona)(写死昔涟头像已清除)。
【时间注入(她自然知道现在几点,深夜催睡交给人格/capacity)】
- options.go Options 加 Timezone;loop.go Loop 加 timeLocation/timeZoneName + New 解析 + loadTimezone;
time.go currentTimeBlock()(当前时间+周几+时区,每轮刷新);memory.go assembleContext 在「工作记忆」
前注入时间 system(keyed 在 timeLocation!=nil,无时区不注入不破坏测试);wire.go Timezone=a.cfg.Timezone。
go build/vet/test 全绿(gateway/loop/persona);前端 tsc/vite build 75模块绿。红线无写死昔涟头像。
This commit is contained in:
1 parent
950bea9758
commit
7455d09d05
20 files changed
+177
-6
No files matched your search
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import { useAppStore } from "../store/useAppStore";
|
||||
import { useModeStore } from "../store/useModeStore";
|
||||
import { applyTheme, readTheme, type ThemeMode } from "../lib/theme";
|
||||
import { personaAvatar } from "../lib/persona";
|
||||
import type { Mode, WsStatus } from "../lib/types";
|
||||
import { Tag } from "./primitives";
|
||||
import { Icon, type IconName } from "./Icon";
|
||||
@@ -27,6 +28,7 @@ const wsMeta: Record<WsStatus, { label: string; tone: "ok" | "warn" | "neutral"
|
||||
export function TopBar(): React.ReactNode {
|
||||
const wsStatus = useAppStore((s) => s.wsStatus);
|
||||
const mood = useAppStore((s) => s.mood);
|
||||
const currentPersona = useAppStore((s) => s.currentPersona);
|
||||
const mode = useModeStore((s) => s.mode);
|
||||
const [theme, setTheme] = useState<ThemeMode>(readTheme);
|
||||
|
||||
@@ -41,7 +43,7 @@ export function TopBar(): React.ReactNode {
|
||||
return (
|
||||
<header className="glass sticky top-0 z-30 flex h-[var(--mu-topbar-h)] items-center gap-3 border-b border-[var(--mu-glass-border)] px-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<img src="/images/Cyrene_Avatar/3rd_Form/Cyrene-3F-Q-Happy-1.png" alt="Cyrene" className="h-7 w-7 rounded-full object-cover" />
|
||||
<img src={personaAvatar(currentPersona)} alt={currentPersona?.name ?? "Cyrene"} className="h-7 w-7 rounded-full object-cover" />
|
||||
<div className="leading-tight">
|
||||
<div className="text-sm font-semibold">Cyrene · 昔涟</div>
|
||||
<div className="text-[11px] text-[var(--mu-text-lo)]">
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import type { ChatMessage, Mode, ToolUsed } from "../lib/types";
|
||||
import { useAppStore } from "../store/useAppStore";
|
||||
import { personaAvatar } from "../lib/persona";
|
||||
import { Tag } from "./primitives";
|
||||
import { Icon, type IconName } from "./Icon";
|
||||
import { WakePath } from "./status";
|
||||
@@ -130,10 +132,11 @@ function AssistantParaBubble({
|
||||
full: boolean;
|
||||
active?: boolean;
|
||||
}): React.ReactNode {
|
||||
const currentPersona = useAppStore((s) => s.currentPersona);
|
||||
return (
|
||||
<div className="mu-rise-in flex gap-3">
|
||||
{full ? (
|
||||
<img src="/images/Cyrene_Avatar/3rd_Form/Cyrene-3F-Q-Happy-1.png" alt="" className="mt-1 h-7 w-7 shrink-0 rounded-full object-cover" />
|
||||
<img src={personaAvatar(currentPersona)} alt="" className="mt-1 h-7 w-7 shrink-0 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-7 shrink-0" aria-hidden />
|
||||
)}
|
||||
@@ -259,9 +262,10 @@ function AssistantBubble({
|
||||
mode: Mode;
|
||||
active?: boolean;
|
||||
}): React.ReactNode {
|
||||
const currentPersona = useAppStore((s) => s.currentPersona);
|
||||
return (
|
||||
<div className="mu-rise-in flex gap-3">
|
||||
<img src="/images/Cyrene_Avatar/3rd_Form/Cyrene-3F-Q-Happy-1.png" alt="" className="mt-1 h-7 w-7 shrink-0 rounded-full object-cover" />
|
||||
<img src={personaAvatar(currentPersona)} alt="" className="mt-1 h-7 w-7 shrink-0 rounded-full object-cover" />
|
||||
<div className="min-w-0 max-w-[85%]">
|
||||
<ModeTag mode={mode} />
|
||||
{message.mood ? (
|
||||
|
||||
Reference in new issue
Block a user