added file and link create

This commit is contained in:
2026-02-24 13:41:39 +01:00
parent 005059be84
commit ebafaef335
10 changed files with 3208 additions and 6 deletions

View File

@@ -41,6 +41,9 @@ from src.services.background_jobs import (
)
from src.services.db_job_manager import job_manager
from src.services.storage_service import storage
from src.services.link_extractor import LinkExtractor, LinkExtractionError
from src.services.file_extractor import FileExtractor, FileExtractionError
from src.agents.link_topic_builder import LinkTopicBuilderAgent
# Router for user frontend
user_router = APIRouter(tags=["user"])
@@ -1813,6 +1816,64 @@ async def create_post_page(request: Request):
})
@user_router.get("/create/link-wizard", response_class=HTMLResponse)
async def create_post_link_page(request: Request):
"""Create post from link wizard page."""
session = require_user_session(request)
if not session:
return RedirectResponse(url="/login", status_code=302)
# Check token limit for companies/employees
limit_reached = False
limit_message = ""
if session.account_type in ("company", "employee") and session.company_id:
can_create, error_msg, _, _ = await db.check_company_token_limit(UUID(session.company_id))
limit_reached = not can_create
limit_message = error_msg
user_id = UUID(session.user_id)
profile_picture = await get_user_avatar(session, user_id)
return templates.TemplateResponse("create_post_link.html", {
"request": request,
"page": "create",
"session": session,
"user_id": session.user_id,
"limit_reached": limit_reached,
"limit_message": limit_message,
"profile_picture": profile_picture
})
@user_router.get("/create/file-wizard", response_class=HTMLResponse)
async def create_post_file_page(request: Request):
"""Create post from file wizard page."""
session = require_user_session(request)
if not session:
return RedirectResponse(url="/login", status_code=302)
# Check token limit for companies/employees
limit_reached = False
limit_message = ""
if session.account_type in ("company", "employee") and session.company_id:
can_create, error_msg, _, _ = await db.check_company_token_limit(UUID(session.company_id))
limit_reached = not can_create
limit_message = error_msg
user_id = UUID(session.user_id)
profile_picture = await get_user_avatar(session, user_id)
return templates.TemplateResponse("create_post_file.html", {
"request": request,
"page": "create",
"session": session,
"user_id": session.user_id,
"limit_reached": limit_reached,
"limit_message": limit_message,
"profile_picture": profile_picture
})
@user_router.get("/chat-create", response_class=HTMLResponse)
async def chat_create_page(request: Request):
"""Chat-based post creation page."""
@@ -2063,6 +2124,117 @@ async def transcribe_audio(request: Request):
raise HTTPException(status_code=500, detail=str(e))
@user_router.post("/api/link-extract")
async def extract_link(request: Request):
"""Extract context from a link and build a structured topic."""
session = require_user_session(request)
if not session:
raise HTTPException(status_code=401, detail="Not authenticated")
# Check token limit for companies/employees
if session.account_type in ("company", "employee") and session.company_id:
can_create, error_msg, _, _ = await db.check_company_token_limit(UUID(session.company_id))
if not can_create:
raise HTTPException(status_code=429, detail=error_msg)
try:
data = await request.json()
url = (data.get("url") or "").strip()
transcript = (data.get("transcript") or "").strip()
manual_title = (data.get("title") or "").strip()
source_type = (data.get("source_type") or "").strip()
source_url = (data.get("source_url") or "").strip()
if transcript:
source = {
"source_url": source_url or url,
"source_type": source_type or "manual",
"title": manual_title or "Manuelles Transkript",
"text": transcript
}
else:
extractor = LinkExtractor()
try:
source = await extractor.extract(url)
except LinkExtractionError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
builder = LinkTopicBuilderAgent()
builder.set_tracking_context(
operation="link_extract",
user_id=session.user_id,
company_id=session.company_id
)
topic = await builder.process(source)
return {"topic": topic, "source": source}
except HTTPException:
raise
except Exception as e:
logger.exception(f"Link extraction failed: {e}")
raise HTTPException(status_code=500, detail=str(e))
@user_router.post("/api/file-extract")
async def extract_file(request: Request):
"""Extract context from an uploaded file and build a structured topic."""
session = require_user_session(request)
if not session:
raise HTTPException(status_code=401, detail="Not authenticated")
# Check token limit for companies/employees
if session.account_type in ("company", "employee") and session.company_id:
can_create, error_msg, _, _ = await db.check_company_token_limit(UUID(session.company_id))
if not can_create:
raise HTTPException(status_code=429, detail=error_msg)
try:
form = await request.form()
upload: UploadFile = form.get("file") # type: ignore[assignment]
if not upload:
raise HTTPException(status_code=400, detail="Keine Datei hochgeladen.")
# Basic validation
allowed_ext = {".pdf", ".docx", ".pptx", ".xlsx", ".txt", ".md", ".rtf"}
filename = upload.filename or ""
ext = Path(filename).suffix.lower()
if not ext or ext not in allowed_ext:
raise HTTPException(status_code=400, detail="Dateityp nicht unterstützt.")
file_bytes = await upload.read()
max_bytes = 10 * 1024 * 1024 # 10 MB
if len(file_bytes) > max_bytes:
raise HTTPException(status_code=400, detail="Datei ist zu groß (max 10 MB).")
extractor = FileExtractor()
try:
text = extractor.extract_text(file_bytes, filename)
except FileExtractionError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
source = {
"source_url": "",
"source_type": "file",
"title": filename or "Datei",
"text": text
}
builder = LinkTopicBuilderAgent()
builder.set_tracking_context(
operation="file_extract",
user_id=session.user_id,
company_id=session.company_id
)
topic = await builder.process(source)
return {"topic": topic, "source": source}
except HTTPException:
raise
except Exception as e:
logger.exception(f"File extraction failed: {e}")
raise HTTPException(status_code=500, detail=str(e))
@user_router.post("/api/hooks")
async def generate_hooks(
request: Request,