راهنمای فریمورکها
جای کد ابزارک در HTML، React، Next.js، Vue، Nuxt، Angular، SvelteKit و Laravel.
ابزارک یک اسکریپت است، پس در هر فریمورکی کار یکی است: یک بار، با سه ویژگی، بارگذاریاش کنید. فقط جای گذاشتن اسکریپت فرق میکند.
پیش از شروع
- کد ابزارک را از صفحهٔ ابزارک در کنسول بگیرید. کلید، شناسهٔ اپ و شناسهٔ فضای کاری شما در آن هست.
- دامنهٔ سایتتان و نشانی محیط توسعهتان (مثل localhost:5173) را به دامنههای مجاز اضافه کنید.
- اسکریپت را یک بار و در بخشی از برنامه بارگذاری کنید که هیچوقت از صفحه حذف نمیشود. ابزارک راهی برای حذف شدن ندارد و نسخهٔ دوم را نادیده میگیرد؛ پس آن را داخل کامپوننت یک صفحه نگذارید. در نمونههای زیر،
dk_live_…یک کلید نمونه است.
اگر این سه مقدار را در متغیرهای محیطی نگه دارید، میتوانید برای محیط آزمایشی (staging) یک اپ و برای محیط اصلی (production) اپ دیگری داشته باشید:
DANESHYAR_WIDGET_KEY=dk_live_…
DANESHYAR_APP_ID=…
DANESHYAR_WORKSPACE_ID=…HTML ساده
تگ را در هر صفحهای که باید گفتوگو داشته باشد، درست پیش از </body> بگذارید. اگر سایتتان پانویس یا قالب مشترک دارد، یک بار همانجا بگذاریدش.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8" />
<title>My clinic</title>
</head>
<body>
<h1>Welcome</h1>
<!-- Daneshyar widget: once per page, just before </body> -->
<script
src="https://app.daneshyar.info/widget.js"
data-api-key="dk_live_9f3aC2xQ7mB1vT8sE4nK6pR0jY5wZ2hL"
data-app-id="2d7c0e91-4a5b-4f8e-b3c6-9e1f0a7d5c42"
data-workspace-id="8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f"
async
></script>
</body>
</html>کار دیگری لازم نیست. اسکریپت با async و بعد از محتوای صفحه بارگذاری میشود.
React (با Vite)
یک کامپوننت کوچک بسازید و یک بار در App.tsx نمایشش دهید. اسکریپت را اولین باری که برنامه بالا میآید اضافه میکند.
import { useEffect } from "react";
const WIDGET_SRC = "https://app.daneshyar.info/widget.js";
/** Render once, in your root component (App.tsx). */
export function DaneshyarWidget() {
useEffect(() => {
// widget.js runs once per page. Don't add it twice.
if (document.querySelector(`script[src="${WIDGET_SRC}"]`)) return;
const script = document.createElement("script");
script.src = WIDGET_SRC;
script.async = true;
// dataset.apiKey becomes data-api-key, and so on.
script.dataset.apiKey = import.meta.env.VITE_DANESHYAR_WIDGET_KEY;
script.dataset.appId = import.meta.env.VITE_DANESHYAR_APP_ID;
script.dataset.workspaceId = import.meta.env.VITE_DANESHYAR_WORKSPACE_ID;
script.dataset.locale = "fa";
document.body.appendChild(script);
}, []);
return null; // the widget draws its own button
}اگر از Create React App استفاده میکنید، بهجای import.meta.env.VITE_… بنویسید process.env.REACT_APP_…. در محیط توسعه، Strict Mode در React افکتها را دو بار اجرا میکند؛ بررسی querySelector جلوی نسخهٔ دوم را میگیرد.
Next.js (با App Router)
از next/script در layout اصلی، یعنی app/layout.tsx، استفاده کنید تا وقتی بازدیدکننده بین صفحهها جابهجا میشود اسکریپت بارگذاریشده بماند.
import Script from "next/script";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="fa" dir="rtl">
<body>
{children}
<Script
src="https://app.daneshyar.info/widget.js"
strategy="afterInteractive"
data-api-key={process.env.NEXT_PUBLIC_DANESHYAR_WIDGET_KEY}
data-app-id={process.env.NEXT_PUBLIC_DANESHYAR_APP_ID}
data-workspace-id={process.env.NEXT_PUBLIC_DANESHYAR_WORKSPACE_ID}
/>
</body>
</html>
);
}متغیرهایی که در مرورگر به کار میروند باید با NEXT_PUBLIC_ شروع شوند. اگر از Pages Router استفاده میکنید، همین <Script> را در pages/_app.tsx بگذارید.
Vue 3
اسکریپت را از کامپوننت اصلی، یعنی App.vue، و داخل onMounted اضافه کنید.
<script setup lang="ts">
import { onMounted } from "vue";
const WIDGET_SRC = "https://app.daneshyar.info/widget.js";
onMounted(() => {
// widget.js runs once per page. Don't add it twice.
if (document.querySelector(`script[src="${WIDGET_SRC}"]`)) return;
const script = document.createElement("script");
script.src = WIDGET_SRC;
script.async = true;
script.dataset.apiKey = import.meta.env.VITE_DANESHYAR_WIDGET_KEY;
script.dataset.appId = import.meta.env.VITE_DANESHYAR_APP_ID;
script.dataset.workspaceId = import.meta.env.VITE_DANESHYAR_WORKSPACE_ID;
document.body.appendChild(script);
});
</script>
<template>
<RouterView />
</template>اگر برنامهٔ Vue شما مرحلهٔ ساخت ندارد، کد HTML را مستقیم در index.html بگذارید.
Nuxt 3
اسکریپت را به app.head در nuxt.config.ts اضافه کنید. Nuxt آن را به همهٔ صفحهها اضافه میکند.
export default defineNuxtConfig({
app: {
head: {
script: [
{
src: "https://app.daneshyar.info/widget.js",
async: true,
tagPosition: "bodyClose",
"data-api-key": "dk_live_9f3aC2xQ7mB1vT8sE4nK6pR0jY5wZ2hL",
"data-app-id": "2d7c0e91-4a5b-4f8e-b3c6-9e1f0a7d5c42",
"data-workspace-id": "8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f",
},
],
},
},
});برای خواندن مقدارها از متغیرهای محیطی، بهجای این روش از runtimeConfig.public و useHead() در app.vue استفاده کنید.
Angular
کد ابزارک را در src/index.html و بعد از <app-root> بگذارید.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8" />
<base href="/" />
</head>
<body>
<app-root></app-root>
<script
src="https://app.daneshyar.info/widget.js"
data-api-key="dk_live_9f3aC2xQ7mB1vT8sE4nK6pR0jY5wZ2hL"
data-app-id="2d7c0e91-4a5b-4f8e-b3c6-9e1f0a7d5c42"
data-workspace-id="8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f"
async
></script>
</body>
</html>سادهترین جا همین است و برای همهٔ مسیرها کار میکند. برای مقدارهای جدا در هر محیط، برای هر ساخت یک index.html داشته باشید و با fileReplacements در angular.json جایگزینش کنید.
SvelteKit
کد ابزارک را در src/app.html و بعد از %sveltekit.body% بگذارید.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
<script
src="https://app.daneshyar.info/widget.js"
data-api-key="dk_live_9f3aC2xQ7mB1vT8sE4nK6pR0jY5wZ2hL"
data-app-id="2d7c0e91-4a5b-4f8e-b3c6-9e1f0a7d5c42"
data-workspace-id="8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f"
async
></script>
</body>
</html>در Svelte ساده با Vite، آن را به index.html اضافه کنید. برای خواندن مقدارها از متغیرهای محیطی، اسکریپت را مثل نمونهٔ React، داخل onMount در +layout.svelte اصلی اضافه کنید.
Laravel (با Blade)
تگ را در layout اصلی Blade بگذارید و مقدارها را از config/services.php بخوانید.
{{-- config/services.php:
'daneshyar' => [
'widget_key' => env('DANESHYAR_WIDGET_KEY'),
'app_id' => env('DANESHYAR_APP_ID'),
'workspace_id' => env('DANESHYAR_WORKSPACE_ID'),
], --}}
<body>
@yield('content')
<script
src="https://app.daneshyar.info/widget.js"
data-api-key="{{ config('services.daneshyar.widget_key') }}"
data-app-id="{{ config('services.daneshyar.app_id') }}"
data-workspace-id="{{ config('services.daneshyar.workspace_id') }}"
async
></script>
</body>بعد از تغییر .env، دستور php artisan config:clear را اجرا کنید تا Laravel مقدارهای تازه را بخواند.
Node.js و Express
ابزارک در مرورگر اجرا میشود، پس برای آن به سرور نیازی ندارید. سرور فقط وقتی لازم است که صفحهٔ گفتوگوی خودتان را بسازید. آن وقت سرور شما با کلید، REST API را صدا میزند و صفحهتان سرور شما را:
import express from "express";
const BASE = "https://api.daneshyar.info/api/v1";
const KEY = process.env.DANESHYAR_API_KEY; // server only, never in the browser
const WORKSPACE = process.env.DANESHYAR_WORKSPACE_ID;
const app = express();
app.use(express.json());
// Your frontend calls POST /api/ask. Only this server knows the key.
app.post("/api/ask", async (req, res) => {
const { question, sessionId } = req.body;
if (typeof question !== "string" || !question.trim()) {
return res.status(400).json({ error: "question is required" });
}
const upstream = await fetch(`${BASE}/workspaces/${WORKSPACE}/chat/`, {
method: "POST",
headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({
message: question,
session_id: sessionId ?? undefined,
// One id per signed-in user keeps their chats apart.
external_user_id: String(req.user?.id ?? "anonymous"),
}),
});
const body = await upstream.json();
if (!upstream.ok) {
return res.status(upstream.status).json({ error: body.message ?? body.detail });
}
const reply = body.data.assistant_message;
res.json({
sessionId: body.data.session.id,
answer: reply.content,
sources: reply.citations,
});
});
app.listen(3000);درخواست و پاسخ کامل در صفحهٔ API گفتوگو آمده است. این کلید باید روی سرور بماند. هیچوقت آن را به مرورگر نفرستید.
چه چیزی باید ببینید
- یک دکمهٔ گرد در گوشهٔ همهٔ صفحهها (یا گفتوگو داخل عنصر خودتان، در حالت درونصفحهای).
- با کلیک روی آن، گفتوگو با عنوان شما و فهرست اسناد باز میشود.
- سؤالی دربارهٔ اسنادتان، پاسخی با منبعهای شمارهدار میگیرد.
چیزی نمایش داده نمیشود یا پیام خطا میبینید؟ رفع اشکال را ببینید.