+ inspiracao.configurar({ ligado: v })} />
+ inspiracao.configurar({ aprendi: v })}
+ />
+
+
+
+
+
+
+
+ {/if}
+ {/if}
+
+
+
diff --git a/web/src/lib/criacao.svelte.ts b/web/src/lib/criacao.svelte.ts
index 05f4cf4..6480392 100644
--- a/web/src/lib/criacao.svelte.ts
+++ b/web/src/lib/criacao.svelte.ts
@@ -18,6 +18,9 @@ export interface ItemCriado {
receita: any;
ia: IaCriacao;
pedido: string;
+ origem?: 'pedido' | 'dia';
+ motivo?: string;
+ aprendi?: string;
}
export interface Provedor {
diff --git a/web/src/lib/estado.svelte.ts b/web/src/lib/estado.svelte.ts
index 6b94b76..1f7a328 100644
--- a/web/src/lib/estado.svelte.ts
+++ b/web/src/lib/estado.svelte.ts
@@ -117,6 +117,8 @@ const tratadores: Record void> = {
expressao: (d: { ordem: string }) => {
// 'humor x' é o modo vida avisando o celular; aparece no cartão Vida, não no feed
if (d.ordem === 'calma' || /^(humor|ritmo|zanga|sono) /.test(d.ordem)) return;
+ // contar o que aprendeu já aparece no diário do cartão Vida
+ if (d.ordem.startsWith('aprendi ')) return;
const criada = /^(expressao|atividade)_criada (.*)$/.exec(d.ordem);
if (criada) {
let nome = '';
@@ -183,7 +185,7 @@ function abrirEventos() {
if (estado.conexao !== 'token') estado.conexao = 'caiu';
};
for (const tipo of ['expressao', 'telemetria', 'app_config', 'aparencia', 'motores', 'estop', 'conversa', 'ia',
- 'reacao', 'treinamento', 'historico', 'pir', 'vida', 'criacao']) {
+ 'reacao', 'treinamento', 'historico', 'pir', 'vida', 'criacao', 'inspiracao']) {
fonte.addEventListener(tipo, (e) => {
const dados = JSON.parse((e as MessageEvent).data);
tratadores[tipo]?.(dados);
diff --git a/web/src/lib/guia.ts b/web/src/lib/guia.ts
index c787c79..a6e77be 100644
--- a/web/src/lib/guia.ts
+++ b/web/src/lib/guia.ts
@@ -196,6 +196,21 @@ export const TOPICOS: Record = {
{ emoji: '⭐', nome: 'Favoritos', texto: 'A estrela põe expressões e atividades criadas na grade de favoritos do Ao vivo (e nas teclas 1 a 9).' },
],
},
+ ideias: {
+ titulo: 'Ideias do dia',
+ emoji: '💡',
+ onde: 'Criar com IA › Ideias do dia',
+ resumo:
+ 'Todo dia, a partir do horário escolhido, ele procura inspiração na internet e o Gemini cria atividades novas (3 por padrão). A IA descarta tragédias, política e afins: só entram temas leves. As novidades entram na rotina do modo vida, as de hoje com mais chance, e ficam na grade do estúdio para tocar, favoritar ou apagar.',
+ itens: [
+ { emoji: '🌦️', nome: 'Tempo da cidade', texto: 'Chuva, sol, frio e calor de hoje na cidade escolhida (Open-Meteo). Ex.: dia de chuva vira "lendo com chá".' },
+ { emoji: '📅', nome: 'Datas comemorativas', texto: 'Feriados (BrasilAPI) e datas como Dia das Crianças, Dia da Pizza, Halloween e Natal, de hoje e dos próximos dias.' },
+ { emoji: '📜', nome: 'Neste dia na história', texto: 'Fatos que aconteceram neste dia, da Wikipédia em português.' },
+ { emoji: '📈', nome: 'Assuntos em alta', texto: 'O que o pessoal está procurando hoje no Google Brasil. Política e notícias tristes são ignoradas.' },
+ { emoji: '🤓', nome: 'Olha o que eu aprendi hoje', texto: 'Cada ideia vem com uma curiosidade. Quando tem alguém perto, ele conta, com legenda e voz de robô (até 2 vezes por dia cada uma). O botão "Contar" faz ele contar na hora.' },
+ { emoji: '💳', nome: 'Custo', texto: 'Uma chamada ao Gemini para escolher as ideias e uma por atividade: 4 por dia com o padrão de 3.' },
+ ],
+ },
personalidade: {
titulo: 'IA local (Qwen)',
emoji: '🧠',
@@ -319,7 +334,7 @@ export const TOPICOS: Record = {
/** Ordem do tutorial (página Guia). */
export const ORDEM_GUIA = [
- 'inicio', 'vida', 'cuidados', 'humores', 'ritmo', 'sono', 'celular', 'camera', 'gestos', 'atividades', 'criar', 'aparencia',
+ 'inicio', 'vida', 'cuidados', 'humores', 'ritmo', 'sono', 'celular', 'camera', 'gestos', 'atividades', 'criar', 'ideias', 'aparencia',
'personalidade', 'acontecimentos', 'eventos', 'presenca', 'tela', 'sensores', 'sensibilidade',
'reacoes', 'conversa', 'movimento', 'atalhos',
];
diff --git a/web/src/lib/inspiracao.svelte.ts b/web/src/lib/inspiracao.svelte.ts
new file mode 100644
index 0000000..5218d7e
--- /dev/null
+++ b/web/src/lib/inspiracao.svelte.ts
@@ -0,0 +1,78 @@
+/**
+ * Ideias do dia (/criacao/dia): todo dia o Carinha cria atividades novas inspiradas no tempo, nas
+ * datas, no "neste dia" da Wikipédia e no que está em alta, e conta o que aprendeu com cada uma.
+ * O estado chega por SSE ('inspiracao') e é recarregado ao abrir a tela.
+ */
+import { pedir, postar } from './api';
+import { avisos, tentar } from './avisos.svelte';
+import { ouvir } from './estado.svelte';
+
+export type Fonte = 'tempo' | 'datas' | 'historia' | 'alta';
+
+export interface ConfigInspiracao {
+ ligado: boolean;
+ por_dia: number;
+ hora: number;
+ aprendi: boolean;
+ cidade: { nome: string; lat: number; lon: number };
+ fontes: Record;
+}
+
+export interface IdeiaDoDia {
+ id: number;
+ nome: string;
+ emoji: string;
+ motivo: string;
+ aprendi: string;
+ horario: number;
+}
+
+export interface StatusInspiracao {
+ config: ConfigInspiracao;
+ fontes: Record;
+ ocupado: boolean;
+ pode: boolean;
+ dia: string;
+ erro: string;
+ tentativas: number;
+ feito_em: number | null;
+ sinais: Partial>;
+ contadas: Record;
+ ideias: IdeiaDoDia[];
+}
+
+class Inspiracao {
+ status = $state(null);
+
+ async carregar() {
+ try {
+ this.status = await pedir('/criacao/dia');
+ } catch (e) {
+ avisos.erro(e);
+ }
+ }
+
+ async configurar(dados: Partial> & { cidade?: string }, aviso?: string) {
+ const r = await tentar(() => postar('/criacao/dia/config', dados), aviso);
+ if (r) this.status = r;
+ return !!r;
+ }
+
+ agora() {
+ return tentar(() => postar('/criacao/dia/agora', {}), 'Procurando ideias na internet…');
+ }
+
+ contar(id: number) {
+ return tentar(() => postar('/criacao/dia/contar', { id }));
+ }
+}
+
+export const inspiracao = new Inspiracao();
+ouvir('inspiracao', (d: StatusInspiracao) => {
+ const antes = inspiracao.status;
+ inspiracao.status = d;
+ if (antes?.ocupado && !d.ocupado) {
+ if (d.erro) avisos.erro(new Error(d.erro));
+ else if (d.ideias.length > (antes.ideias?.length ?? 0)) avisos.ok(`Ideias novas: ${d.ideias.slice(antes.ideias.length).map((i) => i.emoji + ' ' + i.nome).join(', ')}`);
+ }
+});
diff --git a/web/src/telas/Criar.svelte b/web/src/telas/Criar.svelte
index 51e1f25..b96eac2 100644
--- a/web/src/telas/Criar.svelte
+++ b/web/src/telas/Criar.svelte
@@ -3,6 +3,7 @@
import { onMount } from 'svelte';
import { favoritos } from '../lib/comandos.svelte';
import Card from '../lib/componentes/Card.svelte';
+ import IdeiasDoDia from '../lib/componentes/IdeiasDoDia.svelte';
import RostoPrevia from '../lib/componentes/RostoPrevia.svelte';
import Selo from '../lib/componentes/Selo.svelte';
import { criacao, TIPOS, type IaCriacao, type TipoCriacao } from '../lib/criacao.svelte';
@@ -153,6 +154,8 @@