Refactor Google Meet Transcripts Extension for Local Use

- Removed all cloud-related functionalities, including login prompts and token handling.
- Disabled Laxis cloud features, ensuring no data is sent to external servers.
- Updated manifest to reflect the new local-only functionality.
- Added a new Python server to handle transcripts locally, including WebSocket support.
- Implemented storage management for transcripts, including deduplication and file writing.
- Created a smoke test for the WebSocket server to simulate transcript updates.
- Updated README with setup instructions and usage details for the new local server.
This commit is contained in:
vahidaskari
2026-06-12 00:31:32 +03:30
parent 602dcb7430
commit 7bc34c79ed
35 changed files with 1069 additions and 840 deletions
+51
View File
@@ -0,0 +1,51 @@
# Action — Doc Writing
با قواعد اینجا باید اکشن‌ها رو بسازی که داک‌های من و خودت هست و بعد از اجرا اگر
جزییاتی داشت که من نیاز داشت بدونم توی ریزالت یک ریزالت با همین نام می‌سازی و
نتیجه‌ی کارت رو داک می‌کنی.
اکشن‌ها جنرال هستن و روی موقعیت‌های مشابه ممکنه همون داک رو مجدد بهت بدم.
اما ریزالت می‌تونه داخلش اطلاعات اون اجرات و درس‌آموخته‌هات باشه.
---
## ساختار فایل‌ها
```
docs/
├── action/ ← عمومی، قابل استفاده مجدد
└── result/ ← مخصوص هر اجرا
```
**فرمت نام فایل:**
```
{sequential_numbering_xxx}_action_{short_title_of_doc}.md
{sequential_numbering_xxx}_result_{short_title_of_doc}.md
```
- شماره‌ی `NNN` بین جفت action/result **مشترک** است.
- عنوان کوتاه (`short_title`) در هر دو **یکسان** است.
---
## action چیست؟
- **جنرال** — هر بار که موقعیت مشابه پیش آمد، همین فایل داده می‌شود.
- **بدون جزئیات اجرا** — هیچ نام فایل، تاریخ، یا تصمیم مخصوص یک run توش نباشد.
- می‌تواند شامل: هدف، چک‌لیست کارها، قواعد، یا context کلی باشد.
- اگر در حین اجرا متوجه شدی که action ناقص یا گمراه‌کننده بوده، **آن را بهبود بده**.
## result چیست؟
- **مخصوص همان اجرا** — تاریخ، فایل‌های ساخته‌شده، تصمیم‌های گرفته‌شده.
- **درس‌آموخته** — چیزی که دفعه‌ی بعد باید متفاوت انجام شود.
- **وضعیت** — چه چیزی انجام شد، چه چیزی باقی ماند.
- **نیاز به تصمیم** — اگر چیزی هست که کاربر باید تصمیم بگیرد، اینجا بنویس.
---
## قواعد کلی
- result را **بعد از اجرا** بساز، نه قبل از آن.
- اگر result از قبل وجود داشت (اجرای مجدد همان action)، یا آپدیتش کن یا یک بخش
جدید با تاریخ جدید اضافه کن — فایل را overwrite نکن.
- اطلاعاتی که «کاربر نیاز دارد بداند» را در result بنویس، نه فقط خلاصه‌ی فنی.
+77
View File
@@ -0,0 +1,77 @@
- [ ] از اسکریپت laxi هرچیزی که اضافه هست رو حذف کنیم.
- [ ] برای لوگو یک لوگو از خودمون میذاریم.
- [ ] مثلا لاگین یا اگر داده‌ای به جایی میفرسته نباید بفرسته اینا هم اضافی هستن
- [ ] هدف نهایی: بتونیم با استفاده از این پلاگین کپشن رو بگیریم
- [ ] راهکارها:
- [ ] پلاگین خودش یک mcp سرویس بده روی یک پورت
---
<!-- Claude Code comments -->
**درباره حذف کدهای laxis:**
فایل‌هایی که احتمالاً باید بررسی بشن: `analytics.js`، `login.js`، `runtime.js` (در `google-meet-transcripts-extension/`) — اینا بیشترین احتمال ارتباط با سرور laxis رو دارن. `config/` هم ممکنه endpoint داشته باشه. پیشنهاد: اول یه `grep` روی همه فایل‌ها برای `laxis` و `api.` و `fetch(` بزن تا دقیق بفهمیم کجاها data میفرسته.
**درباره MCP روی پورت:**
این رویکرد خوبیه ولی یه محدودیت داره — Chrome extension نمیتونه مستقیم TCP server باز کنه. راه‌حل‌های ممکن:
1. **Native Messaging:** extension با یه اپ native (Python/Node) صحبت میکنه که اون اپ MCP server هست — پیچیده‌تر ولی استانداردتر
2. **WebSocket از extension:** extension یه WebSocket server روی `localhost` باز میکنه از طریق یه background service worker + `chrome.sockets` API — محدودیت‌های manifest v3 داره
3. **Polling روی clipboard یا فایل:** ساده‌ترین راه — extension هر X ثانیه caption رو در یه فایل یا clipboard میریزه، اپ دیگه‌ای میخونه
کدوم راهکار رو در نظر داری؟
---
# پیاده‌سازی — معماری Bridge
> راهکار انتخابی: **افزونه به‌عنوان WebSocket _client_** به یک سرور پایتونِ بیرون مرورگر وصل می‌شود.
> (نه راهکار ۲ که افزونه خودش server باشد — در MV3 سرویس‌ورکر نمی‌تواند پورت TCP باز کند.)
## دیاگرام جریان داده
```mermaid
flowchart TD
A["Google Meet<br/>caption روی صفحه"] -->|"DOM observer"| B["content script<br/>captionProcessing.js"]
B -->|"setSpeaker()"| C["storage.js<br/>نقطه‌ی choke هر caption"]
C -->|"chrome.runtime.sendMessage<br/>{type: TRANSCRIPT_UPDATE}"| D["service worker<br/>bridge.js"]
D -->|"WebSocket<br/>ws://127.0.0.1:8765"| E["سرور پایتون<br/>bridge/server.py"]
E -->|"ذخیره"| F["transcripts/&lt;sessionId&gt;.txt"]
E -.->|"ACK / PONG"| D
E ==>|"گام بعدی"| G["MCP Server"]
G ==> H["Claude<br/>transcript زنده را می‌خواند"]
style E fill:#2F5496,color:#fff
style G fill:#888,color:#fff,stroke-dasharray: 5 5
style H fill:#888,color:#fff,stroke-dasharray: 5 5
```
## چرا client و نه server؟
- **CSP گوگل میت:** اگر WebSocket را از content script باز کنیم، `connect-src` صفحه بلاکش می‌کند.
سرویس‌ورکر تابع CSP صفحه نیست → اتصال از آن‌جا باز می‌شود.
- **MV3 لایف‌سایکل:** سرویس‌ورکر بعد ~۳۰ ثانیه می‌خوابد. دو مکانیزم نگهش می‌دارد:
(۱) هر پیام جدید از content script بیدارش می‌کند، (۲) heartbeat (PING) هر ۲۰ ثانیه
(از Chrome 116+ پیام WebSocket زیر ۳۰ ثانیه ورکر را زنده نگه می‌دارد).
## وضعیت فعلی — ✅ گام ۱ انجام شد (MVP اتصال)
| قطعه | فایل | کار |
|------|------|-----|
| سرور پایتون | `bridge/server.py` | WebSocket روی `127.0.0.1:8765`، ذخیره در `transcripts/` |
| WS client | `google-meet-transcripts-extension/bridge.js` | اتصال + reconnect + heartbeat |
| ایمپورت در ورکر | `login.js` | `importScripts("bridge.js")` |
| نقطه‌ی hook | `storage.js``setSpeaker` | ارسال `TRANSCRIPT_UPDATE` |
| دسترسی شبکه | `manifest.json` | `ws://127.0.0.1:8765/*` در host_permissions |
تست end-to-end سمت پایتون با `_smoke_test.py` پاس شد (PONG + ACK + ذخیره‌ی فایل).
## مراحل بعدی
- [ ] **پاک‌سازی کد laxis** (طبق بالای همین سند): حذف لاگین، analytics، و fetch به `domainUrl`.
- [ ] **تست میدانی با Chrome واقعی:** سرور را بالا بیاور، افزونه را Reload کن، در یک Meet
caption را روشن کن و خروجی را در ترمینال/فایل ببین.
- [ ] **افزودن MCP server** روی همین `server.py` (مثلاً با `mcp` SDK پایتون) تا Claude
بتواند transcript زنده را به‌عنوان resource/tool بخواند.
- [ ] **لوگوی اختصاصی** جایگزین لوگوی laxis.
## محیط توسعه
پایتون داخل **venv** اجرا می‌شود تا سیستم تمیز بماند (راهنما: `bridge/README.md`).