|
|
import gradio as gr |
|
|
from datetime import datetime |
|
|
|
|
|
DAILY_PROMPTS = [ |
|
|
"Кто ты, когда никто не видит?", |
|
|
"Что сегодня было по-настоящему твоим?", |
|
|
"Что ты делаешь из страха, а не из желания?", |
|
|
"Если бы ты знал(а), что тебя никто не осудит — что бы ты изменил(а)?", |
|
|
"Кто смотрит изнутри этих глаз?", |
|
|
"Что ты прячешь даже от себя?", |
|
|
"Что в тебе хочет быть услышанным — но молчит?" |
|
|
] |
|
|
|
|
|
PRACTICES = [ |
|
|
"Письмо от Тени", |
|
|
"Кто наблюдает?", |
|
|
"Голос из зеркала", |
|
|
"Письмо от будущего себя", |
|
|
"Тело знает" |
|
|
] |
|
|
|
|
|
def get_daily_prompt(): |
|
|
today = datetime.today().date() |
|
|
seed = hash(today.strftime("%Y-%m-%d")) % len(DAILY_PROMPTS) |
|
|
return DAILY_PROMPTS[seed] |
|
|
|
|
|
CSS = """ |
|
|
body { |
|
|
background-color: #fdfbf7 !important; |
|
|
color: #2d2b26 !important; |
|
|
} |
|
|
.gradio-container { |
|
|
background: transparent !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
with gr.Blocks(css=CSS, title="Тишина внутри") as demo: |
|
|
gr.Markdown("## 🌿 Тишина внутри") |
|
|
gr.Markdown(f"### «{get_daily_prompt()}»") |
|
|
|
|
|
|
|
|
main_note = gr.Textbox( |
|
|
label="Твоя заметка", |
|
|
placeholder="Напиши всё, что приходит…", |
|
|
lines=4, |
|
|
elem_id="main_note" |
|
|
) |
|
|
|
|
|
gr.HTML(""" |
|
|
<button style="background:#a8a29e;color:white;border:none;padding:8px 16px;border-radius:6px;margin:8px 0;cursor:pointer;" |
|
|
onclick=" |
|
|
const el = document.getElementById('main_note'); |
|
|
if (el) { |
|
|
localStorage.setItem('main-note', el.value); |
|
|
alert('✅ Сохранено'); |
|
|
} |
|
|
"> |
|
|
Сохранить |
|
|
</button> |
|
|
""") |
|
|
|
|
|
|
|
|
gr.Markdown("### Практики") |
|
|
for i, name in enumerate(PRACTICES): |
|
|
with gr.Accordion(name, open=False): |
|
|
practice_box = gr.Textbox( |
|
|
label="Твои впечатления", |
|
|
placeholder=f"Практика {i}", |
|
|
lines=3, |
|
|
elem_id=f"practice_{i}" |
|
|
) |
|
|
|
|
|
gr.HTML(f""" |
|
|
<button style="background:#a8a29e;color:white;border:none;padding:8px 16px;border-radius:6px;margin:8px 0;cursor:pointer;" |
|
|
onclick=" |
|
|
const el = document.getElementById('practice_{i}'); |
|
|
if (el) {{ |
|
|
localStorage.setItem('practice-{i}', el.value); |
|
|
alert('✅ Практика сохранена'); |
|
|
}} |
|
|
"> |
|
|
Сохранить практику |
|
|
</button> |
|
|
""") |
|
|
|
|
|
|
|
|
gr.HTML(""" |
|
|
<button style="background:#a8a29e;color:white;border:none;padding:8px 16px;border-radius:6px;margin:8px 0;cursor:pointer;" |
|
|
onclick=" |
|
|
let txt = '— Главная заметка —\\n' + (localStorage.getItem('main-note') || 'пусто') + '\\n\\n'; |
|
|
const names = ['Письмо от Тени', 'Кто наблюдает?', 'Голос из зеркала', 'Письмо от будущего себя', 'Тело знает']; |
|
|
for (let i = 0; i < 5; i++) { |
|
|
const val = localStorage.getItem('practice-' + i) || 'пусто'; |
|
|
txt += '— ' + names[i] + ' —\\n' + val + '\\n\\n'; |
|
|
} |
|
|
alert(txt); |
|
|
"> |
|
|
👀 Показать все заметки |
|
|
</button> |
|
|
|
|
|
<button style="background:#a8a29e;color:white;border:none;padding:8px 16px;border-radius:6px;margin:8px 0;cursor:pointer;" |
|
|
onclick=" |
|
|
(async () => { |
|
|
if (!window.jspdf) { |
|
|
const s = document.createElement('script'); |
|
|
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js'; |
|
|
document.head.appendChild(s); |
|
|
await new Promise(r => s.onload = r); |
|
|
} |
|
|
const {{ jsPDF }} = window.jspdf; |
|
|
const doc = new jsPDF(); |
|
|
doc.setFontSize(16); |
|
|
doc.text('Тишина внутри — мои заметки', 14, 20); |
|
|
let y = 30; |
|
|
const main = localStorage.getItem('main-note'); |
|
|
if (main) { |
|
|
doc.setFontSize(12); |
|
|
doc.text('Главная заметка:', 14, y); |
|
|
y += 6; |
|
|
const lines = doc.splitTextToSize(main, 180); |
|
|
doc.text(lines, 14, y); |
|
|
y += lines.length * 6 + 10; |
|
|
} |
|
|
const names = ['Письмо от Тени', 'Кто наблюдает?', 'Голос из зеркала', 'Письмо от будущего себя', 'Тело знает']; |
|
|
for (let i = 0; i < 5; i++) { |
|
|
const val = localStorage.getItem('practice-' + i); |
|
|
if (val) { |
|
|
doc.setFontSize(12); |
|
|
doc.text(names[i] + ':', 14, y); |
|
|
y += 6; |
|
|
const lines = doc.splitTextToSize(val, 180); |
|
|
if (y + lines.length * 6 > 280) { doc.addPage(); y = 20; } |
|
|
doc.text(lines, 14, y); |
|
|
y += lines.length * 6 + 10; |
|
|
} |
|
|
} |
|
|
doc.save('тишина-внутри-' + new Date().toISOString().slice(0,10) + '.pdf'); |
|
|
})(); |
|
|
"> |
|
|
📥 Экспортировать в PDF |
|
|
</button> |
|
|
""") |
|
|
|
|
|
|
|
|
gr.HTML(""" |
|
|
<script> |
|
|
setTimeout(() => { |
|
|
const main = document.getElementById('main_note'); |
|
|
if (main && localStorage.getItem('main-note')) { |
|
|
main.value = localStorage.getItem('main-note'); |
|
|
} |
|
|
for (let i = 0; i < 5; i++) { |
|
|
const el = document.getElementById('practice_' + i); |
|
|
if (el && localStorage.getItem('practice-' + i)) { |
|
|
el.value = localStorage.getItem('practice-' + i); |
|
|
} |
|
|
} |
|
|
}, 1000); |
|
|
</script> |
|
|
""") |
|
|
|
|
|
demo.launch(ssr_mode=False) |