Add system memory monitoring, Bedrock support, and Discord integrations

- Add CPU/GPU memory monitoring endpoint and frontend widget
- Add Amazon Bedrock model support (API key / inference profiles) plus model selector entries
- Add Discord weather/laundry notification job (JMA forecast + LLM-generated message)
- Add Discord bot that replies to mentions via the configured LLM, with weather-aware context
- Add scheduled "useless tips" job with separate webhook and quiet-hours skip
- Switch FastAPI startup to lifespan handler, log viewer, markdown rendering, and toast UI additions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 00:59:38 +09:00
co-authored by Claude Sonnet 4.6
parent 903d34761c
commit 4a08ba29fa
34 changed files with 5051 additions and 160 deletions
+110
View File
@@ -0,0 +1,110 @@
<script setup lang="ts">
import { computed } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
const props = defineProps<{
content: string
pending?: boolean
}>()
marked.setOptions({ breaks: true, gfm: true })
function closeOpenFences(src: string): string {
const fenceCount = (src.match(/^```/gm) ?? []).length
if (fenceCount % 2 !== 0) return src + '\n```'
return src
}
const html = computed(() => {
const raw = props.pending ? closeOpenFences(props.content) : props.content
return DOMPurify.sanitize(marked.parse(raw) as string)
})
</script>
<template>
<div class="md" v-html="html" />
</template>
<style scoped>
.md { line-height: 1.7; word-break: break-word; }
/* インライン要素 */
.md :deep(code) {
background: #1a1a1a;
color: #e2e8f0;
padding: 1px 5px;
border-radius: 4px;
font-size: 0.875em;
font-family: 'Consolas', 'Menlo', monospace;
}
/* コードブロック */
.md :deep(pre) {
background: #0f0f0f;
border: 1px solid #2a2a2a;
border-radius: 8px;
padding: 12px 14px;
overflow-x: auto;
margin: 8px 0;
}
.md :deep(pre code) {
background: none;
padding: 0;
font-size: 0.85em;
color: #e2e8f0;
}
/* 見出し */
.md :deep(h1),
.md :deep(h2),
.md :deep(h3) {
margin: 12px 0 4px;
color: #f1f5f9;
font-weight: 600;
}
.md :deep(h1) { font-size: 1.2em; }
.md :deep(h2) { font-size: 1.1em; }
.md :deep(h3) { font-size: 1em; }
/* リスト */
.md :deep(ul),
.md :deep(ol) {
padding-left: 20px;
margin: 4px 0;
}
.md :deep(li) { margin: 2px 0; }
/* 段落 */
.md :deep(p) { margin: 4px 0; }
/* 引用 */
.md :deep(blockquote) {
border-left: 3px solid #444;
margin: 6px 0;
padding: 4px 12px;
color: #94a3b8;
}
/* テーブル */
.md :deep(table) {
border-collapse: collapse;
margin: 8px 0;
font-size: 0.9em;
width: 100%;
}
.md :deep(th),
.md :deep(td) {
border: 1px solid #333;
padding: 6px 10px;
text-align: left;
}
.md :deep(th) { background: #1a1a1a; color: #cbd5e1; }
/* 水平線 */
.md :deep(hr) { border-color: #333; margin: 10px 0; }
/* リンク */
.md :deep(a) { color: #60a5fa; text-decoration: none; }
.md :deep(a:hover) { text-decoration: underline; }
</style>