mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 16:53:38 +00:00
feat: NLP patch insights + standalone demo mode
- dlib/ai/insights.py: pure-Python NLP analysis that correlates accepted AI suggestion operations/keywords/sections with submission outcomes (pending_review / published = positive, archived = negative) - Backend: GET /api/v1/insights route + service + Pydantic schema - Frontend: InsightsPanel component with bar charts for operation impact, section impact, and keyword signal lift scores - Insights tab added to the version panel; compact preview on doc overview - NEXT_PUBLIC_DEMO=true makes the webapp fully standalone: loads DEMO_DOCUMENTS / DEMO_SUBMISSIONS / DEMO_INSIGHTS from demo-data.ts, disables all mutating actions, shows a DEMO badge in the top bar - apps/webapp/public/demo-cv.docx: static dummy CV (Alex Rivera) for demo - scripts/gen_demo_cv.py: script to regenerate the demo DOCX - .env.example: document NEXT_PUBLIC_DEMO flag https://claude.ai/code/session_01LWxu2qrwY6BRjUFXXn7NiM
This commit is contained in:
41
apps/backend/fastapi/app/api/routes/insights.py
Normal file
41
apps/backend/fastapi/app/api/routes/insights.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_current_user, get_db
|
||||
from app.schemas.insights import InsightsResponse
|
||||
from app.services.insights import get_insights
|
||||
from dlib.auth import AuthenticatedUser
|
||||
|
||||
router = APIRouter(prefix="/insights", tags=["insights"])
|
||||
|
||||
|
||||
@router.get("", response_model=InsightsResponse)
|
||||
async def insights_endpoint(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
user: AuthenticatedUser = Depends(get_current_user),
|
||||
):
|
||||
result = await get_insights(session, owner_id=user.sub)
|
||||
return InsightsResponse(
|
||||
total_submissions=result.total_submissions,
|
||||
positive_count=result.positive_count,
|
||||
positive_rate=result.positive_rate,
|
||||
operation_impact=[
|
||||
{"operation": o.operation, "total": o.total, "positive": o.positive, "rate": o.rate}
|
||||
for o in result.operation_impact
|
||||
],
|
||||
top_positive_keywords=[
|
||||
{"keyword": k.keyword, "positive_count": k.positive_count, "negative_count": k.negative_count, "lift": k.lift}
|
||||
for k in result.top_positive_keywords
|
||||
],
|
||||
top_negative_keywords=[
|
||||
{"keyword": k.keyword, "positive_count": k.positive_count, "negative_count": k.negative_count, "lift": k.lift}
|
||||
for k in result.top_negative_keywords
|
||||
],
|
||||
section_impact=[
|
||||
{"section": s.section, "positive_rate": s.positive_rate, "count": s.count}
|
||||
for s in result.section_impact
|
||||
],
|
||||
has_data=result.has_data,
|
||||
)
|
||||
Reference in New Issue
Block a user