@danhachuel/thunderbolt 0.6.13 → 0.6.14
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/app/main.py +2 -1
- package/hermes_ui/growth_bilibili.py +188 -0
- package/package.json +1 -1
package/app/main.py
CHANGED
|
@@ -112,6 +112,7 @@ from hermes_ui.growth_youtube import list_analyses, run_audit
|
|
|
112
112
|
from hermes_ui.growth_tiktok import render_growth_tiktok
|
|
113
113
|
from hermes_ui.growth_instagram import render_growth_instagram
|
|
114
114
|
from hermes_ui.growth_facebook_pages import render_growth_facebook_pages
|
|
115
|
+
from hermes_ui.growth_bilibili import render_growth_bilibili
|
|
115
116
|
from hermes_ui.canva_auth import authorization_url, create_pkce_pair, create_state, exchange_code
|
|
116
117
|
from integrations.platforms import IntegrationResult, TikTokAdapter, YouTubeAdapter, fetch_channel_videos_public
|
|
117
118
|
from integrations.tiktok_public import fetch_public_tiktok_profile, normalize_tiktok_reference
|
|
@@ -9076,7 +9077,7 @@ def main():
|
|
|
9076
9077
|
"Analista Growth Tiktok": render_growth_tiktok,
|
|
9077
9078
|
"Analista Growth Instagram": render_growth_instagram,
|
|
9078
9079
|
"Analista Facebook Pages": render_growth_facebook_pages,
|
|
9079
|
-
"Analista Bilibili":
|
|
9080
|
+
"Analista Bilibili": render_growth_bilibili,
|
|
9080
9081
|
"Documentação": lambda: render_edit_placeholder("Documentação", "Seleccione um tutorial no menu expansível."),
|
|
9081
9082
|
"Tutorial Meta": render_models_ai_tutorial,
|
|
9082
9083
|
"Tutorial Supabase": render_supabase_tutorial,
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from html import escape
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import streamlit as st
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
BILIBILI_CARDS: tuple[tuple[str, int, bool, tuple[tuple[str, str, str, str], ...]], ...] = (
|
|
10
|
+
(
|
|
11
|
+
"Validação de Procura",
|
|
12
|
+
70,
|
|
13
|
+
True,
|
|
14
|
+
(
|
|
15
|
+
("Tecto dos concorrentes", "A medir", "> 500k views", "A verificar"),
|
|
16
|
+
("Volume de pesquisa", "A medir", "Procura crescente", "A verificar"),
|
|
17
|
+
("Tráfego de pesquisa", "A medir", "15–30%", "A verificar"),
|
|
18
|
+
("Diagnóstico", "Validar antes de produzir", "Nicho validado", "A verificar"),
|
|
19
|
+
),
|
|
20
|
+
),
|
|
21
|
+
(
|
|
22
|
+
"Thumbnail",
|
|
23
|
+
70,
|
|
24
|
+
True,
|
|
25
|
+
(
|
|
26
|
+
("CTR", "A medir", "> 6%", "A verificar"),
|
|
27
|
+
("Contraste", "Alto contraste", "Fundo escuro + cor viva", "Meta"),
|
|
28
|
+
("Texto", "3–5 palavras", "Legível no telemóvel", "Meta"),
|
|
29
|
+
("Elementos Bilibili", "ACG quando adequado", "Visual expressivo", "Meta"),
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
(
|
|
33
|
+
"Título e Intenção",
|
|
34
|
+
70,
|
|
35
|
+
True,
|
|
36
|
+
(
|
|
37
|
+
("Estrutura", "Curiosity · Clarity · Context", "Promessa clara", "Meta"),
|
|
38
|
+
("Keyword principal", "No início", "Pesquisa Bilibili", "Meta"),
|
|
39
|
+
("CTR + retenção", "A medir", "CTR alto sem queda brusca", "A verificar"),
|
|
40
|
+
("Formato", "Why / How to / VS", "Intenção explícita", "Meta"),
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
(
|
|
44
|
+
"Hook e Retenção",
|
|
45
|
+
70,
|
|
46
|
+
False,
|
|
47
|
+
(
|
|
48
|
+
("Retenção aos 15s", "A medir", "> 50%", "A verificar"),
|
|
49
|
+
("Retenção aos 30s", "A medir", "> 70%", "A verificar"),
|
|
50
|
+
("Método", "Clímax primeiro", "Resultado antes da introdução", "Meta"),
|
|
51
|
+
("Abertura", "Sem introdução longa", "Primeiro frame forte", "Meta"),
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
(
|
|
55
|
+
"Ritmo e Edição",
|
|
56
|
+
70,
|
|
57
|
+
False,
|
|
58
|
+
(
|
|
59
|
+
("Pattern interrupt", "A cada 5–8s", "Sem imagens estáticas > 4s", "Meta"),
|
|
60
|
+
("Quedas intermédias", "A medir", "Quedas pequenas", "A verificar"),
|
|
61
|
+
("Texto danmaku", "Usar com intenção", "Comentários sobrepostos", "Meta"),
|
|
62
|
+
("Cadência visual", "A medir", "Plateau de retenção", "A verificar"),
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
(
|
|
66
|
+
"Engagement 三连",
|
|
67
|
+
70,
|
|
68
|
+
False,
|
|
69
|
+
(
|
|
70
|
+
("三连率", "A medir", "> 4%", "A verificar"),
|
|
71
|
+
("Likes + Coins + Favorites", "Três cliques", "Sinal de qualidade", "Meta"),
|
|
72
|
+
("Danmaku", "A medir", "> 5/min", "A verificar"),
|
|
73
|
+
("Comentários", "A medir", "> 1/100 views", "A verificar"),
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
(
|
|
77
|
+
"Tráfego e Algoritmo",
|
|
78
|
+
70,
|
|
79
|
+
False,
|
|
80
|
+
(
|
|
81
|
+
("Recommendation 推荐", "A medir", "40–60%", "A verificar"),
|
|
82
|
+
("Search 搜索", "A medir", "15–30%", "A verificar"),
|
|
83
|
+
("Followers 粉丝", "A medir", "10–30%", "A verificar"),
|
|
84
|
+
("External 外部", "A medir", "< 10%", "A verificar"),
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
(
|
|
88
|
+
"Conversão e Saúde",
|
|
89
|
+
70,
|
|
90
|
+
False,
|
|
91
|
+
(
|
|
92
|
+
("Conversão em followers", "A medir", "> 1%", "A verificar"),
|
|
93
|
+
("Fan Playback", "A medir", "40–60%", "A verificar"),
|
|
94
|
+
("Novos viewers", "A medir", "> 20%", "A verificar"),
|
|
95
|
+
("Abandono mensal", "A medir", "< 5%", "A verificar"),
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _card_html(card: tuple[str, int, bool, tuple[tuple[str, str, str, str], ...]]) -> str:
|
|
102
|
+
title, score, featured, rows = card
|
|
103
|
+
row_html = "".join(
|
|
104
|
+
f'<tr><td>{escape(label)}</td><td><b>{escape(value)}</b></td><td>{escape(target)}</td>'
|
|
105
|
+
f'<td><span style="color:#94a3b8;font-weight:700;">● {escape(status)}</span></td></tr>'
|
|
106
|
+
for label, value, target, status in rows
|
|
107
|
+
)
|
|
108
|
+
height = "350px" if featured else "280px"
|
|
109
|
+
title_size = "19px" if featured else "16px"
|
|
110
|
+
score_size = "38px" if featured else "30px"
|
|
111
|
+
return (
|
|
112
|
+
f'<div style="min-height:{height};border:1px solid #2b3b52;border-radius:14px;padding:16px;'
|
|
113
|
+
f'background:linear-gradient(145deg,#111c2b,#0b121c);box-shadow:0 8px 22px rgba(0,0,0,.16);">'
|
|
114
|
+
f'<div style="font-size:11px;font-weight:800;letter-spacing:.08em;color:#7dd3fc;text-transform:uppercase;">BILIBILI GROWTH</div>'
|
|
115
|
+
f'<div style="font-size:{title_size};font-weight:750;color:#f8fafc;margin-top:8px;">{escape(title)}</div>'
|
|
116
|
+
f'<div style="display:flex;align-items:baseline;gap:5px;margin:8px 0 10px;">'
|
|
117
|
+
f'<span style="font-size:{score_size};font-weight:850;color:#22c55e;">{score}</span>'
|
|
118
|
+
f'<span style="font-size:13px;color:#94a3b8;">/100 · meta do agente</span></div>'
|
|
119
|
+
f'<div style="overflow-x:auto;"><table style="width:100%;border-collapse:collapse;font-size:11px;color:#cbd5e1;">'
|
|
120
|
+
f'<thead><tr><th style="text-align:left;padding:5px 3px;border-bottom:1px solid #334155;">KPI</th>'
|
|
121
|
+
f'<th style="text-align:left;padding:5px 3px;border-bottom:1px solid #334155;">Valor</th>'
|
|
122
|
+
f'<th style="text-align:left;padding:5px 3px;border-bottom:1px solid #334155;">Meta</th>'
|
|
123
|
+
f'<th style="text-align:left;padding:5px 3px;border-bottom:1px solid #334155;">Estado</th></tr></thead>'
|
|
124
|
+
f'<tbody>{row_html}</tbody></table></div></div>'
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def render_growth_bilibili() -> None:
|
|
129
|
+
st.title("Analista Bilibili")
|
|
130
|
+
st.caption("Como o agente opera e reporta: procura, click funnel, retenção, engagement 三连 e saúde da audiência Bilibili.")
|
|
131
|
+
st.info("Esta aba define o protocolo e o dashboard de reporte do agente. Os valores privados são preenchidos quando os dados autorizados do Bilibili Studio estiverem disponíveis; não são inventados a partir de páginas públicas.")
|
|
132
|
+
|
|
133
|
+
summary_col, status_col = st.columns([3.25, 1], gap="large")
|
|
134
|
+
with summary_col:
|
|
135
|
+
st.markdown(
|
|
136
|
+
'<div style="border:1px solid #263447;border-radius:12px;padding:18px;margin:12px 0 20px;'
|
|
137
|
+
'background:#101722;display:flex;align-items:center;justify-content:space-between;min-height:76px;">'
|
|
138
|
+
'<div><div style="font-size:13px;color:#94a3b8;text-transform:uppercase;letter-spacing:.08em;">Estado do agente</div>'
|
|
139
|
+
'<div style="font-size:18px;font-weight:700;margin-top:5px;">Pronto para auditoria Bilibili</div></div>'
|
|
140
|
+
'<div style="font-size:18px;font-weight:800;color:#22c55e;">PROTOCOLO ACTIVO</div></div>',
|
|
141
|
+
unsafe_allow_html=True,
|
|
142
|
+
)
|
|
143
|
+
with status_col:
|
|
144
|
+
st.write("")
|
|
145
|
+
st.button("ANALISAR CANAL", disabled=True, use_container_width=True, key="growth_bilibili_analyse_disabled")
|
|
146
|
+
st.caption("A ligação ao Studio será usada quando autorizada.")
|
|
147
|
+
|
|
148
|
+
st.subheader("Dashboard de Growth")
|
|
149
|
+
st.caption("Os três pilares críticos aparecem primeiro; os cinco blocos operacionais completam o diagnóstico. Verde: referência de execução · Cinzento: dado a verificar no Studio.")
|
|
150
|
+
st.markdown('<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin:14px 0 18px;">' + "".join(_card_html(card) for card in BILIBILI_CARDS[:3]) + '</div>', unsafe_allow_html=True)
|
|
151
|
+
st.markdown('<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px;margin:0 0 18px;">' + "".join(_card_html(card) for card in BILIBILI_CARDS[3:]) + '</div>', unsafe_allow_html=True)
|
|
152
|
+
st.caption("Legenda: o agente compara os dados autorizados com as metas Bilibili; quando um dado não existe, apresenta “A verificar” em vez de estimar.")
|
|
153
|
+
|
|
154
|
+
st.divider()
|
|
155
|
+
operation_tab, report_tab, monetization_tab = st.tabs(["Como o agente vai operar", "Como vai reportar", "Contexto de monetização"])
|
|
156
|
+
with operation_tab:
|
|
157
|
+
st.subheader("Protocolo de auditoria em 10 passos")
|
|
158
|
+
st.markdown("""
|
|
159
|
+
1. **Validar procura:** compara o tecto de concorrentes, pesquisa e origem do tráfego.
|
|
160
|
+
2. **Avaliar thumbnail:** verifica CTR, contraste, legibilidade móvel, emoção e elementos ACG quando adequados.
|
|
161
|
+
3. **Avaliar título:** cruza CTR com retenção inicial e aplica Curiosity, Clarity e Context.
|
|
162
|
+
4. **Verificar engagement:** mede a taxa 三连 (Like + Coin + Favorite), danmaku e qualidade dos comentários.
|
|
163
|
+
5. **Diagnosticar hook:** localiza a queda dos primeiros 15–30 segundos e aplica “clímax primeiro”.
|
|
164
|
+
6. **Diagnosticar ritmo:** identifica quedas recorrentes e recomenda pattern interrupts a cada 5–8 segundos.
|
|
165
|
+
7. **Ler o algoritmo:** compara Recommendation, Search, Followers e External com as metas da plataforma.
|
|
166
|
+
8. **Medir conversão:** calcula novos followers por visualização e posiciona a CTA aos 40% do vídeo.
|
|
167
|
+
9. **Verificar cadência:** acompanha 1–2 vídeos por semana, consistência e uso de posts/live para comunidade.
|
|
168
|
+
10. **Avaliar saúde:** cruza Fan Playback, New Viewer, abandono mensal e sinais moonshot.
|
|
169
|
+
""")
|
|
170
|
+
with report_tab:
|
|
171
|
+
st.subheader("Formato do reporte entregue pelo agente")
|
|
172
|
+
st.markdown("""
|
|
173
|
+
O agente reporta sempre em cinco blocos: **projecção financeira e contexto**, **resumo dos dez pilares**, **Top 3 prioridades accionáveis**, **estratégia de longo prazo** e **checklist dos próximos passos**. Cada KPI recebe valor observado, meta, estado e origem do dado.
|
|
174
|
+
|
|
175
|
+
As três prioridades são escolhidas por impacto: primeiro **Thumbnail + Título**, depois **retenção e engagement**, e só depois produção ou expansão. O relatório distingue claramente `DADO OBSERVADO`, `A VERIFICAR` e `RECOMENDAÇÃO`, sem transformar uma meta em resultado real.
|
|
176
|
+
|
|
177
|
+
> Regra de reporte: um vídeo com conteúdo forte, mas sem click funnel, não é considerado optimizado. O agente corrige primeiro a combinação thumbnail + título e acompanha a evolução no ciclo seguinte.
|
|
178
|
+
""")
|
|
179
|
+
st.markdown("**Checklist padrão:** validar nicho · corrigir as últimas 5 thumbnails · reescrever títulos · cortar a introdução · inserir prompt danmaku · publicar em dia fixo · rever analytics em 30 dias.")
|
|
180
|
+
with monetization_tab:
|
|
181
|
+
st.subheader("Referências internas usadas pelo agente")
|
|
182
|
+
st.markdown("""
|
|
183
|
+
A projecção considera Video Incentive Program, Charging, Paid Subscriptions e Huahuo. O cálculo interno é: `Playbacks × Base Rate × Zone Multiplier × Quality Multiplier + Ad Revenue + Tips + Subscriptions`.
|
|
184
|
+
|
|
185
|
+
Para o diagnóstico inicial, o agente acompanha originalidade do conteúdo, verificação de identidade, estado da conta, direitos ≥ 3, score de crédito ≥ 80 e os limiares de audiência definidos no material Bilibili. Estes itens são **contexto de elegibilidade**, não promessa de rendimento.
|
|
186
|
+
|
|
187
|
+
Os sinais moonshot acompanhados são densidade de danmaku (> 5 por minuto), crescimento do Search Index (+20% mensal), Long-tail Traffic (> 30%), Shares (> 1%) e Collect Rate (> 5%).
|
|
188
|
+
""")
|
package/package.json
CHANGED