Fujimod
브라우저에서 카메라 펌웨어를 시험하고 Fujimod SD 부팅 파일을 만든다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗מתכנן טיולים בעברית — בונים מסלול יום-אחר-יום, מקבלים קוד שיתוף בן 6 ספרות, ושולחים לחברים.
public/js/popular.js, רשימה אחת לדף הבית ולאשף) — וקרוסלת טיולים מומלציםbuild_now של המודל נזרק בקוד). ה-AI בונה ועורך את התחנות בעצמו דרך אותם ops, אותו אימות מקומות ואותו כותב של השינוי החכם, ומעבר לתחנות — מלונות, מסגרת התקציב ותאריך היציאה (lib/plan-actions.js, עם היפוך מדויק לכל פעולה). כל שינוי הוא כרטיס אחד, וה-AI מחליט בעצמו בכל תור אם הוא מבצע מיד (עם ביטול) — שינוי שהתבקש במילים, או עובדה שנמסרה: כרטיס, הזמנה, תקציב — או מציע לאישור — יוזמה שלו, מחיקה או החלפה של מה שהמטיילים בחרו. (היה כאן מתג ידני/אוטומטי; הנתונים הראו אותו נלחץ הלוך ושוב.) ליד שורת ההקלדה + לצירוף כרטיס טיסה, אישור מלון או צילום מסך: הקובץ נקרא במכשיר (שכבת הטקסט של PDF, OCR של הדפדפן או tesseract — אותו סולם כמו במסמכים, doc-text.js), ולשרת נשלח הטקסט ולא הקובץ; רק תמונה שהמכשיר לא הצליח לקרוא נשלחת כעותק מוקטן (עד 1024px, JPEG) שהמודל קורא ברמת low — עלות קבועה וזעירה. עד 3 קבצים ביום למשתמש (lib/attachments.js, מונה files), וה-AI פותח את התשובה במה שהבין מהקובץ ("ראיתי שהעליתם כרטיסי טיסה עם קונקשן בציריך") ואז ממלא: טיסה למסלול, מלון לרשימת המלונות, תאריך לטיול. כל קובץ שמצורף נשמר ברקע גם במסמכים של הטיול (TripDocs.stash), מתויג לפי הטקסט שכבר נקרא — בלי OCR שני ובלי הודעה; התג על טאב המסמכים הוא כל ההכרזה. חלוקת האזורים שה-AI מציע מצוירת על לוח שנה בתוך הצ'אט, וצובעים ימים כדי לשנות. כשהטיול נראה מגובש ה-AI מציע פעם אחת להזמין חברים לתכנון (וואטסאפ / קישור). כל תור על המודל החזק — צ'אט הוא קול אחד, ושני מודלים נשמעו כשניים. השיחה וזיכרון התכנון (trips.plan_state: שלב, עובדות שהוסכמו, חלוקת האזורים) נשמרים בשרת (trip_plan_messages), כך שהמודל לא "שוכח" החלטה מלפני עשרים הודעות. מרגע השמירה הטאב הופך להמלצות. routes/plan.js; 20 הודעות ליום למשתמשPOST /api/trips/code/:code/recs: המודל החזק עונה, כל מקום מאומת מול Photon/Google ומה שלא אומת נזרק, תמונות מוויקיפדיה (חינם, בלי מפתח), 30 שאלות ליום למשתמשtrip_day_recs) כך שכל המשתתפים רואים אותן, ונטענות לפי הסדר הכרונולוגי ובבקשות קטנות: קודם נקבעת חלוקת הימים לאזורים — החלוקה שהמטיילים קבעו בצ'אט התכנון אם יש כזו, אחרת זו שהתחנות כבר מכתיבות, ורק כשאין אף אחת מהן בקשה נפרדת ל-AI (trip_rec_areas, נשמרת ונשאלת מחדש אחרי כל שינוי; היא פנימית בלבד ולא משנה את המסלול) — ואז בקשה אחת לכל אזור, עד שישה ימים בכל בקשה, עם הימים הקבועים שבטווח כ-context. כל יום נכתב ברגע שהוא מוכן, כך שטיול של 30 יום מתמלא מיום 1 והלאה מול המשתמש במקום להמתין לסוף; הטעינה מתחילה כבר במסך הטעינה של הדף ושל הבנייה. אחרי כל שינוי במסלול — מהצ'אטים או ידני — נשלחת בקשה נוספת, שמשחזרת רק ימים שה-context שלהם השתנה (האזור והתחנות משני צדדיו), כך שתחנה שנוספה ביום 3 לא מייצרת 30 קריאות מודל. routes/day-recs.js, public/js/trip-dayrecs.js; בדיקת המבנה בלי מודל: node tools/day-recs-plan-check.js; הכפתור מוגבל ל-40 רענונים ליום למשתמש🚪 סגור, עם התגית שממנה זה נקבע). המקור החינמי קודם: התגית opening_hours של OSM דרך ה-endpoint של האלמנט (בלי מפתח, בלי מכסה), וגוגל רק למה ש-OSM לא ידע. אף פעם לא מנחשים: תגית שהפרסר לא מבין במלואה מקבלת unknown ולא "סגור", כי סימון שגוי גורם למטייל לוותר על מקום פתוח. הסימון הוא הצעה בלבד — שום דבר לא זז ולא נמחק מהמסלול. lib/opening-hours.js, routes/hours.js; בדיקה בלי רשת: node tools/opening-hours-check.js; בדיקת נגישות המקורות מהשרת: node tools/opening-hours-probe.js; מדידת הבסיס על טיולים אמיתיים: node tools/opening-hours-audit.jslib/hours-fit.js). המלצות ליום פנוי פשוט לא מציעות מקום שסגור באותו יום. הדיווח נשאר בכל מקרה — תחנה שנוספה ידנית או שעה ששונתה ביד לא עוברות כאן כלל⏱ לא מספיקים; לעורך הסימון הוא התיקון: לחיצה אחת מזיזה אותה לשעה הראשונה שאפשר להגיע בה). הכלל אחד, משותף לבנייה ולדף (public/js/travel-rules.js): לכל קטגוריה רצפת שהייה (ארוחה 45 דק׳, מוזיאון שעה…) — לא הערכה, מינימום — ותחנה נחשבת מחוץ להישג רק כשגם המינימום ועוד הדרך לא נכנסים בפער. קטע של מעל 120 ק״מ לא נשפט (רכבת? מטוס?), וגם קטע אל תחנת נסיעה או ממנה — היא עצמה הנסיעה. בבנייה (lib/travel-fit.js, לפני בדיקת השעות) תחנה כזו זזה קדימה, בתוך היום שלה, ולעולם לא מעבר לתחנה הבאה — אחרת מדווחת ולא זזה. תשובות OSRM נשמרות ב-api_cache, ורוּטר שלא עונה לא משנה כלום. בדיקה בלי רשת: node tools/travel-fit-check.jspublic/js/doc-classify.js, ובדיקתם: node tools/docs-classify-check.jsroutes/checklist.js, public/js/trip-checklist.js, המילון המשותף ב-public/js/checklist-tags.js; טבלאות trip_checklists, trip_checklist_items, trip_checklist_tickslib/quota.js) — מונה יומי אחד לכל פיצ'ר (בניות, שינויים חכמים, שאלות המלצות, הודעות תכנון), נשמר ב-DB (ai_usage) ולא בזיכרון, כי השרת החינמי מתאתחל בכל deploy ונרדם אחרי רבע שעה. מנהלים לא מוגבלים. כשהמכסה נגמרת הצ'אט לא מציג שגיאה אלא כרטיס: אפשר להמשיך ידנית ומחר יש מכסה חדשה — ומי שמשתף את האפליקציה בוואטסאפ ושלושה חברים נרשמים דרך הקישור שלו (/?ref=CODE, GET /api/me/referral) מקבל מכסה כפולה לכל המונים, לתמיד/trip/CODE#plan)lib/guest.js: שורת users בלי אימייל, JWT עם guest: true), והאשף, צ'אט התכנון, הבנייה והעריכה עובדים לו כמו לכל אחד. החומה עומדת איפה שהטיול הופך לאמיתי לאנשים אחרים — שמירת הטיול (חשיפת קוד השיתוף) והצטרפות לטיול של מישהו אחר — ושם ההרשמה שומרת הכול: הרשמה הופכת את שורת האורח עצמה לחשבון (אותו id), והתחברות לחשבון קיים מעבירה אליו את הטיולים, ההצטרפויות וההצבעות ומוחקת את האורח (גם דרך Google, עם ?guest= על הקישור). "הטיולים שלי" אומר לאורח שהטיולים שמורים בדפדפן הזה בלבד. טביעת אורחים מוגבלת ל-10 לרבע שעה לכתובת, כמו הרשמה — כל אורח הוא מכסות AI טריותapi/index.js), PostgreSQL (Neon, דרך Vercel)האתר מצהיר על עצמו לסוכנים דרך WebMCP: במקום שסוכן ינחש איפה לוחצים, הדף מגיש לו כלים בשם, עם סכימת קלט ותוצאה מובנית.
הכלים נרשמים לכל מארח שהדפדפן חושף, לפי הסדר: document.modelContext (הטיוטה של W3C),
navigator.modelContext (Edge 147 / ה-origin trial של Chrome 149), ובכל מקרה גם window.tripmakerTools —
גשר משלנו. הגשר הוא זה שעובד היום בפועל: תמיכה נייטיבית עדיין דקה, ורוב הסוכנים שמגיעים לאתר עושים זאת
דרך דפדפן headless שבו הערוץ היחיד הוא הרצת JS.
window.tripmakerTools.host // 'document' | 'navigator' | null
window.tripmakerTools.list() // כל הכלים: שם, תיאור, inputSchema, annotations
await window.tripmakerTools.call(name, input)
התוצאה תמיד באותו מבנה — content קריא לאדם ו-structuredContent לפרסור. כישלון חוזר כתוצאה עם
isError: true ולא כחריגה, כדי שסוכן יוכל לקרוא את הסיבה ולנסות מהלך אחר.
בכל דף (webmcp-tools.js): tripmaker_whoami · tripmaker_search_trips ·
tripmaker_list_suggested_trips · tripmaker_get_trip · tripmaker_list_my_trips ·
tripmaker_search_destinations · tripmaker_create_trip · tripmaker_open
רק כשטיול פתוח (נרשמים מ-trip.js): tripmaker_current_trip · tripmaker_add_stop ·
tripmaker_update_stop · tripmaker_delete_stop
כלי התחנות עוברים דרך addItem/saveItem/deleteItem של הדף עצמו, לא ישר ל-API — כך עריכה של סוכן
מתרנדרת בשתי התצוגות בדיוק כמו עריכה של אדם, במקום להשאיר על המסך מסלול שכבר לא קיים.
הערות אבטחה: כלי קריאה מסומנים readOnlyHint, וכל כלי שמחזיר תוכן שנוצר על ידי משתמשים אחרים מסומן גם
untrustedContentHint. הרשאות לא נעקפות — הכלים רוכבים על אותו JWT ואותן בדיקות הרשאה של ה-API, וסוכן
לא מתחבר בשם המשתמש. /admin לא טוען את הכלים בכוונה.
node db/migrate.js — עמודת destinations (ריבוי יעדים + קואורדינטות), אידמפוטנטי.
npm install
# צרו קובץ .env עם:
# DATABASE_URL=postgresql://...
node db/setup.js # פעם אחת: סכימה + טיולים מומלצים
npm start # http://localhost:3000
npm test # כל הבדיקות שלא צריכות רשת, מפתח או DB: תחביר של כל קובץ + ארבעת סקריפטי ה-check
| משתנה | תיאור |
|---|---|
DATABASE_URL | כתובת חיבור ל-PostgreSQL. הסכימה, המיגרציות והטיולים המומלצים נוצרים לבד בעלייה (lib/db-bootstrap.js) — מסד נתונים חדש לא צריך שום צעד ידני |
IMPORT_FROM_DATABASE_URL | חד-פעמי: כתובת מסד הנתונים הישן (חי). בעלייה הבאה השרת מעתיק ממנו את כל הטבלאות (משתמשים, טיולים, תחנות…) עם אותם מזהים — רק לתוך מסד שאין בו עדיין משתמשים, אחרת מדלג. מסירים אחרי הריצה |
DB_BACKUP_KEY | סוד לפענוח גיבוי ה-escrow החודשי. כשהוא מוגדר, מסד ריק (או שיש בו רק טיולי הדגמה) משוחזר אוטומטית בעלייה מהגיבוי המוצפן ב-GitHub (lib/db-restore.js). בלעדיו אין שחזור — רק seed |
RESTORE_FROM_ESCROW | 1 = לכפות שחזור מה-escrow גם על טיולי הדגמה שכבר קיימים (התאוששות חד-פעמית). מוחק ומשחזר; מסירים אחרי הריצה. בלי זה השחזור רץ רק על מסד ריק/דגמה |
RESTORE_SOURCE_URL | אופציונלי — כתובת קובץ ה-escrow. ברירת מחדל: ה-raw של ofir6868/tripi בענף db-rotation-backups |
JWT_SECRET | סוד לחתימת טוקנים |
PORT | פורט (ברירת מחדל 3000). רלוונטי רק כשמריצים את server.js ישירות — על Vercel אין פורט להאזין עליו |
CRON_SECRET | הטוקן שהמתזמן של Vercel חותם איתו את /api/cron/tick — התזכורות, גיבוי ה-escrow וטאטוא המטמון, שעל מארח תמיד-דלוק רצים כטיימרים בתוך התהליך. בלעדיו הנתיב מסרב לכולם, וזו התשובה הנכונה לנתיב שאחרת היה נותן לזר לשרוף לנו את מכסת ה-push |
OSRM_URL | אופציונלי — שרת הניתוב לזמני הנסיעה בין תחנות בבנייה (lib/travel-fit.js). ברירת מחדל: השרת הציבורי https://router.project-osrm.org, בלי מפתח. הדפדפן פונה אליו ישירות ולא דרך המשתנה הזה |
CANONICAL_ORIGIN | אופציונלי — המקור היחיד שמותר להיכנס לאינדקס. ברירת מחדל https://tripmaker.co.il (מתוך SITE ב-lib/seo.js). כל בקשת GET לדף שמגיעה למארח או לסכימה אחרים מקבלת 301 לכאן |
GOOGLE_PLACES_API_KEY | מפתח Google Places (New) — אוטוקומפליט של יעדים, וגם תמונות המקומות בכרטיסי ההמלצות. בלעדיו התמונות נופלות חזרה לוויקיפדיה |
AI_MODEL_PLAN | אופציונלי — המודל של צ'אט התכנון. ברירת מחדל: , כי התורות שלו מכניסות מקומות אמיתיים ישר למסלול |
ב-Google Cloud → OAuth client (Web application):
https://tripmaker.co.il (ו־http://localhost:3000 לפיתוח)https://tripmaker.co.il/api/auth/google/callback (ו־http://localhost:3000/api/auth/google/callback)אחרי הגדרת המשתנים, הריצו node db/migrate.js פעם אחת (עמודת google_sub + סיסמה אופציונלית).
בדיקת הספק הפעיל: node tools/hotel-content-probe.js (או node tools/hotel-content-probe.js liteapi).
AI_MODEL_STRONGAI_QUOTA_PLAN / AI_QUOTA_RECS / AI_QUOTA_BUILD / AI_QUOTA_EDIT / AI_QUOTA_CHECKLIST | אופציונלי — מכסה יומית למשתמש לכל מונה (ברירות מחדל 20 / 30 / 20 / 3 / 10; הצ'קליסט נספר רק ברענון, הבנייה הראשונה לטיול חינם). AI_QUOTA_PLAN=2 הוא הדרך לראות את כרטיס המכסה בלי שישים תורות אמיתיים |
PLACE_PHOTO_MONTHLY_LIMIT | תקרת הורדות התמונה מ-Google בחודש (ברירת מחדל 900 — מתחת ל-1,000 החינמיות של SKU Place Details Photos). מעבר לתקרה, תמונות מגיעות מוויקיפדיה. כל מקום נמשך פעם אחת ונשמר בקאש ב-DB (api_cache), כך שגם deploy לא קונה אותו מחדש. כל תקרות Google מוגדרות ב-lib/google-skus.js, נספרות לפי החודש של גוגל (שעון פסיפיק), משתחררות לאורך החודש, ומוצגות ב-/admin/google |
PLACE_HOURS_MONTHLY_LIMIT | תקרת בדיקות שעות הפתיחה מול Google בחודש (ברירת מחדל 900 — מתחת למכסת החינם של 1,000 בדרג Enterprise). OSM עונה חינם ובלי מכסה, וגוגל נשאל רק על מה ש-OSM לא ידע |
PLACE_SEARCH_MONTHLY_LIMIT | תקרת "חוות הדעת השנייה" של Google באימות מקומות (ברירת מחדל 4,000). מעבר לתקרה האימות נשאר על Photon בלבד — הוורדיקט אף פעם לא הופך ל-ok בגלל תקציב, הוא פשוט נשאר מה ש-OSM אמר |
PLACES_AUTOCOMPLETE_MONTHLY_LIMIT | תקרת האוטוקומפליט של בוחר המקומות (ברירת מחדל 4,000). מעבר לתקרה הבוחר נופל ל-Photon, בדיוק כמו בלי מפתח |
PLACES_DETAILS_MONTHLY_LIMIT | תקרת פענוח הקואורדינטות של מקום שנבחר (ברירת מחדל 5,000) |
GOOGLE_MONITORING_KEY | אופציונלי — JSON של service account עם התפקיד Monitoring Viewer בפרויקט של מפתח ה-Places (גולמי או ב-base64). כשמוגדר, /admin/google משווה את המונה שלנו למה שגוגל עצמו ספר. GOOGLE_MONITORING_PROJECT דורס את הפרויקט שהמפתח מציין |
BRAVE_SEARCH_API_KEY | אופציונלי — מפתח Brave Search (2,000 חיפושים חינם בחודש) לכלי החיפוש של ה-AI (lib/web-search.js). בלעדיו החיפוש עובר דרך דף ה-HTML של DuckDuckGo, בלי מפתח. בשני המקרים התוצאות מסוננות לרשימת אתרי הטיולים המורשים בלבד (Booking, Klook, SWISS, אל על, Google Maps, Tripadvisor, Wikipedia…) |
AI_SEARCH_EXTRA_SITES | אופציונלי — אתרים נוספים שמותר ל-AI לחפש ולקרוא בהם, מופרדים בפסיקים (example.com,other.org) |
CONNECTOR_SECRET | אופציונלי — מפתח ההצפנה של טוקני החיבורים (יומן/Gmail/Drive) ב-user_connectors. ברירת מחדל: נגזר מ-JWT_SECRET. החלפתו מנתקת את כל החיבורים (השורות הופכות בלתי-קריאות ונחשבות מנותקות) |
CONNECTORS_REDIRECT_URI | אופציונלי — ברירת מחדל {origin}/api/connectors/google/callback. צריך להיות רשום ב-Google Cloud לצד ה-redirect של ההתחברות, ואותו Client ID משמש את שניהם. ה-scopes: calendar.readonly, gmail.readonly, drive.readonly — קריאה בלבד |
GOOGLE_CLIENT_ID | OAuth 2.0 Client ID מ-Google Cloud (התחברות, וגם החיבורים של ה-AI) |
GOOGLE_CLIENT_SECRET | OAuth 2.0 Client Secret מ-Google Cloud |
GOOGLE_REDIRECT_URI | אופציונלי — ברירת מחדל {origin}/api/auth/google/callback (בפרודקשן: https://tripmaker.co.il/api/auth/google/callback) |
HOTEL_CONTENT_PROVIDER | ספק תוכן המלונות: osm (ברירת מחדל, ללא מפתח) או liteapi |
LITEAPI_KEY | מפתח LiteAPI — בלעדיו המערכת נופלת חזרה ל-osm ולא נשברת |
HOTEL_GUEST_NATIONALITY | לאום האורח לתמחור (ברירת מחדל IL) |