Introduces websearch.py (Tavily) + knowledge.py to ground chat responses in search results, tagging.py to tag user and assistant messages via LLM and pick related topics for the Discord useless-tips job, and word_memory.py to track recent conversation nouns (surfaced in the new WordPool.vue sidebar) used to pick tip topics close to a related tag.
88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
from fastapi import APIRouter, Depends
|
||
import psutil
|
||
from pydantic import BaseModel
|
||
from sqlalchemy.orm import Session as DBSession
|
||
|
||
from app.core.scheduler import send_useless_tip, send_weather_laundry_notification
|
||
from app.core.tagging import backfill_tags
|
||
from app.core.weather_cache import get_latest as get_latest_weather
|
||
from app.core.word_memory import get_word_pool_with_counts
|
||
from app.db.database import get_db
|
||
|
||
router = APIRouter(prefix="/api/system", tags=["system"])
|
||
|
||
|
||
class MemoryStats(BaseModel):
|
||
cpu_percent: float
|
||
memory_percent: float
|
||
memory_used_mb: float
|
||
memory_total_mb: float
|
||
gpu_memory_used_mb: float | None = None
|
||
gpu_memory_total_mb: float | None = None
|
||
gpu_memory_percent: float | None = None
|
||
|
||
|
||
@router.get("/memory", response_model=MemoryStats)
|
||
async def get_memory_stats():
|
||
"""CPU と GPU のメモリ使用状況を返す"""
|
||
# CPU/メモリ情報
|
||
cpu_percent = psutil.cpu_percent(interval=0.1)
|
||
memory = psutil.virtual_memory()
|
||
|
||
stats = {
|
||
"cpu_percent": cpu_percent,
|
||
"memory_percent": memory.percent,
|
||
"memory_used_mb": memory.used / (1024 * 1024),
|
||
"memory_total_mb": memory.total / (1024 * 1024),
|
||
}
|
||
|
||
# GPU 情報(オプション)
|
||
try:
|
||
import pynvml
|
||
pynvml.nvmlInit()
|
||
device_count = pynvml.nvmlDeviceGetCount()
|
||
if device_count > 0:
|
||
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
||
stats["gpu_memory_used_mb"] = mem_info.used / (1024 * 1024)
|
||
stats["gpu_memory_total_mb"] = mem_info.total / (1024 * 1024)
|
||
stats["gpu_memory_percent"] = (mem_info.used / mem_info.total) * 100
|
||
pynvml.nvmlShutdown()
|
||
except Exception:
|
||
pass
|
||
|
||
return MemoryStats(**stats)
|
||
|
||
|
||
@router.post("/weather-notify/test")
|
||
async def test_weather_notify():
|
||
"""天気予報→Discord通知を手動で即時実行する(動作確認用)"""
|
||
await send_weather_laundry_notification()
|
||
return {"status": "sent"}
|
||
|
||
|
||
@router.post("/useless-tip/test")
|
||
async def test_useless_tip():
|
||
"""どうでもいいtips→Discord通知を手動で即時実行する(動作確認用)"""
|
||
await send_useless_tip()
|
||
return {"status": "sent"}
|
||
|
||
|
||
@router.get("/weather/latest")
|
||
async def get_latest_weather_data():
|
||
"""直近で取得した明日の天気データを返す(未取得ならnull)"""
|
||
return get_latest_weather()
|
||
|
||
|
||
@router.get("/word-pool")
|
||
async def get_word_pool():
|
||
"""どうでもいいtips生成に使われているワードプールを出現回数順で返す"""
|
||
return get_word_pool_with_counts()
|
||
|
||
|
||
@router.post("/tags/backfill")
|
||
async def run_tags_backfill(limit: int | None = None, db: DBSession = Depends(get_db)):
|
||
"""過去のユーザーメッセージのうち、タグが未生成のものにまとめてタグを付ける"""
|
||
count = await backfill_tags(db, limit=limit)
|
||
return {"tagged_count": count}
|