mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 08:43:37 +00:00
- 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
42 lines
1.6 KiB
Python
42 lines
1.6 KiB
Python
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,
|
|
)
|