mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
151 lines
4.5 KiB
Python
151 lines
4.5 KiB
Python
"""
|
|
Routes for public chat access via immutable snapshots.
|
|
|
|
All public endpoints use share_token for access - no authentication required
|
|
for read operations. Clone requires authentication.
|
|
"""
|
|
|
|
import os
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from fastapi.responses import StreamingResponse
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.db import User, get_async_session
|
|
from app.schemas.new_chat import (
|
|
CloneResponse,
|
|
PublicChatResponse,
|
|
)
|
|
from app.services.public_chat_service import (
|
|
clone_from_snapshot,
|
|
get_public_chat,
|
|
get_snapshot_podcast,
|
|
get_snapshot_report,
|
|
)
|
|
from app.users import current_active_user
|
|
|
|
router = APIRouter(prefix="/public", tags=["public"])
|
|
|
|
|
|
@router.get("/{share_token}", response_model=PublicChatResponse)
|
|
async def read_public_chat(
|
|
share_token: str,
|
|
session: AsyncSession = Depends(get_async_session),
|
|
):
|
|
"""
|
|
Get a public chat snapshot by share token.
|
|
|
|
No authentication required.
|
|
Returns immutable snapshot data (sanitized, citations stripped).
|
|
"""
|
|
return await get_public_chat(session, share_token)
|
|
|
|
|
|
@router.post("/{share_token}/clone", response_model=CloneResponse)
|
|
async def clone_public_chat(
|
|
share_token: str,
|
|
session: AsyncSession = Depends(get_async_session),
|
|
user: User = Depends(current_active_user),
|
|
):
|
|
"""
|
|
Clone a public chat snapshot to the user's account.
|
|
|
|
Creates thread and copies messages.
|
|
Requires authentication.
|
|
"""
|
|
return await clone_from_snapshot(session, share_token, user)
|
|
|
|
|
|
@router.get("/{share_token}/podcasts/{podcast_id}")
|
|
async def get_public_podcast(
|
|
share_token: str,
|
|
podcast_id: int,
|
|
session: AsyncSession = Depends(get_async_session),
|
|
):
|
|
"""
|
|
Get podcast details from a public chat snapshot.
|
|
|
|
No authentication required - the share_token provides access.
|
|
Returns podcast info including transcript.
|
|
"""
|
|
podcast_info = await get_snapshot_podcast(session, share_token, podcast_id)
|
|
|
|
if not podcast_info:
|
|
raise HTTPException(status_code=404, detail="Podcast not found")
|
|
|
|
return {
|
|
"id": podcast_info.get("original_id"),
|
|
"title": podcast_info.get("title"),
|
|
"status": "ready",
|
|
"podcast_transcript": podcast_info.get("transcript"),
|
|
}
|
|
|
|
|
|
@router.get("/{share_token}/podcasts/{podcast_id}/stream")
|
|
async def stream_public_podcast(
|
|
share_token: str,
|
|
podcast_id: int,
|
|
session: AsyncSession = Depends(get_async_session),
|
|
):
|
|
"""
|
|
Stream a podcast from a public chat snapshot.
|
|
|
|
No authentication required - the share_token provides access.
|
|
Looks up podcast by original_id in the snapshot's podcasts array.
|
|
"""
|
|
podcast_info = await get_snapshot_podcast(session, share_token, podcast_id)
|
|
|
|
if not podcast_info:
|
|
raise HTTPException(status_code=404, detail="Podcast not found")
|
|
|
|
file_path = podcast_info.get("file_path")
|
|
|
|
if not file_path or not os.path.isfile(file_path):
|
|
raise HTTPException(status_code=404, detail="Podcast audio file not found")
|
|
|
|
def iterfile():
|
|
with open(file_path, mode="rb") as file_like:
|
|
yield from file_like
|
|
|
|
return StreamingResponse(
|
|
iterfile(),
|
|
media_type="audio/mpeg",
|
|
headers={
|
|
"Accept-Ranges": "bytes",
|
|
"Content-Disposition": f"inline; filename={os.path.basename(file_path)}",
|
|
},
|
|
)
|
|
|
|
|
|
@router.get("/{share_token}/reports/{report_id}/content")
|
|
async def get_public_report_content(
|
|
share_token: str,
|
|
report_id: int,
|
|
session: AsyncSession = Depends(get_async_session),
|
|
):
|
|
"""
|
|
Get report content from a public chat snapshot.
|
|
|
|
No authentication required - the share_token provides access.
|
|
Returns report content including title, markdown body, metadata, and versions.
|
|
"""
|
|
from app.services.public_chat_service import get_snapshot_report_versions
|
|
|
|
report_info = await get_snapshot_report(session, share_token, report_id)
|
|
|
|
if not report_info:
|
|
raise HTTPException(status_code=404, detail="Report not found")
|
|
|
|
# Get version siblings from the same snapshot
|
|
versions = await get_snapshot_report_versions(
|
|
session, share_token, report_info.get("report_group_id")
|
|
)
|
|
|
|
return {
|
|
"id": report_info.get("original_id"),
|
|
"title": report_info.get("title"),
|
|
"content": report_info.get("content"),
|
|
"report_metadata": report_info.get("report_metadata"),
|
|
"report_group_id": report_info.get("report_group_id"),
|
|
"versions": versions,
|
|
}
|