Spaces:
Runtime error
Runtime error
File size: 7,210 Bytes
052521c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
"""
NotebookLM-Py FastAPI REST API
提供 RESTful 接口供 n8n 等工具调用
"""
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional, List
from contextlib import asynccontextmanager
from notebooklm import NotebookLMClient
import os
# ==================== 数据模型 ====================
class CreateNotebookRequest(BaseModel):
title: str
class AddSourceRequest(BaseModel):
url: str
wait: bool = True
class AskRequest(BaseModel):
question: str
class GenerateAudioRequest(BaseModel):
instructions: Optional[str] = None
class GenerateQuizRequest(BaseModel):
difficulty: Optional[str] = "medium"
class NotebookResponse(BaseModel):
id: str
title: str
class SourceResponse(BaseModel):
id: str
title: str
source_type: str
class ChatResponse(BaseModel):
answer: str
citations: Optional[List[str]] = None
class TaskResponse(BaseModel):
task_id: str
status: str
# ==================== 客户端管理 ====================
@asynccontextmanager
async def get_client():
"""获取 NotebookLM 客户端"""
async with await NotebookLMClient.from_storage() as client:
yield client
# ==================== FastAPI 应用 ====================
app = FastAPI(
title="NotebookLM-Py API",
description="非官方 Google NotebookLM REST API",
version="1.0.0",
docs_url="/api/docs",
redoc_url="/api/redoc",
)
# CORS 配置
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ==================== 笔记本 API ====================
@app.get("/api/notebooks", response_model=List[NotebookResponse], tags=["Notebooks"])
async def list_notebooks():
"""列出所有笔记本"""
try:
async with get_client() as client:
notebooks = await client.notebooks.list()
return [NotebookResponse(id=nb.id, title=nb.title) for nb in notebooks]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/notebooks", response_model=NotebookResponse, tags=["Notebooks"])
async def create_notebook(request: CreateNotebookRequest):
"""创建新笔记本"""
try:
async with get_client() as client:
nb = await client.notebooks.create(request.title)
return NotebookResponse(id=nb.id, title=nb.title)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/notebooks/{notebook_id}", response_model=NotebookResponse, tags=["Notebooks"])
async def get_notebook(notebook_id: str):
"""获取笔记本详情"""
try:
async with get_client() as client:
nb = await client.notebooks.get(notebook_id)
return NotebookResponse(id=nb.id, title=nb.title)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/api/notebooks/{notebook_id}", tags=["Notebooks"])
async def delete_notebook(notebook_id: str):
"""删除笔记本"""
try:
async with get_client() as client:
await client.notebooks.delete(notebook_id)
return {"message": "Notebook deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 资源 API ====================
@app.get("/api/notebooks/{notebook_id}/sources", response_model=List[SourceResponse], tags=["Sources"])
async def list_sources(notebook_id: str):
"""列出笔记本的所有资源"""
try:
async with get_client() as client:
sources = await client.sources.list(notebook_id)
return [SourceResponse(id=s.id, title=s.title, source_type=s.source_type) for s in sources]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/notebooks/{notebook_id}/sources/url", response_model=SourceResponse, tags=["Sources"])
async def add_url_source(notebook_id: str, request: AddSourceRequest):
"""添加 URL 资源"""
try:
async with get_client() as client:
source = await client.sources.add_url(notebook_id, request.url, wait=request.wait)
return SourceResponse(id=source.id, title=source.title, source_type=source.source_type)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 对话 API ====================
@app.post("/api/notebooks/{notebook_id}/ask", response_model=ChatResponse, tags=["Chat"])
async def ask_question(notebook_id: str, request: AskRequest):
"""向笔记本提问"""
try:
async with get_client() as client:
result = await client.chat.ask(notebook_id, request.question)
return ChatResponse(answer=result.answer)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 生成内容 API ====================
@app.post("/api/notebooks/{notebook_id}/generate/audio", response_model=TaskResponse, tags=["Generate"])
async def generate_audio(notebook_id: str, request: GenerateAudioRequest = None):
"""生成音频播客"""
try:
async with get_client() as client:
instructions = request.instructions if request else None
status = await client.artifacts.generate_audio(notebook_id, instructions=instructions)
return TaskResponse(task_id=status.task_id, status="started")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/notebooks/{notebook_id}/generate/quiz", response_model=TaskResponse, tags=["Generate"])
async def generate_quiz(notebook_id: str, request: GenerateQuizRequest = None):
"""生成测验"""
try:
async with get_client() as client:
difficulty = request.difficulty if request else "medium"
status = await client.artifacts.generate_quiz(notebook_id, difficulty=difficulty)
return TaskResponse(task_id=status.task_id, status="started")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/notebooks/{notebook_id}/generate/flashcards", response_model=TaskResponse, tags=["Generate"])
async def generate_flashcards(notebook_id: str):
"""生成闪卡"""
try:
async with get_client() as client:
status = await client.artifacts.generate_flashcards(notebook_id)
return TaskResponse(task_id=status.task_id, status="started")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ==================== 健康检查 ====================
@app.get("/api/health", tags=["System"])
async def health_check():
"""健康检查"""
return {"status": "ok"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
|