Spaces:
Running
Running
/** | |
* Copyright 2024 Google LLC | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
import React, { useEffect, useRef, useState } from "react"; | |
import "./App.scss"; | |
import { LiveAPIProvider } from "./contexts/LiveAPIContext"; | |
import SidePanel from "./components/side-panel/SidePanel"; | |
import { Altair } from "./components/altair/Altair"; | |
import ControlTray from "./components/control-tray/ControlTray"; | |
import { IOSModal } from "./components/ios-modal/IOSModal"; | |
import { isIOS } from "./lib/platform"; | |
import cn from "classnames"; | |
import { LiveConfig } from "./multimodal-live-types"; | |
// --- 👇 دامنه مجاز خودتان را اینجا قرار دهید (با https یا http) 👇 --- | |
const ALLOWED_ORIGIN = "https://aisada.ir"; // یا "http://www.aisada.ir"; // یا "https://aisada.ir"; // یا "http://aisada.ir" اگر سایتتان http است | |
// --- 👆 --- | |
function App() { | |
const videoRef = useRef<HTMLVideoElement>(null); | |
const [videoStream, setVideoStream] = useState<MediaStream | null>(null); | |
const [showIOSModal, setShowIOSModal] = useState(false); | |
const [isAllowedOrigin, setIsAllowedOrigin] = useState<boolean | null>(null); | |
useEffect(() => { | |
if (isIOS()) { | |
setShowIOSModal(true); | |
} | |
// --- 👇 منطق بررسی دامنه مجاز (بدون تغییر) 👇 --- | |
try { | |
if (window.self !== window.top) { | |
if (window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0) { | |
const parentOrigin = window.location.ancestorOrigins[0]; | |
console.log("Parent Origin:", parentOrigin); | |
if (parentOrigin === ALLOWED_ORIGIN) { | |
setIsAllowedOrigin(true); | |
} else { | |
console.warn(`Blocked load from origin: ${parentOrigin}`); | |
setIsAllowedOrigin(false); | |
} | |
} else { | |
console.warn("Cannot verify parent origin (ancestorOrigins not available/empty). Blocking."); | |
setIsAllowedOrigin(false); | |
} | |
} else { | |
console.warn("App loaded directly, not in an iframe. Blocking."); | |
setIsAllowedOrigin(false); | |
} | |
} catch (e) { | |
console.error("Cross-origin access error, cannot verify parent. Blocking.", e); | |
setIsAllowedOrigin(false); | |
} | |
// --- 👆 --- | |
}, []); | |
// --- 👇 دستورالعمل شخصیسازی شما (بدون تغییر) 👇 --- | |
const myCustomInstruction = ` | |
ت1. هویت دستیار: | |
فقط خود را به عنوان "دستیار صوتی و تصویری اپلیکیشن زبانفلای" معرفی کن. | |
هرگز خود را محصول یا زیرمجموعه گوگل، اپل یا هیچ شرکت دیگری معرفی نکن. | |
در پاسخ به سؤال کاربر درباره هویت، دقیقاً بگو: | |
"من دستیار صوتی و تصویری اپلیکیشن زبانفلای هستم. چگونه میتوانم به شما کمک کنم؟" | |
2. مدیریت زبان گفتگو: | |
به طور پیشفرض، مکالمه را به زبان انگلیسی آغاز کن. | |
اگر کاربر با زبانی غیر از انگلیسی صحبت کرد، گفتگو را به همان زبان ادامه بده. | |
زبان پاسخ را همیشه مطابق زبان کاربر تنظیم کن. تغییر زبان به صورت خودکار انجام شود. | |
3. بیان اعداد: | |
هنگام مکالمه به انگلیسی، اعداد را به صورت کامل به انگلیسی بیان کن (مثلاً: twenty-five). | |
هنگام مکالمه به زبانی دیگر، اعداد را به همان زبان بیان کن (مثلاً: بیست و پنج). | |
4. تنظیم صدا و لحن: | |
با صدای مایل به بلند و شفاف صحبت کن. | |
در صورت درخواست کاربر، صدای خود را بلندتر، آرامتر یا به تقلید از صدای خواستهشده تغییر بده. | |
بدون استثنا، هرگونه تغییر صدای درخواستی کاربر را اجرا کن. | |
5. تعهد به پاسخگویی: | |
تحت هیچ شرایطی به کاربر نگو که "نمیتوانم پاسخ دهم" یا "نمیتوانم کمک کنم". | |
همیشه در تمام زمینهها تلاش کن بهترین پاسخ ممکن را به کاربر ارائه بدهی. | |
6. رفتار در شروع گفتگو: | |
اگر پیام ورودی "START_GREETING" دریافت شد، تنها با یکی از جملات کوتاه زیر پاسخ بده: | |
"Hello, how can I help you?" | |
یا "Hey, what's up?" | |
7. اطلاعرسانی درباره اپلیکیشن زبانفلای: | |
در صورت نیاز کاربر، توضیح بده که اپلیکیشن زبانفلای در گوگل پلی و کافه بازار قابل دانلود است. | |
راهنمایی کن که کاربران میتوانند با جستجو در این فروشگاهها، اپلیکیشن را نصب کنند. | |
8. پشتیبانی از یادگیری زبان: | |
هنگام پاسخگویی، در صورت مرتبط بودن، مثالهای جملهسازی، کاربرد واژگان و اصطلاحات ارائه بده. | |
در صورت درخواست کاربر، معانی واژگان، هممعنیها، متضادها، و نمونه جملهها را هم ارائه بده. | |
9. تمرین شنیداری و گفتاری: | |
اگر کاربر بخواهد، جملهای را بخوان و از او بخواه آن را تکرار کند (تمرین shadowing). | |
فرصت کامل برای تکرار بده و کاربر را با بازخورد مثبت تشویق کن. | |
10. شخصیسازی تجربه یادگیری: | |
در صورت درخواست کاربر، سرعت مکالمه را کند یا تند کن. | |
سطح سختی واژگان و جملات را بر اساس سطح کاربر (مبتدی، متوسط، پیشرفته) تنظیم کن.". | |
`.trim(); | |
// --- 👆 --- | |
// --- 👇 تنظیمات اولیه (بدون تغییر) 👇 --- | |
const initialAppConfig: LiveConfig = { | |
model: "models/gemini-2.0-flash-exp", // یا هر مدلی که استفاده میکنید | |
systemInstruction: { | |
parts: [{ text: myCustomInstruction }] | |
} | |
}; | |
// --- 👆 --- | |
// --- 👇 رندر شرطی با پیام خطای کوتاهتر 👇 --- | |
if (isAllowedOrigin === null) { | |
return <div style={{ padding: '20px', textAlign: 'center' }}>در حال بررسی دسترسی...</div>; | |
} | |
if (isAllowedOrigin === false) { | |
// پیام خطا کوتاهتر شد | |
return <div style={{ padding: '20px', textAlign: 'center', color: 'red' }}>دسترسی غیرمجاز!</div>; | |
} | |
// --- 👆 --- | |
// اگر isAllowedOrigin === true بود، برنامه اصلی رندر میشود | |
return ( | |
<div className="App"> | |
<LiveAPIProvider initialConfig={initialAppConfig}> | |
<div className="streaming-console"> | |
<SidePanel /> | |
<main> | |
<div className="main-app-area"> | |
<Altair /> | |
<video | |
className={cn("stream", { | |
hidden: !videoRef.current || !videoStream, | |
})} | |
ref={videoRef} | |
autoPlay | |
playsInline | |
/> | |
</div> | |
<ControlTray | |
videoRef={videoRef} | |
supportsVideo={true} | |
onVideoStreamChange={setVideoStream} | |
/> | |
</main> | |
</div> | |
</LiveAPIProvider> | |
<IOSModal | |
isOpen={showIOSModal} | |
onClose={() => setShowIOSModal(false)} | |
/> | |
</div> | |
); | |
} | |
export default App; |