Admin panel — brauzerdan boshqarish
Hozirgacha hamma narsani terminaldan qildik. Endi brauzerdan.
Bu talaba uchun katta farq: PDF yuklaydi, tugma bosadi, natijani
ko'radi. python -m scraper.embedder yozish shart emas.
Yetti endpoint
app/routes/admin.py da:
Diqqat: bu yo'llar ILDIZDA, /admin/ prefiksisiz.
main.py da include_router(admin.router) — prefix berilmagan.
| Endpoint | Vazifasi |
|---|---|
GET / |
dashboard — statistika |
GET /documents |
hujjatlar ro'yxati |
POST /scrape |
saytdan yig'ish |
POST /upload-pdf |
PDF yuklash |
POST /chunk-all |
hammasini chunklash |
POST /embed-all |
hammasini embedding |
GET/POST /settings |
sozlamalar |
Dashboard
@router.get("/") def dashboard(request: Request, db: Session = Depends(get_db)): stats = { "documents": db.execute(text( "SELECT count(*) FROM rag.documents")).scalar(), "chunks": db.execute(text( "SELECT count(*) FROM rag.chunks")).scalar(), "embedded": db.execute(text( "SELECT count(embedding_local) FROM rag.chunks")).scalar(), } return templates.TemplateResponse( "dashboard.html", {"request": request, "stats": stats})
Uchta son — butun tizim holati:
documents— nechta hujjatchunks— nechta bo'lakembedded— nechtasida vektor bor
Eng muhimi uchinchisi. Agar chunks = 100 va embedded = 0
bo'lsa — qidiruv ishlamaydi. Dashboard buni darhol ko'rsatadi.
Darsda shuni ayting: bu uch son bir-biriga yaqin bo'lishi kerak.
embedded < chunks bo'lsa — embed-all bosish kerak.
Uch bosqichli oqim
Admin panel RAG ni uch tugmaga bo'ladi:
[Yuklash] -> [Chunklash] -> [Embedding] PDF/URL bo'laklarga vektorlarga
Nega uchta alohida tugma, bitta emas?
Chunki har biri turli vaqt oladi va turli sababdan buziladi:
- Yuklash — sekund, tarmoq muammosi
- Chunklash — tez, xatosi kam
- Embedding — daqiqalar, Ollama kerak
Bitta tugma bo'lsa, embedding bosqichida uzilganda hammasini qaytadan qilishga to'g'ri keladi.
POST /scrape
class ScrapeSorovi(BaseModel): url: str = Field(min_length=8, max_length=2000) css_selector: str | None = None @router.post("/scrape") def scrape_url(sorov: ScrapeSorovi, db: Session = Depends(get_db)): try: natija = scrape_page(sorov.url, sorov.css_selector) except Exception as e: raise HTTPException(400, f"Sahifa olinmadi: {type(e).__name__}") if not natija["text"].strip(): raise HTTPException(400, "Sahifadan matn chiqmadi. CSS selector ko'rsating " "yoki sayt JavaScript bilan yuklanadi.") return {"title": natija["title"], "length": len(natija["text"])}
Ikkinchi tekshiruv juda muhim. Ko'p zamonaviy saytlar
JavaScript bilan yuklanadi — HTML da matn YO'Q. httpx faqat
boshlang'ich HTML ni oladi.
Bunday saytlar uchun playwright kerak (brauzerni ishga tushiradi).
Bu kitob doirasidan tashqarida, lekin talabaga aytib qo'ying —
ular albatta uchratadi.
POST /embed-all
@router.post("/embed-all") def embed_all(db: Session = Depends(get_db)): natija = embed_all_chunks(db) return {"embedded": natija}
Diqqat: bu SEKIN. 1000 chunk = bir necha daqiqa. HTTP so'rovi kutib turadi va timeout bo'lishi mumkin.
Production'da bu fon vazifasi bo'lishi kerak:
# parcha from fastapi import BackgroundTasks @router.post("/embed-all") def embed_all(bg: BackgroundTasks, db: Session = Depends(get_db)): bg.add_task(embed_all_chunks, db) return {"status": "boshlandi"}
Darsda oddiy variantni ko'rsating, keyin muammoni tushuntiring.
Sozlamalar
class SozlamaSorovi(BaseModel): top_k: int = Field(ge=1, le=50) rerank_top: int = Field(ge=1, le=30) similarity_threshold: float = Field(ge=0.0, le=1.0)
Bu — dars uchun eng qiziqarli qism. Talaba threshold ni
brauzerdan o'zgartirib, natija qanday o'zgarishini darhol
ko'radi.
Tajriba qildiring:
threshold = 0.1— hamma narsa topiladi, ko'pi keraksizthreshold = 0.8— deyarli hech narsa topilmaydi
Shunda ular o'zlari tushunadi: to'g'ri qiymat o'rtada va uni o'lchash kerak.
Ishga tushiring
python run.py
Brauzerda:
http://localhost:8000/— dashboardhttp://localhost:8000/documents— hujjatlarhttp://localhost:8000/chat— suhbat
Shablon va route KELISHUVI
Bu bobni yozishda uchta xato topildi — hammasi bir sababdan: shablon bir nomni kutadi, route boshqasini beradi.
| Shablon kutgan | Route bergan | Natija |
|---|---|---|
stats.total_documents |
doc_count |
'stats' is undefined |
settings.llm_model |
rag |
'settings' is undefined |
url_for('static', path=) |
filename= (Flask) |
NoMatchFound |
Uchalasi ham 500 xato beradi va sahifa umuman ochilmaydi.
Nega topilmagan: hech kim sahifani BROWSERDA ochmagan. Kod "to'g'ri ko'rinadi", testlar yo'q, xato faqat ishga tushirganda chiqadi.
Saboq: har bir sahifani ochib ko'ring. Bitta curl yetadi:
for y in / /documents /settings /chat; do printf "%s " "$y" curl -s -o /dev/null -w "%{http_code}\n" "http://localhost:8000$y" done
Hammasi 200 bo'lishi kerak. 500 chiqsa — shablon va route
nomlari mos emas.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.