new-term-radar
신규 AI 용어를 매일 추적, X·Hugging Face·GitHub 등에서 모델·제품·레포 이름을 빠르게 수집
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Dyno Ads — Fasa 0 (Create Post) Auto-create iklan Meta Click-to-WhatsApp untuk peniaga kecil. Produk di bawah ekosistem DYNOPRO. Fasa 0 = alat single-account untuk pemilik. Tiada login, tiada OAuth, tiada bayaran. Token duduk dalam .env. Fasa 1 (guna posting sedia ada) hingga Fasa 9 diterangkan dalam CLAUDE.md dan docs/dyno-ads-spec-v0.2.md. Satu gambar = satu campaign. Itu asas split test: kita bandingkan gambar, bukan bandingkan adset dalam satu campaign. Frontend guna Tailwind CDN secara lalai — tak perlu npm untuk mula. Kalau nak build sendiri (lebih laju, saiz kecil):README 전문 보기 ↗
Auto-create iklan Meta Click-to-WhatsApp untuk peniaga kecil. Produk di bawah ekosistem DYNOPRO.
Fasa 0 = alat single-account untuk pemilik. Tiada login, tiada OAuth, tiada bayaran.
Token duduk dalam .env. Fasa 1 (guna posting sedia ada) hingga Fasa 9 diterangkan dalam
CLAUDE.md dan docs/dyno-ads-spec-v0.2.md.
/buat Upload 1–4 gambar → bisnes → masalah → tawaran → telefon → kawasan → bajet
/posting Pilih 2–4 posting Page sedia ada → kawasan → bajet → campaign PAUSED
/bisnes/{id} AI Amir terangkan bisnes → peniaga sahkan atau betulkan (sekali setiap bisnes)
/semak/{id} Caption AI (boleh edit) + pratonton → Approve → campaign dibuat PAUSED
/run/{id} Butang RUN SEMUA → campaign/adset/ad jadi ACTIVE. Pause per iklan.
/dashboard/{id} Spend, lead WhatsApp, kos/lead setiap iklan + rekod tindakan
Satu gambar = satu campaign. Itu asas split test: kita bandingkan gambar, bukan bandingkan adset dalam satu campaign.
git clone https://github.com/Dynopos/Dynopos.git
cd Dynopos
composer install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite # Fasa 0 guna sqlite
php artisan migrate
php artisan storage:link # supaya gambar boleh dipapar
php artisan serve # http://localhost:8000
Frontend guna Tailwind CDN secara lalai — tak perlu npm untuk mula.
Kalau nak build sendiri (lebih laju, saiz kecil):
npm install && npm run build # layout auto-guna build kalau manifest wujud
.env yang perlu diisi| Kunci | Contoh | Nota |
|---|---|---|
META_ACCESS_TOKEN | EAAB… | System User token, expiry Never. Jangan commit. |
META_AD_ACCOUNT_ID | act_701202512896650 | Prefix act_ ditambah automatik kalau tertinggal |
META_PAGE_ID | 377330642350146 | Page yang linked dengan nombor WhatsApp |
META_WA_PHONE | 60187922844 | Format antarabangsa, tiada + |
META_API_VERSION | v21.0 | Versi dipin — jangan auto-upgrade |
OPENAI_API_KEY | sk-… | Untuk caption. Tukar pembekal dengan CAPTION_DRIVER |
MetaAdsService tiada method update* — nak ubah campaign = buat baru.AdVariant::isOwnedByApp() menapis setiap pause/run. Campaign yang bukan app ni buat
tidak akan disentuh — ia langsung tiada dalam jadual ad_variants.PAUSED. Hanya butang RUN yang menghidupkannya.auto_actions sebelum panggilan API dibuat..env; MetaApiException sengaja tidak memuatkan token dalam mesej.Dari 150+ campaign sejarah DynoPOS (kos/lead ~RM10–15). Semuanya duduk dalam
config/dynoads.php — satu tempat, senang audit.
| Lapisan | Setting |
|---|---|
| Campaign | OUTCOME_ENGAGEMENT, budget di campaign (CBO), LOWEST_COST_WITHOUT_CAP, special_ad_categories=[] |
| Ad set | CONVERSATIONS, destination_type=WHATSAPP, billing_event=IMPRESSIONS, promoted_object={page_id, whatsapp_phone_number} |
| Targeting | umur 25–65, locales=[41], advantage_audience=1, location_types=[home,recent], brand safety RELAXED |
| Seluruh Malaysia | countries=[MY], exclude region 2546 Sarawak / 2550 Labuan / 2551 Sabah |
| Negeri tertentu | geo_locations.regions=[{key}] |
| Ad | link ad, WHATSAPP_MESSAGE, link=https://api.whatsapp.com/send, gambar via image_hash |
| Bajet lalai | RM37/hari (3700 sen) |
| Nama | DYNOADS-{setID}-{n}-{DDMMMYY} |
⚠️ Satu field perlu disahkan pada akaun sebenar: bila pilih negeri tertentu, kod menghantar
targeting_automation.individual_setting.geo_locations = 1(mengikut setup manual). Kalau Meta pulangkan ralat parameter, buang baris tu dalamMetaAdsService::buildTargeting()— tiada kesan lain.
Video dibenarkan sehingga 100MB setiap fail, empat fail setiap set iklan. Tanpa pembersihan, setiap video yang pernah dimuat naik kekal di cakera selamanya — kos yang berkembang tanpa had, dan Prinsip Penyimpanan PDPA yang tidak dipatuhi.
php artisan dynoads:prune-media --dry-run # papar sahaja, jangan padam
php artisan dynoads:prune-media # jalankan betul-betul
php artisan dynoads:prune-media --days=180 # tempoh lain
Dijadualkan 3:30 pagi waktu Malaysia setiap hari.
Scheduler mesti dihidupkan di Forge. Site → Scheduler → aktifkan. Tanpa cron
schedule:run, jadual ini tidak pernah berjalan dan tiada apa yang memberitahu anda. Jalankanphp artisan schedule:listuntuk mengesahkan ia terdaftar.
| Dibuang | Kekal |
|---|---|
| Fail gambar dan video | Baris ad_variants, caption, metrics_daily |
Yang kekal itu kecil, dan ia satu-satunya sebab peniaga boleh tahu creative mana yang menang tahun lepas.
Iklan di Meta tidak terjejas — Meta memegang salinannya sendiri melalui
image_hash dan video_id. Yang hilang ialah pratonton dalam app, dan keupayaan
melancarkan semula set iklan lama tanpa memuat naik semula.
active tidak pernah disentuh — walaupun
ia berjalan setahun. Peniaga melihatnya dalam dashboard setiap hari.dynoads/{set}/…;
satu baris pangkalan data yang rosak tidak boleh menyuruh kita memadam fail di
tempat lain.Skrin memaparkan "Gambar dibuang selepas 90 hari" dan bukan kotak kosong. Cuba
melancarkan set iklan yang medianya dibuang memberi ayat yang memberitahu apa yang
perlu dibuat, bukan amaran file_get_contents mentah.
| Laluan | Untuk |
|---|---|
/privasi | Notis Privasi — Akta 709 s.7 |
/terma | Terma Perkhidmatan |
POST /meta/data-deletion | Callback pemadaman data Meta |
/meta/data-deletion/status/{kod} | Status permintaan pemadaman |
Ketiga-tiga yang pertama ialah prasyarat App Review Meta. Dua yang pertama juga kewajipan PDPA secara berasingan — anda perlukannya walaupun tiada Meta.
Notis Privasi mengambil butiran Data User dari .env, bukan dari kod:
COMPANY_NAME=
COMPANY_SSM=
COMPANY_ADDRESS=
COMPANY_EMAIL=
COMPANY_PHONE=
Selagi ia kosong, /privasi memaparkan amaran kuning yang menyatakan notis itu belum
lengkap. Itu disengajakan: notis yang membawa butiran syarikat yang direka lebih
teruk daripada tiada notis — ia menipu pengguna dan tidak melindungi sesiapa.
META_APP_SECRET wajib diisi. Endpoint itu terdedah kepada internet terbuka tanpa log
masuk dan tanpa CSRF — satu-satunya yang menjaganya ialah tandatangan HMAC pada
signed_request. Tanpa rahsia app, ia menolak semua permintaan. Gagal tertutup,
bukan gagal terbuka.
Yang dipadam: FbConnection — token, id akaun iklan, id dan nama Page, nombor WhatsApp.
Yang tidak dipadam: set iklan dan metrik. Itu rekod perniagaan peniaga sendiri, dan
memusnahkannya atas satu callback akan menghapuskan sejarah yang dia mungkin perlukan.
Halaman status menerangkan perbezaan ini.
Dalam tetapan app Meta, isi:
https://dynoads.my/privasihttps://dynoads.my/termahttps://dynoads.my/meta/data-deletionLaravel Forge: lihat docs/forge.md — deploy script, tetapan PHP,
dan cara isi .env melalui tab Environment.
Setiap peniaga ada akaun sendiri, kredential Meta sendiri, dan tidak nampak data peniaga lain.
| Laluan | Untuk |
|---|---|
/daftar, /masuk | akaun peniaga |
/sambung | token, ad account, Page dan nombor WhatsApp peniaga |
Kredential ditentukan di satu tempat sahaja: App\Services\Meta\MetaCredentials.
.env kekal berfungsi, tetapi hanya untuk pemilik app (users.is_owner).
Peniaga lain tanpa FbConnection aktif tidak boleh membuat iklan — kalau tidak
mereka akan membelanjakan duit pemilik.
Data sedia ada (ad_sets, poster_jobs) mempunyai user_id null dan tidak kelihatan
kepada sesiapa sehingga dituntut:
php artisan migrate
php artisan dynoads:owner [email protected] --name="Borhan"
Arahan itu mencipta akaun pemilik (kalau belum ada), menetapkan is_owner, dan
menyerahkan semua baris yang belum bertuan kepadanya.
Token disimpan berenkripsi (APP_KEY). Ia tidak pernah dipapar semula selepas
disimpan, dan tidak pernah masuk ke dalam log atau mesej ralat — peraturan mutlak #8.
php artisan test
Semua panggilan luar guna Http::fake() — test tidak sentuh Meta atau Claude.
Yang diuji: payload campaign/adset/ad, targeting geo, parsing insights
(onsite_conversion.total_messaging_connection), pengendalian error_user_msg,
retry JSON caption, penapis perkataan larangan, flow Livewire /buat →
/semak → /run → /dashboard, dan setiap peraturan mutlak CLAUDE.md
(tests/Feature/AbsoluteRulesTest.php).
vendor/bin/pint --test # gaya kod
php artisan test # 34 test
CI (.github/workflows/ci.yml) jalankan Pint + test pada setiap push.
DYNOADS-…app/Services/MetaAdsService.php semua panggilan Graph API (tiada method update*)
app/Services/CaptionService.php caption AI, fallback bila Claude gagal
app/Services/AdLauncher.php orkestra DB ⇄ Meta, log auto_actions
app/Services/ImageProcessor.php crop tengah 1080×1080 (GD)
app/Exceptions/MetaApiException.php ralat Graph API, mengutamakan error_user_msg
app/Models/ AdSet, AdVariant, AutoAction, MetricDaily
app/Livewire/AdSets/ Create, Review, Run, Dashboard
resources/views/livewire/ad-sets/ 4 skrin, mobile-first, BM santai
config/dynoads.php semua setting Meta yang terbukti
docs/dyno-ads-spec-v0.2.md spec produk penuh
Kunci region Meta tidak pernah ditulis tangan dalam kod. Skrin /buat menarik
senarai negeri terus dari GET /search?type=adgeolocation&country_code=MY
(cache 24 jam), jadi ia sentiasa sepadan dengan akaun sebenar. Tanpa token,
pilihan kekal "Seluruh Malaysia" — yang sudah pun mengecualikan Sabah, Sarawak
dan Labuan mengikut config/dynoads.php.
Pembekal boleh ditukar dari .env sahaja:
CAPTION_DRIVER=openai # atau claude
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini
Prompt, penghuraian JSON, penapis perkataan larangan dan caption ganti semuanya
duduk dalam CaptionService. Hanya panggilan HTTP yang berbeza antara pembekal
(app/Services/Caption/), jadi menukar pembekal tidak menukar kualiti copy.
Bila pembekal gagal atau kunci belum diisi, app memulangkan caption asas yang
boleh diedit — dan /semak memaparkan amaran yang menyebut kunci mana yang
hilang. Fallback tidak pernah senyap.
Peniaga muat naik gambar, video, atau campuran kedua-duanya — sehingga empat. Satu media = satu campaign. Itu asas split test: yang menang dikekalkan, yang mahal dipause.
| Gambar | Video | |
|---|---|---|
| Diproses | dipotong persegi 1080×1080 (GD) | disimpan seadanya |
| Ke Meta | /adimages → image_hash | /advideos → video_id |
| Creative | object_story_spec.link_data | object_story_spec.video_data |
| Thumbnail | — | medan picture dari Meta |
Video tidak dipotong persegi. Pelayan ini tiada ffmpeg, dan Meta menerima nisbah selain 1:1 untuk video — memaksa persegi bermakna memotong kepala orang dalam video menegak yang peniaga rakam sendiri.
/advideos memulangkan video_id serta-merta, tetapi creative yang dibuat
sebelum Meta selesai memproses akan ditolak. MetaAdsService::waitForVideo()
menunggu sehingga status.video_status menjadi ready (had masa dalam
config/dynoads.php). Tanpa itu, iklan video gagal secara rawak bergantung pada
saiz fail dan beban Meta.
Belum disahkan terhadap dokumentasi rasmi Meta. Bentuk payload video datang dari sumber sekunder kerana
developers.facebook.comtidak boleh dicapai dari persekitaran pembangunan. Peraturan mutlak #3 mengehadkan kerosakannya — semua dibuat PAUSED, jadi bentuk yang salah gagal dengan ralat yang kelihatan semasa Approve, sebelum satu sen dibelanjakan. Uji dengan satu video sebenar sebelum mempercayainya.
Had sebenar ditentukan oleh upload_max_filesize dan post_max_size dalam
php.ini, bukan oleh config app. Video telefon 30 saat selalunya 20–60 MB, jadi
had lalai 8 MB tidak mencukupi. Skrin Buat memberi amaran awal bila had pelayan
terlalu ketat untuk video — naikkan di Forge → server → PHP.
App tidak lagi menjana gambar atau poster. Ia melambatkan setiap permintaan dan
peniaga sudah pun ada gambar sendiri. Jadual poster_jobs dan baris
source_type=poster dikekalkan sebagai sejarah — campaign itu betul-betul
berjalan dan angkanya masih bermakna untuk perbandingan.
/posting menyenaraikan posting bergambar dari Page anda — gambar, petikan teks,
tarikh, jumlah reaksi dan komen. Tick 2–4, pilih kawasan dan bajet, dan setiap
posting jadi satu campaign PAUSED seperti biasa.
Creative dibina dengan object_story_id, bukan object_story_spec. Bezanya
penting kepada peniaga: like, komen dan share terkumpul pada posting asal dia,
jadi bukti sosial tidak berpecah merentas empat iklan asing.
Butang WhatsApp di atas posting sedia ada tidak diterima oleh setiap gabungan
objektif dan format, dan Meta tidak mendokumenkan dengan jelas yang mana. Bila
ia ditolak, app jatuh secara automatik ke laluan kedua: gambar dan teks posting
yang sudah disalin semasa pemilihan digunakan sebagai creative biasa. Iklan tetap
jalan — cuma engagement tinggal pada iklan itu sendiri, bukan pada posting asal.
Setiap kali ini berlaku ia direkod dalam auto_actions sebagai
post_creative_fallback, berserta ayat yang menjelaskan kesannya, supaya peniaga
tahu tanpa perlu bertanya.
Peraturan 13: PagePostService hanya membaca. Ia tiada satu pun method yang
menulis, memadam atau mengubah posting, dan ada ujian yang membaca kod sumber
fail itu untuk menguatkuasakannya.
Amaran yang dipapar pada skrin itu kekal penting: posting yang naik secara organik belum tentu murah kosnya sebagai iklan. Organik diedar kepada peminat sedia ada; iklan diedar kepada orang asing. Sebab tu ia tetap di-split test.
Bila pelanggan tekan butang WhatsApp pada iklan, satu ayat sudah terisi dalam kotak mesej dia. Kalau kita tidak menetapkannya, Meta isi ayat defaultnya sendiri dalam Bahasa Inggeris ("Hello! Can I get more info on this?"). Pelanggan hantar Inggeris, dan mana-mana AI agent di hujung sana akan cermin bahasa itu lalu membalas Inggeris — walaupun iklan dan pelanggan dua-dua orang Malaysia.
Ayat lalai kita: Hi, saya nak tahu lanjut pasal ni.
Tukar melalui DYNOADS_WA_PREFILL dalam .env, atau config/dynoads.php.
AdVariant::isOwnedByApp() menapis setiap run/pause. Campaign yang bukan app
ini buat langsung tiada dalam ad_variants, jadi ia tak boleh disentuh.activate() dan pause() hanya menghantar medan status — tiada budget,
targeting atau creative dihantar semula. Ini diuji dalam
tests/Feature/AbsoluteRulesTest.php.CaptionService pulangkan caption asas yang boleh
diedit. Peniaga tidak tersekat sebab AI down.