Dokumentacion teknik
Integro Barleti AI në website-in tënd
Asistenti i Universitetit Barleti mund të vendoset në çdo website, pavarësisht teknologjisë, me një rresht kodi. Për aplikacione me ndërfaqe të vetën ofrohet edhe një API REST.
Serveri i Barleti AI: {{BASE}}
1. Si funksionon
Ka dy mënyra integrimi. Shumica e website-eve kanë nevojë vetëm për të parën.
| Widget (rekomandohet) | API REST | |
|---|---|---|
| Çfarë merrni | Buton chat-i gati në cep të faqes, me të gjitha funksionet | Të dhënat (pyetje → përgjigje) për t'i shfaqur në UI-në tuaj |
| Kodi | 1 rresht <script> | Thirrje HTTP nga shfletuesi ose serveri |
| Çelësi | Publik (pk_…) | Publik nga shfletuesi · Sekret (sk_…) nga serveri |
| Koha | ~5 minuta | Sipas UI-së që ndërtoni |
Widget-i hap chat-in zyrtar të Barleti AI në një dritare të izoluar (iframe). Stilet e website-it
tuaj nuk ndikojnë te chat-i dhe chat-i nuk ndikon te faqja juaj. Vizitori merr përgjigje nga burimet zyrtare
të universitetit, me referenca, pyetje të shpeshta, historik bisedash dhe zgjedhje gjuhe (shqip/anglisht).
2. Para se të filloni
Kërkojini administratorit të Barleti AI të krijojë një integrim për website-in tuaj. Për këtë i duhen:
- Emri i website-it (p.sh. "Faqja e Fakultetit të Drejtësisë").
- Të gjitha domain-et ku do të shfaqet chat-i: prodhimi, staging dhe mjedisi lokal i zhvillimit,
p.sh.
https://fdrejtesi.umb.edu.al,staging.fdrejtesi.umb.edu.al,localhost:3000. Chat-i shfaqet vetëm në domain-et e regjistruara.
Do të merrni:
- Çelësin publik
pk_…. Mund të shfaqet lirshëm në HTML, sepse punon vetëm nga domain-et tuaja. - Çelësin sekret
sk_…, vetëm nëse do të përdorni API-n nga serveri. Mbajeni si fjalëkalim.
http://localhost:<porta>, me kusht që ajo portë të jetë e regjistruar.3. Hapi 1 - Widget-i
Ngjitni këtë rresht në HTML-në e çdo faqeje ku doni chat-in. Vendi më i mirë është menjëherë para </body>:
<script src="{{BASE}}/widget.js" data-key="{{KEY}}" async></script>Kaq. Rifreskoni faqen: në cep poshtë djathtas del butoni i Barleti AI, dhe klikimi hap chat-in.
async) dhe chat-i krijohet vetëm kur vizitori klikon butonin,
kështu që shpejtësia e faqes suaj nuk preket.4. Udhëzime sipas platformës
Zgjidhni teknologjinë e website-it tuaj:
Në çdo faqe HTML (ose në template-in e përbashkët, p.sh. footer.php), para </body>:
...
<script src="{{BASE}}/widget.js" data-key="{{KEY}}" async></script>
</body>
</html>Pa prekur temën, me plugin-in falas WPCode:
- Plugins → Add New → kërkoni WPCode → Install → Activate.
- Code Snippets → + Add Snippet → "Add Your Custom Code" → lloji HTML Snippet.
- Ngjitni kodin e widget-it, zgjidhni Insert Method: Auto Insert dhe Location: Site Wide Footer.
- Aktivizojeni dhe ruajeni.
Alternativa: te tema child, në footer.php, para <?php wp_footer(); ?>.
React (Vite / CRA): në index.html, para </body>, ngjitni kodin e widget-it.
Next.js (App Router), te app/layout.tsx:
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="sq">
<body>
{children}
<Script src="{{BASE}}/widget.js" data-key="{{KEY}}" strategy="lazyOnload" />
</body>
</html>
);
}Te Pages Router vendoseni në pages/_app.tsx ose _document.tsx.
Vue (Vite): në index.html, para </body>.
Nuxt 3, te nuxt.config.ts:
export default defineNuxtConfig({
app: {
head: {
script: [
{ src: "{{BASE}}/widget.js", "data-key": "{{KEY}}", async: true, tagPosition: "bodyClose" }
]
}
}
});Në src/index.html, para </body>:
<app-root></app-root>
<script src="{{BASE}}/widget.js" data-key="{{KEY}}" async></script>
</body>Te layout-i kryesor, p.sh. resources/views/layouts/app.blade.php. Çelësi mund të mbahet te .env:
{{-- .env: BARLETI_AI_KEY={{KEY}} --}}
<script src="{{BASE}}/widget.js" data-key="{{ env('BARLETI_AI_KEY') }}" async></script>
</body>Te Views/Shared/_Layout.cshtml (MVC / Razor Pages), para </body>:
<script src="{{BASE}}/widget.js" data-key="{{KEY}}" async></script>
@await RenderSectionAsync("Scripts", required: false)
</body>- Wix: Settings → Custom Code → + Add Custom Code → ngjitni kodin → "All pages" → vendndodhja Body - end.
- Webflow: Site settings → Custom code → Footer code → Save → Publish.
- Squarespace: Settings → Advanced → Code Injection → Footer.
- Google Tag Manager: Tag i ri → Custom HTML → ngjitni kodin → trigger "All Pages" → Publish.
5. Personalizimi
Pamja e widget-it ndryshohet me atribute te <script>. Të gjitha janë opsionale:
| Atributi | Vlerat | Default | Përshkrimi |
|---|---|---|---|
data-key | pk_… | - | I detyrueshëm. Çelësi publik i integrimit. |
data-position | right · left | right | Cepi ku shfaqet butoni. |
data-color | hex, p.sh. #0055A4 | #B1005D | Ngjyra e butonit, sipas identitetit të website-it tuaj. |
data-lang | sq · en | sq | Gjuha fillestare e chat-it. Vizitori mund ta ndryshojë. |
data-label | tekst | Pyet Barleti AI | Etiketa e butonit për lexuesit e ekranit (aksesueshmëri). |
data-open | true | - | Hap chat-in automatikisht kur ngarkohet faqja. |
data-mode | inline | - | Chat brenda faqes, pa buton lundrues (shih seksionin 7). |
Shembull: butoni në të majtë, me ngjyrën e fakultetit, chat-i në anglisht:
<script src="{{BASE}}/widget.js" data-key="{{KEY}}"
data-position="left" data-color="#0055A4" data-lang="en" async></script>Në celular, chat-i hapet automatikisht në ekran të plotë.
6. Kontrolli nga JavaScript
Pasi ngarkohet, widget-i krijon objektin global window.BarletiAI:
| Metoda | Çfarë bën |
|---|---|
BarletiAI.open() | Hap chat-in. |
BarletiAI.close() | Mbyll chat-in. |
BarletiAI.toggle() | Hap / mbyll. |
BarletiAI.ask("pyetja") | Hap chat-in dhe dërgon pyetjen menjëherë. |
Shembull: buton në faqen e pranimeve që pyet drejtpërdrejt:
<button type="button" onclick="window.BarletiAI && BarletiAI.ask('Cilat janë afatet e aplikimit për Master?')">
Pyet për afatet e aplikimit
</button>7. Chat brenda faqes (pa buton lundrues)
Nëse doni chat-in si pjesë të faqes, p.sh. te "Kontakt" ose "Ndihmë", përdorni modalitetin inline.
Chat-i vendoset brenda elementit të treguar me data-target:
<div id="barleti-ai"></div>
<script src="{{BASE}}/widget.js" data-key="{{KEY}}"
data-mode="inline" data-target="#barleti-ai" data-height="600px" async></script>data-height pranon px, vh ose %. Gjerësia merr 100% të elementit.
8. API REST (v1)
Përdoreni API-n nëse doni ndërfaqen tuaj (p.sh. aplikacion celular, chatbot në një platformë tjetër, sistem i brendshëm).
Dokumentimi interaktiv, ku çdo endpoint mund të provohet, është te
{{BASE}}/api/docs.
Autentikimi
| Header | Kur |
|---|---|
Authorization: Bearer sk_… | Nga serveri juaj (PHP, Node, Python, .NET…). Pa kufizim domain-i, prandaj çelësi s'duhet të dalë kurrë në shfletues. |
X-Barleti-Key: pk_… | Nga shfletuesi, vetëm nga domain-et e regjistruara (CORS). Refuzohet nëse thirret nga një server. |
X-Visitor-Id: <id> | I detyrueshëm për çdo endpoint përveç GET /faq. Një ID e qëndrueshme e përdoruesit tuaj (1–128 karaktere), p.sh. ID-ja e llogarisë ose një UUID në localStorage. I njëjti ID sheh të njëjtën histori bisedash. |
Endpoint-et
URL bazë: {{BASE}}/api/v1
| Metoda | Rruga | Përshkrimi |
|---|---|---|
| POST | /chat | Bëj një pyetje. Body: {"message", "conversationId"?, "lang"?} |
| GET | /faq?lang=sq | Pyetjet e shpeshta sipas kategorive (pa përgjigje) |
| POST | /faq/{entryId} | Zgjidh një pyetje të shpeshtë. Kthen përgjigjen zyrtare. Body: {"conversationId"?, "lang"?} |
| POST | /messages/{id}/feedback | Vlerëso një përgjigje. Body: {"rating": "up"|"down", "comment"?} |
| GET | /conversations | Bisedat e këtij përdoruesi |
| GET | /conversations/{id} | Një bisedë me të gjitha mesazhet |
message pranon deri në 600 karaktere. Për të vazhduar të njëjtën bisedë, dërgoni conversationId nga përgjigjja e mëparshme.
Chat-i e mban mend kontekstin, kështu që pyetje vijuese si "po për master?" funksionojnë.
Shembuj
curl -X POST {{BASE}}/api/v1/chat \
-H "Authorization: Bearer sk_JUAJ_CELESI_SEKRET" \
-H "X-Visitor-Id: user-123" \
-H "Content-Type: application/json" \
-d '{"message": "Si regjistrohem në programin Master?"}'// Node 18+ (fetch i integruar). Çelësi nga variablat e mjedisit, jo në kod.
async function askBarleti(message, userId, conversationId) {
const res = await fetch("{{BASE}}/api/v1/chat", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.BARLETI_AI_SECRET}`,
"X-Visitor-Id": String(userId),
"Content-Type": "application/json",
},
body: JSON.stringify({ message, conversationId }),
});
if (!res.ok) throw new Error((await res.json()).error);
return res.json(); // { conversationId, answer, citations, status, ... }
}<?php
$ch = curl_init("{{BASE}}/api/v1/chat");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("BARLETI_AI_SECRET"),
"X-Visitor-Id: " . $userId,
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["message" => "Ku ndodhet universiteti?"]),
]);
$data = json_decode(curl_exec($ch), true);
echo $data["answer"];import os, requests
r = requests.post(
"{{BASE}}/api/v1/chat",
headers={
"Authorization": f"Bearer {os.environ['BARLETI_AI_SECRET']}",
"X-Visitor-Id": "user-123",
},
json={"message": "Çfarë bursash ofron universiteti?"},
timeout=60,
)
r.raise_for_status()
print(r.json()["answer"])Nga shfletuesi përdoret vetëm çelësi publik, dhe funksionon vetëm nga domain-et e regjistruara:
// ID e qëndrueshme e pajisjes, që historiku të ruhet ndërmjet vizitave
const visitorId = localStorage.getItem("barleti-visitor") || crypto.randomUUID();
localStorage.setItem("barleti-visitor", visitorId);
const res = await fetch("{{BASE}}/api/v1/chat", {
method: "POST",
headers: {
"X-Barleti-Key": "{{KEY}}",
"X-Visitor-Id": visitorId,
"Content-Type": "application/json",
},
body: JSON.stringify({ message: "Si aplikoj për Erasmus?" }),
});
const data = await res.json();Përgjigjja
{
"conversationId": 62,
"userMessageId": 427,
"assistantMessageId": 428,
"answer": "Për t'u regjistruar në programet Master ... (tekst Markdown)",
"status": "ANSWERED",
"citations": [
{ "label": "Universiteti Barleti - Pranimet Master", "url": "https://www.umb.edu.al/..." }
]
}answerështë në Markdown (lista, bold, lidhje). Shfaqeni me një renderues Markdown.status:ANSWERED, oseUNANSWEREDkur burimet zyrtare nuk e mbulojnë pyetjen.citations: burimet zyrtare të përdorura.urlmund të jetënullpër dokumente të brendshme.assistantMessageIdpërdoret për feedback (POST /messages/{id}/feedback).
Gabimet
Çdo gabim kthehet si {"error": "mesazh në shqip"}:
| Kodi | Kuptimi |
|---|---|
400 | Kërkesë e pavlefshme, p.sh. mesazh bosh ose më i gjatë se 600 karaktere, ose mungon X-Visitor-Id. |
401 | Mungon çelësi, është i pavlefshëm, ose integrimi është çaktivizuar. |
403 | Domain-i nuk është i regjistruar, ose çelësi publik u përdor nga një server. |
404 | Biseda ose mesazhi nuk ekziston, ose i përket një përdoruesi tjetër. |
429 | Shumë pyetje brenda pak kohe. Prisni pak dhe provoni sërish. |
9. Siguria & privatësia
- Çelësi publik (
pk_…) mund të shihet në HTML. Nuk mund të përdoret në domain të tjera, dhe shfletuesi e bllokon chat-in jashtë listës së regjistruar. - Çelësi sekret (
sk_…) mbahet vetëm në server, në variabla mjedisi, jo në kod të publikuar apo në Git. Nëse rrjedh, kërkoni menjëherë një çelës të ri. I vjetri çaktivizohet në çast. - Widget-i nuk vendos cookie në domain-in tuaj dhe nuk lexon asgjë nga faqja juaj. Chat-i funksionon i izoluar në iframe dhe ruan vetëm një ID të rastësishme pajisjeje, për historikun e bisedave.
- Pyetjet përpunohen sipas Politikës së Privatësisë së Barleti AI. Nëse website-i juaj ka politikë cookie/privatësie, përmendni që përdor asistentin e Universitetit Barleti.
- Nëse website-i juaj përdor Content-Security-Policy, lejoni serverin e Barleti AI:
script-src ... {{BASE}}; frame-src ... {{BASE}}; connect-src ... {{BASE}}; (vetëm nëse përdorni API-n nga shfletuesi)
10. Zgjidhja e problemeve
| Problemi | Shkaku / Zgjidhja |
|---|---|
| Butoni nuk shfaqet | Kontrolloni në Console (F12) për gabime. Verifikoni që data-key është i saktë dhe që skripti ngarkohet
(tab-i Network → widget.js → 200). |
| Butoni shfaqet, por chat-i është bosh ose i bllokuar | Domain-i nuk është i regjistruar. Console tregon "violates the following
Content Security Policy directive: frame-ancestors". Dërgojini administratorit domain-in e saktë.
www.site.al dhe site.al janë domain-e të ndryshme. |
| "Barleti AI nuk është i disponueshëm këtu" | Çelësi është i pavlefshëm ose integrimi është çaktivizuar. Kontaktoni administratorin. |
| Punon në prodhim, jo lokalisht | Porta lokale nuk është e regjistruar (p.sh. localhost:3000). Faqja nuk hapet si skedar
(file://), por nga një server lokal. |
| Gabim "Mixed Content" | Website-i juaj është në https://, por skripti ngarkohet nga http://. Përdorni adresën HTTPS të Barleti AI. |
API: 403 nga serveri | Po përdorni çelësin publik nga serveri. Nga serveri përdoret Authorization: Bearer sk_…. |
| API: CORS error në shfletues | Domain-i i faqes nuk është i regjistruar, ose po përdorni çelësin sekret nga shfletuesi (nuk lejohet). |
11. Ndihmë
Për çelësa, domain-e të reja ose probleme teknike, kontaktoni administratorin e Barleti AI: [email protected]. Në email tregoni emrin e website-it, domain-in dhe, nëse ka, mesazhin e gabimit nga Console.