Add session export/import as JSON

Sessions can now be downloaded as a JSON file containing the session
metadata and every message with its tags, and re-imported as a new
session from that same format.

GET /chat/sessions/{id}/export streams the session as a file download.
POST /chat/sessions/import validates the roles, then recreates the
session under a fresh UUID so importing never collides with an existing
session. The sidebar gets a per-row download button and an import button
that feeds a hidden file input.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 01:22:08 +09:00
co-authored by Claude Opus 5
parent 1ad8b130c7
commit ef588d99d8
4 changed files with 192 additions and 5 deletions
+29 -1
View File
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { fetchSessions, fetchMessages, deleteSession, streamChat, type SessionInfo, type Source } from '../api/client'
import { fetchSessions, fetchMessages, deleteSession, exportSession, importSession, streamChat, type SessionInfo, type Source, type ImportPayload } from '../api/client'
export interface Message {
role: 'user' | 'assistant'
@@ -69,6 +69,32 @@ export const useChatStore = defineStore('chat', () => {
await loadSessions()
}
function downloadSessionLog(sessionId: string): void {
exportSession(sessionId)
}
async function importSessionFromFile(file: File): Promise<void> {
let payload: ImportPayload
try {
const parsed = JSON.parse(await file.text())
if (!Array.isArray(parsed?.messages)) {
throw new Error('messages 配列が見つかりません')
}
payload = parsed as ImportPayload
} catch (e) {
pushToast(`インポート失敗: JSONの読み込みに失敗しました (${e instanceof Error ? e.message : e})`)
return
}
try {
const session = await importSession(payload)
await loadSessions()
await selectSession(session.id)
pushToast(`「${session.title}」をインポートしました`)
} catch (e) {
pushToast(`インポート失敗: ${e instanceof Error ? e.message : e}`)
}
}
function sendMessage(text: string): void {
if (isStreaming.value || !text.trim()) return
@@ -137,6 +163,8 @@ export const useChatStore = defineStore('chat', () => {
loadSessions,
selectSession,
removeSession,
downloadSessionLog,
importSessionFromFile,
sendMessage,
retryMessage,
}