@mazees/mark 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +209 -0
  3. package/bin/mark.js +27 -0
  4. package/out/renderer/assets/icon-DHo2CYph.svg +1 -0
  5. package/out/renderer/assets/index-G2fADWO-.js +4768 -0
  6. package/out/renderer/assets/index-f3mVse3c.css +1 -0
  7. package/out/renderer/assets/music-cover-CG4vi3kZ.png +0 -0
  8. package/out/renderer/assets/poppins-devanagari-400-normal-CJDn6rn8.woff2 +0 -0
  9. package/out/renderer/assets/poppins-devanagari-400-normal-CqVvlrh5.woff +0 -0
  10. package/out/renderer/assets/poppins-devanagari-500-normal-BIdkeU1p.woff2 +0 -0
  11. package/out/renderer/assets/poppins-devanagari-500-normal-DMPDjHtT.woff +0 -0
  12. package/out/renderer/assets/poppins-devanagari-600-normal-ClASKHrr.woff +0 -0
  13. package/out/renderer/assets/poppins-devanagari-600-normal-STEjXBNN.woff2 +0 -0
  14. package/out/renderer/assets/poppins-devanagari-700-normal-O-jipLrW.woff2 +0 -0
  15. package/out/renderer/assets/poppins-devanagari-700-normal-fHs-vx92.woff +0 -0
  16. package/out/renderer/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
  17. package/out/renderer/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
  18. package/out/renderer/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
  19. package/out/renderer/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
  20. package/out/renderer/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
  21. package/out/renderer/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
  22. package/out/renderer/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
  23. package/out/renderer/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
  24. package/out/renderer/assets/poppins-latin-ext-400-normal-DaBSavcJ.woff +0 -0
  25. package/out/renderer/assets/poppins-latin-ext-400-normal-by3JarPu.woff2 +0 -0
  26. package/out/renderer/assets/poppins-latin-ext-500-normal-CK-6C4Hw.woff2 +0 -0
  27. package/out/renderer/assets/poppins-latin-ext-500-normal-CgAe2rWW.woff +0 -0
  28. package/out/renderer/assets/poppins-latin-ext-600-normal-CAhIAdZj.woff2 +0 -0
  29. package/out/renderer/assets/poppins-latin-ext-600-normal-Df5ffKXP.woff +0 -0
  30. package/out/renderer/assets/poppins-latin-ext-700-normal-DctTR6Tg.woff +0 -0
  31. package/out/renderer/assets/poppins-latin-ext-700-normal-cby-RkWa.woff2 +0 -0
  32. package/out/renderer/favicon.ico +0 -0
  33. package/out/renderer/icon-256.png +0 -0
  34. package/out/renderer/icon.svg +1 -0
  35. package/out/renderer/index.html +25 -0
  36. package/out/renderer/manifest.json +25 -0
  37. package/out/renderer/robot-simulator.html +1640 -0
  38. package/package.json +106 -0
  39. package/src/cli/index.js +332 -0
  40. package/src/cli/monitor.js +413 -0
  41. package/src/cli/theme.js +347 -0
  42. package/src/launcher/MarkTray.cs +227 -0
  43. package/src/main/browser-agent.js +1132 -0
  44. package/src/main/git-service.js +90 -0
  45. package/src/main/google/google-calendar.js +69 -0
  46. package/src/main/google/google-drive.js +263 -0
  47. package/src/main/google/google-gmail.js +131 -0
  48. package/src/main/google/google-service.js +241 -0
  49. package/src/main/node-tools.js +23 -0
  50. package/src/main/pc-agent-scripts/mouse-locker.ps1 +76 -0
  51. package/src/main/pc-agent-scripts/ocr-region.ps1 +185 -0
  52. package/src/main/pc-agent-scripts/pc-daemon.ps1 +726 -0
  53. package/src/main/pc-agent-scripts/pc-overlay.ps1 +253 -0
  54. package/src/main/pc-agent-scripts/pick-folder.ps1 +33 -0
  55. package/src/main/pc-agent-scripts/read-ui.ps1 +181 -0
  56. package/src/main/pc-agent-scripts/take-screenshot.ps1 +24 -0
  57. package/src/main/pc-agent-scripts/win-action.ps1 +380 -0
  58. package/src/main/plugins/plugin-loader.js +306 -0
  59. package/src/main/skills/skill-manager.js +265 -0
  60. package/src/main/syntax-validator.js +455 -0
  61. package/src/main/task-daemon.js +117 -0
  62. package/src/main/telegram/telegram-service.js +835 -0
  63. package/src/main/tools/browser-tools.js +516 -0
  64. package/src/main/tools/file-tools.js +1126 -0
  65. package/src/main/tools/git-tools.js +79 -0
  66. package/src/main/tools/google-tools.js +566 -0
  67. package/src/main/tools/index.js +36 -0
  68. package/src/main/tools/media-tools.js +42 -0
  69. package/src/main/tools/system-tools.js +295 -0
  70. package/src/main/tools/task-tools.js +73 -0
  71. package/src/main/tools/telegram-tools.js +101 -0
  72. package/src/renderer/index.html +24 -0
  73. package/src/renderer/public/favicon.ico +0 -0
  74. package/src/renderer/public/icon-256.png +0 -0
  75. package/src/renderer/public/icon.svg +1 -0
  76. package/src/renderer/public/manifest.json +25 -0
  77. package/src/renderer/public/robot-simulator.html +1640 -0
  78. package/src/renderer/src/App.jsx +304 -0
  79. package/src/renderer/src/api/ai/awareness.js +294 -0
  80. package/src/renderer/src/api/ai/chatSummarizer.js +79 -0
  81. package/src/renderer/src/api/ai/contextCompactor.js +129 -0
  82. package/src/renderer/src/api/ai/contextManager.js +1130 -0
  83. package/src/renderer/src/api/ai/core.js +167 -0
  84. package/src/renderer/src/api/ai/index.js +4 -0
  85. package/src/renderer/src/api/ai/memoryGroomer.js +101 -0
  86. package/src/renderer/src/api/ai/persona.js +115 -0
  87. package/src/renderer/src/api/ai/planning.js +317 -0
  88. package/src/renderer/src/api/ai/relationship.js +177 -0
  89. package/src/renderer/src/api/ai/skillSynthesizer.js +168 -0
  90. package/src/renderer/src/api/ai/tools.js +167 -0
  91. package/src/renderer/src/api/ai/utils.js +359 -0
  92. package/src/renderer/src/api/db.js +1013 -0
  93. package/src/renderer/src/api/oramaStore.js +592 -0
  94. package/src/renderer/src/api/ragPipeline.js +87 -0
  95. package/src/renderer/src/api/subagent/subagentExecutor.js +780 -0
  96. package/src/renderer/src/api/subagent/subagentPrompt.js +44 -0
  97. package/src/renderer/src/api/subagent/subagentStore.js +173 -0
  98. package/src/renderer/src/api/taskExecutor.js +18 -0
  99. package/src/renderer/src/api/taskStore.js +315 -0
  100. package/src/renderer/src/api/tools/core-tools.js +707 -0
  101. package/src/renderer/src/api/tools/index.js +151 -0
  102. package/src/renderer/src/api/turnPairMigrator.js +200 -0
  103. package/src/renderer/src/api/vectorMemory.js +136 -0
  104. package/src/renderer/src/api/wakeWord.js +101 -0
  105. package/src/renderer/src/api/web-bridge.js +885 -0
  106. package/src/renderer/src/api/webSpeech.js +178 -0
  107. package/src/renderer/src/api/workspaceRag.js +76 -0
  108. package/src/renderer/src/assets/electron.svg +10 -0
  109. package/src/renderer/src/assets/icon.svg +1 -0
  110. package/src/renderer/src/assets/main.css +589 -0
  111. package/src/renderer/src/assets/music-cover.png +0 -0
  112. package/src/renderer/src/assets/wavy-lines.svg +25 -0
  113. package/src/renderer/src/components/Chat/ApprovalBubble.jsx +127 -0
  114. package/src/renderer/src/components/Chat/CodeBlock.jsx +83 -0
  115. package/src/renderer/src/components/Chat/DurableTaskBubble.jsx +455 -0
  116. package/src/renderer/src/components/Chat/FileDiffModal.jsx +328 -0
  117. package/src/renderer/src/components/Chat/GeminiWidgets.jsx +82 -0
  118. package/src/renderer/src/components/Chat/MemoryFooterBubble.jsx +34 -0
  119. package/src/renderer/src/components/Chat/MessageBubble.jsx +459 -0
  120. package/src/renderer/src/components/Chat/PluginExecutionBubble.jsx +41 -0
  121. package/src/renderer/src/components/Chat/ThinkingBubble.jsx +316 -0
  122. package/src/renderer/src/components/Chat/YoutubeSearchBubble.jsx +43 -0
  123. package/src/renderer/src/components/Chat/YoutubeSummaryBubble.jsx +40 -0
  124. package/src/renderer/src/components/Chat/index.js +11 -0
  125. package/src/renderer/src/components/ChatList.jsx +434 -0
  126. package/src/renderer/src/components/GlobalCameraManager.jsx +67 -0
  127. package/src/renderer/src/components/Versions.jsx +15 -0
  128. package/src/renderer/src/components/YoutubeMusicPlayer.jsx +375 -0
  129. package/src/renderer/src/components/camera/CameraPreview.jsx +236 -0
  130. package/src/renderer/src/components/config/AiEngineSection.jsx +363 -0
  131. package/src/renderer/src/components/config/CameraSection.jsx +100 -0
  132. package/src/renderer/src/components/config/PermissionsSection.jsx +130 -0
  133. package/src/renderer/src/components/config/ShortcutSection.jsx +102 -0
  134. package/src/renderer/src/components/config/VoiceSection.jsx +110 -0
  135. package/src/renderer/src/components/config/index.js +5 -0
  136. package/src/renderer/src/components/core/Avatar.jsx +2197 -0
  137. package/src/renderer/src/components/core/ConfirmModal.jsx +80 -0
  138. package/src/renderer/src/components/core/DraggableHoloCard.jsx +125 -0
  139. package/src/renderer/src/components/core/FloatingMenu.jsx +272 -0
  140. package/src/renderer/src/components/core/HoloCard.jsx +64 -0
  141. package/src/renderer/src/components/core/InputBar.jsx +1346 -0
  142. package/src/renderer/src/components/core/ProcessPanel.jsx +216 -0
  143. package/src/renderer/src/components/core/ResponseArea.jsx +149 -0
  144. package/src/renderer/src/components/core/StatusIndicator.jsx +59 -0
  145. package/src/renderer/src/components/core/ThoughtNeuralFlow.jsx +168 -0
  146. package/src/renderer/src/components/core/ToolClustersDeck.jsx +210 -0
  147. package/src/renderer/src/components/core/native-skills.js +43 -0
  148. package/src/renderer/src/components/neural-core/EmotionalCortexLobe.jsx +359 -0
  149. package/src/renderer/src/components/neural-core/NodeDissectionModal.jsx +57 -0
  150. package/src/renderer/src/components/neural-core/ProceduralMatrixLobe.jsx +193 -0
  151. package/src/renderer/src/components/neural-core/ProceduralSkillModal.jsx +53 -0
  152. package/src/renderer/src/components/neural-core/ResetAiModal.jsx +198 -0
  153. package/src/renderer/src/components/neural-core/SynapticMemoryLobe.jsx +204 -0
  154. package/src/renderer/src/components/neural-core/traitMeta.js +102 -0
  155. package/src/renderer/src/components/subagent/AgentChatFeed.jsx +603 -0
  156. package/src/renderer/src/components/subagent/AgentInspector.jsx +224 -0
  157. package/src/renderer/src/components/subagent/AgentSidebar.jsx +216 -0
  158. package/src/renderer/src/components/subagent/SubagentIntercom.jsx +572 -0
  159. package/src/renderer/src/components/subagent/SubagentTopologyMap.jsx +423 -0
  160. package/src/renderer/src/contexts/ApprovalContext.jsx +425 -0
  161. package/src/renderer/src/contexts/ChatContext.jsx +61 -0
  162. package/src/renderer/src/contexts/YoutubeMusicContext.jsx +333 -0
  163. package/src/renderer/src/data/faqData.js +202 -0
  164. package/src/renderer/src/hooks/agent/executeAgentTool.js +895 -0
  165. package/src/renderer/src/hooks/agent/index.js +4 -0
  166. package/src/renderer/src/hooks/agent/useMarkMusic.js +75 -0
  167. package/src/renderer/src/hooks/agent/useMarkPlan.js +2739 -0
  168. package/src/renderer/src/hooks/agent/useMarkState.js +173 -0
  169. package/src/renderer/src/hooks/agent/useMarkYoutube.js +82 -0
  170. package/src/renderer/src/hooks/agent/useRelationalGrowth.js +201 -0
  171. package/src/renderer/src/hooks/telegram/useTelegramBot.js +63 -0
  172. package/src/renderer/src/hooks/useAwareness.js +289 -0
  173. package/src/renderer/src/hooks/useChatArchiver.js +52 -0
  174. package/src/renderer/src/hooks/useConfirm.jsx +68 -0
  175. package/src/renderer/src/hooks/useMarkAgent.js +454 -0
  176. package/src/renderer/src/hooks/useMemoryGroomer.js +152 -0
  177. package/src/renderer/src/hooks/useVAD.js +511 -0
  178. package/src/renderer/src/hooks/useWebSpeechWakeWord.js +122 -0
  179. package/src/renderer/src/main.jsx +12 -0
  180. package/src/renderer/src/pages/ChatStudio.jsx +922 -0
  181. package/src/renderer/src/pages/Configuration.jsx +360 -0
  182. package/src/renderer/src/pages/GoogleWorkspace.jsx +293 -0
  183. package/src/renderer/src/pages/Guidebook.jsx +917 -0
  184. package/src/renderer/src/pages/Knowledge.jsx +241 -0
  185. package/src/renderer/src/pages/MarkHome.jsx +491 -0
  186. package/src/renderer/src/pages/NeuralCore.jsx +786 -0
  187. package/src/renderer/src/pages/Plugins.jsx +630 -0
  188. package/src/renderer/src/pages/SkillEditor.jsx +380 -0
  189. package/src/renderer/src/pages/Skills.jsx +219 -0
  190. package/src/renderer/src/pages/Subagents.jsx +342 -0
  191. package/src/renderer/src/pages/TelegramBot.jsx +343 -0
  192. package/src/renderer/src/utils/chatContentParser.js +203 -0
  193. package/src/renderer/src/utils/toolClusters.js +201 -0
  194. package/src/server/bin/sha3_wasm_bg.wasm +0 -0
  195. package/src/server/config-manager.js +57 -0
  196. package/src/server/index.js +195 -0
  197. package/src/server/launcher.js +87 -0
  198. package/src/server/memory/db-store.js +758 -0
  199. package/src/server/memory/orama-store.js +177 -0
  200. package/src/server/memory/vector-engine.js +109 -0
  201. package/src/server/routes/ai.routes.js +280 -0
  202. package/src/server/routes/awareness.routes.js +62 -0
  203. package/src/server/routes/chat.routes.js +61 -0
  204. package/src/server/routes/config.routes.js +41 -0
  205. package/src/server/routes/index.js +35 -0
  206. package/src/server/routes/integrations.routes.js +116 -0
  207. package/src/server/routes/memory.routes.js +256 -0
  208. package/src/server/routes/plugins.routes.js +72 -0
  209. package/src/server/routes/skills.routes.js +139 -0
  210. package/src/server/routes/subagents.routes.js +70 -0
  211. package/src/server/routes/tasks.routes.js +175 -0
  212. package/src/server/routes/workspace.routes.js +127 -0
  213. package/src/server/services/ai/ai-utils.js +161 -0
  214. package/src/server/services/ai/openai-provider.js +757 -0
  215. package/src/server/services/ai/web-provider.js +729 -0
  216. package/src/server/services/ai-bridge.js +46 -0
  217. package/src/server/services/deepseek-web.js +956 -0
  218. package/src/server/services/gemini-web.js +170 -0
  219. package/src/server/services/notification-service.js +91 -0
  220. package/src/server/services/updater.js +125 -0
  221. package/src/server/tools/awareness-tracker.js +292 -0
  222. package/src/server/tools/group-tools.js +1164 -0
  223. package/src/server/tools/media-tools.js +244 -0
  224. package/src/server/tools/pc-agent.js +327 -0
  225. package/src/server/tools/screen-service.js +51 -0
  226. package/src/server/ws-hub.js +168 -0
  227. package/src/shared/parsers/mark-tag-parser.js +275 -0
@@ -0,0 +1,333 @@
1
+ import { useState, useContext, createContext, useRef, useCallback, useEffect } from 'react'
2
+
3
+ const YoutubeMusicContext = createContext()
4
+
5
+ /**
6
+ * Load YouTube IFrame Player API Script dynamically
7
+ */
8
+ let ytIframeScriptLoading = false
9
+ let ytIframeReadyCallbacks = []
10
+
11
+ function loadYouTubeIframeApi(callback) {
12
+ if (window.YT && window.YT.Player) {
13
+ callback()
14
+ return
15
+ }
16
+
17
+ ytIframeReadyCallbacks.push(callback)
18
+
19
+ if (!ytIframeScriptLoading) {
20
+ ytIframeScriptLoading = true
21
+ const tag = document.createElement('script')
22
+ tag.src = 'https://www.youtube.com/iframe_api'
23
+ const firstScriptTag = document.getElementsByTagName('script')[0]
24
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
25
+
26
+ window.onYouTubeIframeAPIReady = () => {
27
+ ytIframeReadyCallbacks.forEach((cb) => cb())
28
+ ytIframeReadyCallbacks = []
29
+ }
30
+ }
31
+ }
32
+
33
+ export const YoutubeMusicProvider = ({ children }) => {
34
+ const [currentTrack, setCurrentTrack] = useState({
35
+ id: '',
36
+ videoId: '',
37
+ title: 'Tidak Ada Lagu',
38
+ artist: 'Pilih lagu untuk memutar',
39
+ thumbnail: '',
40
+ duration: 0
41
+ })
42
+
43
+ const [queue, setQueue] = useState([])
44
+ const [currentIndex, setCurrentIndex] = useState(-1)
45
+ const [isPlayerOpen, setIsPlayerOpen] = useState(false)
46
+ const [isPlaying, setIsPlaying] = useState(false)
47
+ const [isMuted, setIsMuted] = useState(false)
48
+ const [volume, setVolume] = useState(80)
49
+ const [currentTime, setCurrentTime] = useState(0)
50
+ const [duration, setDuration] = useState(0)
51
+ const [viewMode, setViewMode] = useState('thumbnail') // 'thumbnail' | 'video'
52
+ const [isReady, setIsReady] = useState(false)
53
+
54
+ const playerRef = useRef(null)
55
+ const containerIdRef = useRef('mark-yt-iframe-player')
56
+ const timeUpdateTimerRef = useRef(null)
57
+
58
+ // Inisialisasi YouTube Player
59
+ useEffect(() => {
60
+ loadYouTubeIframeApi(() => {
61
+ if (playerRef.current) return
62
+
63
+ try {
64
+ playerRef.current = new window.YT.Player(containerIdRef.current, {
65
+ height: '100%',
66
+ width: '100%',
67
+ host: 'https://www.youtube-nocookie.com',
68
+ playerVars: {
69
+ autoplay: 1,
70
+ controls: 1,
71
+ rel: 0,
72
+ modestbranding: 1,
73
+ playsinline: 1,
74
+ iv_load_policy: 3,
75
+ disablekb: 0,
76
+ enablejsapi: 1,
77
+ origin: window.location.origin
78
+ },
79
+ events: {
80
+ onReady: (event) => {
81
+ setIsReady(true)
82
+ event.target.setVolume(80)
83
+ },
84
+ onStateChange: (event) => {
85
+ // YT.PlayerState: -1 (unstarted), 0 (ended), 1 (playing), 2 (paused), 3 (buffering), 5 (video cued)
86
+ if (event.data === window.YT.PlayerState.PLAYING) {
87
+ setIsPlaying(true)
88
+ const dur = playerRef.current?.getDuration() || 0
89
+ if (dur > 0) setDuration(dur)
90
+ } else if (event.data === window.YT.PlayerState.PAUSED) {
91
+ setIsPlaying(false)
92
+ } else if (event.data === window.YT.PlayerState.ENDED) {
93
+ setIsPlaying(false)
94
+ // Otomatis next track jika ada di queue
95
+ nextTrack()
96
+ }
97
+ },
98
+ onError: (e) => {
99
+ console.warn('[YT Player] Error:', e.data)
100
+ // Error 150/101 sering terjadi jika embedding ditolak, coba lagu berikutnya
101
+ if (e.data === 150 || e.data === 101) {
102
+ nextTrack()
103
+ }
104
+ }
105
+ }
106
+ })
107
+ } catch (err) {
108
+ console.error('[YT Player] Failed to create player instance:', err)
109
+ }
110
+ })
111
+
112
+ return () => {
113
+ if (timeUpdateTimerRef.current) clearInterval(timeUpdateTimerRef.current)
114
+ }
115
+ }, [])
116
+
117
+ // Timer pemantau progress durasi
118
+ useEffect(() => {
119
+ if (isPlaying) {
120
+ timeUpdateTimerRef.current = setInterval(() => {
121
+ if (playerRef.current && typeof playerRef.current.getCurrentTime === 'function') {
122
+ const curr = playerRef.current.getCurrentTime() || 0
123
+ const dur = playerRef.current.getDuration() || 0
124
+ setCurrentTime(curr)
125
+ if (dur > 0 && dur !== duration) setDuration(dur)
126
+ }
127
+ }, 500)
128
+ } else {
129
+ if (timeUpdateTimerRef.current) clearInterval(timeUpdateTimerRef.current)
130
+ }
131
+ return () => {
132
+ if (timeUpdateTimerRef.current) clearInterval(timeUpdateTimerRef.current)
133
+ }
134
+ }, [isPlaying, duration])
135
+
136
+ // Memutar Track tertentu
137
+ const playTrack = useCallback((track, newQueue = null) => {
138
+ if (!track) return
139
+
140
+ const videoId = track.videoId || track.id || (track.url ? track.url.split('v=')[1]?.split('&')[0] : '')
141
+ if (!videoId) return
142
+
143
+ const formattedTrack = {
144
+ id: videoId,
145
+ videoId: videoId,
146
+ title: track.title || 'YouTube Track',
147
+ artist: track.artist || track.author || 'YouTube Artist',
148
+ thumbnail: track.thumbnail || `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
149
+ duration: track.seconds || 0
150
+ }
151
+
152
+ setCurrentTrack(formattedTrack)
153
+ setIsPlayerOpen(true)
154
+ setCurrentTime(0)
155
+
156
+ if (newQueue && Array.isArray(newQueue) && newQueue.length > 0) {
157
+ setQueue(newQueue)
158
+ const foundIndex = newQueue.findIndex(
159
+ (item) => (item.videoId || item.id) === videoId
160
+ )
161
+ setCurrentIndex(foundIndex >= 0 ? foundIndex : 0)
162
+ }
163
+
164
+ if (playerRef.current && typeof playerRef.current.loadVideoById === 'function') {
165
+ playerRef.current.loadVideoById({
166
+ videoId: videoId,
167
+ startSeconds: 0
168
+ })
169
+ playerRef.current.playVideo()
170
+ setIsPlaying(true)
171
+ }
172
+ }, [])
173
+
174
+ // Kompatibilitas untuk pemanggilan via URL
175
+ const playUrl = useCallback(
176
+ (url, initialTrack = null) => {
177
+ let videoId = ''
178
+ if (url.includes('v=')) {
179
+ videoId = url.split('v=')[1]?.split('&')[0]
180
+ } else if (url.includes('youtu.be/')) {
181
+ videoId = url.split('youtu.be/')[1]?.split('?')[0]
182
+ }
183
+
184
+ if (videoId) {
185
+ playTrack(initialTrack || { videoId, title: 'YouTube Track', artist: 'YouTube' })
186
+ }
187
+ },
188
+ [playTrack]
189
+ )
190
+
191
+ const playPause = useCallback(() => {
192
+ if (!playerRef.current) return
193
+ try {
194
+ if (isPlaying) {
195
+ playerRef.current.pauseVideo()
196
+ setIsPlaying(false)
197
+ } else {
198
+ playerRef.current.playVideo()
199
+ setIsPlaying(true)
200
+ }
201
+ } catch (_) {}
202
+ }, [isPlaying])
203
+
204
+ const nextTrack = useCallback(() => {
205
+ setQueue((currQueue) => {
206
+ if (!currQueue || currQueue.length === 0) return currQueue
207
+ setCurrentIndex((currIndex) => {
208
+ const nextIdx = currIndex + 1 < currQueue.length ? currIndex + 1 : 0
209
+ const nextItem = currQueue[nextIdx]
210
+ if (nextItem) {
211
+ const videoId = nextItem.videoId || nextItem.id
212
+ if (videoId) {
213
+ setCurrentTrack({
214
+ id: videoId,
215
+ videoId: videoId,
216
+ title: nextItem.title || 'YouTube Track',
217
+ artist: nextItem.artist || nextItem.author || 'YouTube Artist',
218
+ thumbnail: nextItem.thumbnail || `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
219
+ duration: nextItem.seconds || 0
220
+ })
221
+ if (playerRef.current && typeof playerRef.current.loadVideoById === 'function') {
222
+ playerRef.current.loadVideoById({ videoId, startSeconds: 0 })
223
+ playerRef.current.playVideo()
224
+ setIsPlaying(true)
225
+ }
226
+ }
227
+ }
228
+ return nextIdx
229
+ })
230
+ return currQueue
231
+ })
232
+ }, [])
233
+
234
+ const prevTrack = useCallback(() => {
235
+ setQueue((currQueue) => {
236
+ if (!currQueue || currQueue.length === 0) return currQueue
237
+ setCurrentIndex((currIndex) => {
238
+ const prevIdx = currIndex - 1 >= 0 ? currIndex - 1 : currQueue.length - 1
239
+ const prevItem = currQueue[prevIdx]
240
+ if (prevItem) {
241
+ const videoId = prevItem.videoId || prevItem.id
242
+ if (videoId) {
243
+ setCurrentTrack({
244
+ id: videoId,
245
+ videoId: videoId,
246
+ title: prevItem.title || 'YouTube Track',
247
+ artist: prevItem.artist || prevItem.author || 'YouTube Artist',
248
+ thumbnail: prevItem.thumbnail || `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
249
+ duration: prevItem.seconds || 0
250
+ })
251
+ if (playerRef.current && typeof playerRef.current.loadVideoById === 'function') {
252
+ playerRef.current.loadVideoById({ videoId, startSeconds: 0 })
253
+ playerRef.current.playVideo()
254
+ setIsPlaying(true)
255
+ }
256
+ }
257
+ }
258
+ return prevIdx
259
+ })
260
+ return currQueue
261
+ })
262
+ }, [])
263
+
264
+ const seekTo = useCallback((seconds) => {
265
+ if (playerRef.current && typeof playerRef.current.seekTo === 'function') {
266
+ playerRef.current.seekTo(seconds, true)
267
+ setCurrentTime(seconds)
268
+ }
269
+ }, [])
270
+
271
+ const handleVolumeChange = useCallback((newVolume) => {
272
+ setVolume(newVolume)
273
+ if (playerRef.current && typeof playerRef.current.setVolume === 'function') {
274
+ playerRef.current.setVolume(newVolume)
275
+ if (newVolume > 0 && isMuted) {
276
+ playerRef.current.unMute()
277
+ setIsMuted(false)
278
+ }
279
+ }
280
+ }, [isMuted])
281
+
282
+ const toggleMute = useCallback(() => {
283
+ if (!playerRef.current) return
284
+ if (isMuted) {
285
+ playerRef.current.unMute()
286
+ setIsMuted(false)
287
+ } else {
288
+ playerRef.current.mute()
289
+ setIsMuted(true)
290
+ }
291
+ }, [isMuted])
292
+
293
+ const togglePlayer = useCallback(() => {
294
+ setIsPlayerOpen((prev) => !prev)
295
+ }, [])
296
+
297
+ const toggleViewMode = useCallback(() => {
298
+ setViewMode((prev) => (prev === 'thumbnail' ? 'video' : 'thumbnail'))
299
+ }, [])
300
+
301
+ const value = {
302
+ currentTrack,
303
+ queue,
304
+ currentIndex,
305
+ isPlaying,
306
+ isMuted,
307
+ volume,
308
+ currentTime,
309
+ duration,
310
+ viewMode,
311
+ isPlayerOpen,
312
+ isReady,
313
+ containerId: containerIdRef.current,
314
+ setIsPlayerOpen,
315
+ togglePlayer,
316
+ setViewMode,
317
+ toggleViewMode,
318
+ playTrack,
319
+ playUrl,
320
+ playPause,
321
+ nextTrack,
322
+ prevTrack,
323
+ seekTo,
324
+ setVolume: handleVolumeChange,
325
+ toggleMute
326
+ }
327
+
328
+ return <YoutubeMusicContext.Provider value={value}>{children}</YoutubeMusicContext.Provider>
329
+ }
330
+
331
+ export const useYoutubeMusic = () => {
332
+ return useContext(YoutubeMusicContext)
333
+ }
@@ -0,0 +1,202 @@
1
+ export const faqs = [
2
+ {
3
+ q: "Apakah Mark membutuhkan koneksi internet?",
4
+ a: "Tidak selalu! Jika Anda mengatur AI Provider ke LM Studio (Offline), sebagian besar fungsi Mark bisa berjalan tanpa internet secara lokal. Namun, fitur Voice (Speech-to-Text), Web Search (mencari di Google), dan perangkum YouTube tetap membutuhkan koneksi internet."
5
+ },
6
+ {
7
+ q: "Bagaimana cara kerja sistem memori Mark?",
8
+ a: "Mark tidak mengingat percakapan sekadar dari kata kunci yang sama persis. Mark mengubah informasi penting menjadi 'konsep makna'. Jadi saat Anda bertanya, Mark akan langsung mencari ingatan yang paling nyambung maknanya dengan obrolan saat itu."
9
+ },
10
+ {
11
+ q: "Mark tiba-tiba mengajak bicara saat saya sedang diam. Kenapa?",
12
+ a: "Itu adalah hasil kerja Awareness Engine. Mark secara berkala memantau aktivitas Anda di laptop (misal: Anda sedang buka Youtube, atau memutar musik). Jika Anda ingin privasi penuh dan ingin Mark diam saja, matikan toggle Awareness Engine di halaman Pengaturan."
13
+ },
14
+ {
15
+ q: "Apa arti perubahan warna bola cahaya (Orb) Mark di layar?",
16
+ a: "Warna tersebut menunjukkan 1 dari 9 Emosi yang sedang dirasakan Mark. Misalnya kuning keemasan untuk senang, merah untuk kesal, atau kelabu untuk bosan. Emosi ini akan berubah secara alami tergantung cara Anda memperlakukannya tiap hari."
17
+ },
18
+ {
19
+ q: "Bagaimana kalau Mark tiba-tiba mengotak-atik sistem penting di laptop saya?",
20
+ a: "Tidak akan terjadi tanpa izin Anda! Alat-alat berisiko (seperti menghapus file atau menjalankan terminal PC) WAJIB menunggu persetujuan (Acc) dari Anda melalui klik tombol sebelum dijalankan. Jika Anda menolak, Mark tidak akan memaksa."
21
+ },
22
+ {
23
+ q: "Mark macet dan terus menerus error saat mencoba sesuatu. Apa yang harus saya lakukan?",
24
+ a: "Jika Mark terjebak kebingungan memecahkan sebuah error panjang, Anda bisa langsung menghentikan proses berpikirnya dengan mengklik tombol STOP (Kotak Merah) di dekat area tempat Anda mengetik chat."
25
+ },
26
+ {
27
+ q: "Bagaimana cara saya ngobrol pakai suara sama Mark?",
28
+ a: "Cukup pakai mikrofon Anda! Mark otomatis bisa mendeteksi saat Anda mulai berbicara dan kapan Anda selesai ngomong, lalu dia akan langsung membalas pakai suara."
29
+ },
30
+ {
31
+ q: "Apakah Mark bisa menyetel lagu?",
32
+ a: "Ya! Anda bisa bilang, 'Putarkan lagu Nadin Amizah'. Mark otomatis mencari dan memutar lagunya secara tersembunyi di latar belakang tanpa Anda harus repot buka aplikasi musik visual."
33
+ },
34
+ {
35
+ q: "Mark bisa dihubungi lewat Telegram?",
36
+ a: "Sangat bisa! Mark punya fitur bot Telegram khusus. Cukup masukkan API Token dari @BotFather dan Telegram User ID kamu di menu Pengaturan. Mark bisa mendownload lagu YouTube lalu dikirim ke Telegram Anda sebagai MP3 atau mengirimkan screenshot PC."
37
+ },
38
+ {
39
+ q: "Apakah Mark bisa membantu saya ngoding dan ngecek file kerjaan di laptop?",
40
+ a: "Tentu. Mark punya fitur khusus untuk menjelajahi dan membaca ratusan file kerjaan dalam folder Anda secara mandiri, sangat cocok dijadikan asisten ngoding pribadi."
41
+ },
42
+ {
43
+ q: "Bagaimana cara mengubah otak pintar (AI Provider) Mark?",
44
+ a: "Buka menu Configuration. Di sana Anda bisa memilih antara Gemini (Gratis tanpa API Key), LM Studio (Offline lokal), atau Custom API (OpenAI-Compatible Endpoint). Pilih model dari dropdown yang tersedia."
45
+ },
46
+ {
47
+ q: "Kenapa balasan Mark kadang sangat lambat?",
48
+ a: "Jika Anda pakai mode Offline (LM Studio), kecepatan mikir Mark 100% bergantung pada kekuatan prosesor (CPU) dan VGA laptop Anda. Semakin besar memori otak (model AI) yang dipakai, semakin berat kerja laptopnya."
49
+ },
50
+ {
51
+ q: "Untuk apa Groq API Key di pengaturan?",
52
+ a: "Groq API Key digunakan khusus untuk fitur Speech-to-Text (Voice STT via Whisper), sehingga Mark dapat mendengarkan ucapan suara Anda dari mikrofon secara cepat dan akurat."
53
+ },
54
+ {
55
+ q: "Bisakah saya menghapus ingatan Mark tentang saya?",
56
+ a: "Bisa. Ingatan disimpan aman di database lokal laptop Anda. Anda bisa menyuruh Mark 'Lupakan tentang hal itu', atau Anda bisa menghapusnya manual lewat menu kelola memori."
57
+ },
58
+ {
59
+ q: "Apakah riwayat curhat saya ke Mark dikirim ke internet?",
60
+ a: "TIDAK SAMA SEKALI. Seluruh riwayat obrolan, ingatan, dan pengaturan tersimpan murni secara rahasia di dalam hard disk Anda. Tidak ada sekecil apapun data yang dicolong ke server pusat aplikasi."
61
+ },
62
+ {
63
+ q: "Apakah Mark bisa melacak lokasi fisik saya di dunia nyata?",
64
+ a: "Tidak bisa melacak koordinat GPS. Namun jika Anda menyuruh Mark memakai kamera laptop (camera-look) atau melihat layar (analyze-screen), Mark dapat melihat sebatas apa yang terlihat di monitor atau ruangan Anda."
65
+ },
66
+ {
67
+ q: "Bagaimana cara stop musik latar yang tadi dinyalakan Mark?",
68
+ a: "Cukup ketik 'Mark, stop musiknya' atau 'pause musik'. Mark otomatis akan langsung menghentikan lagu tersebut di latar belakang."
69
+ },
70
+ {
71
+ q: "Apakah video YouTube durasi panjang bisa dirangkum semua sama Mark?",
72
+ a: "Bisa, asalkan video tersebut punya teks *subtitle/transkrip* bawaan. Jika durasinya berjam-jam, Mark akan memotong-motongnya perlahan untuk dibaca dan dirangkum secara mandiri."
73
+ },
74
+ {
75
+ q: "Siapa saja yang bisa mengakses bot Telegram Mark saya?",
76
+ a: "Hanya user yang ID Telegram-nya terdaftar di menu Pengaturan (Telegram Admin User IDs). Orang lain yang mencoba chat ke bot akan ditolak otomatis."
77
+ },
78
+ {
79
+ q: "Bagaimana cara mendapatkan Telegram Bot Token?",
80
+ a: "Buka aplikasi Telegram, cari akun resmi @BotFather, ketik /newbot, ikuti petunjuk pembuatan nama bot, lalu copy API Token yang diberikan ke halaman Configuration di Mark."
81
+ },
82
+ {
83
+ q: "Kok Mark kadang bisa tiba-tiba nanya 'Lagi sibuk ngerjain dokumen ya?'",
84
+ a: "Itu berkat Awareness Engine! Fitur ini diam-diam ngecek judul jendela aplikasi apa yang lagi kebuka paling depan di layar laptop Anda (misal lagi buka MS Word atau Game), jadi Mark ngerasa lebih peka."
85
+ },
86
+ {
87
+ q: "Apa maksudnya kalau warna Mark berubah jadi abu-abu pucat?",
88
+ a: "Abu-abu itu emosi kebosanan. Ini wajar kalau Anda udah lama banget nyuekin dia atau interaksi Anda jawabnya cuma 'oke', 'sip', tanpa ada obrolan bermakna."
89
+ },
90
+ {
91
+ q: "Apakah Mark jago bikin aplikasi utuh dari nol?",
92
+ a: "Bisa banget! Mark bisa ngetik kode sendiri, bikin folder sendiri, dan ngetes aplikasinya lewat terminal laptop Anda. Tapi, Anda tetap harus mandorin ngasih instruksi yang jelas tahap demi tahap."
93
+ },
94
+ {
95
+ q: "Kenapa pas disuruh, Mark kadang cuma diam 'Berpikir' agak lama?",
96
+ a: "Itu namanya Agentic Planning. Daripada langsung asal jawab, Mark lagi asik nyusun langkah-langkah di kepalanya, makai beberapa alat, ngecek hasilnya bener apa salah, baru ngasih tau Anda kesimpulan akhirnya."
97
+ },
98
+ {
99
+ q: "Bisakah Mark disuruh buka Instagram lalu balesin DM mantan saya?",
100
+ a: "Prakteknya susah karena website modern punya sistem keamanan tebal (seperti minta konfirmasi login/captcha). Biasanya Mark bakal nyerah dan nyuruh Anda bantu login manual dulu di layar pop-up nya."
101
+ },
102
+ {
103
+ q: "Apakah Mark bisa mendownload file dari internet ke laptop saya?",
104
+ a: "Bisa, asalkan Anda ngasih izin (klik OK) waktu notifikasi keamanan muncul untuk mengunduh skrip dari internet."
105
+ },
106
+ {
107
+ q: "Bisa panggil Mark saat saya lagi seru-serunya main game full-screen?",
108
+ a: "Bisa! Meskipun wujud Mark mungkin ketutupan game, kalau Anda pakai fitur mikrofon (Voice Chat), teriak aja manggil namanya dan Mark bakal ngebales pakai suara."
109
+ },
110
+ {
111
+ q: "Bikin baterai laptop boros dan cepat panas nggak sih?",
112
+ a: "Kalau Anda atur otak AI-nya pakai mode Offline (LM Studio) pas nggak di-cas, JELAS IYA. Mesin AI lokal itu kerja rodi. Tapi kalau pakai sambungan online (Groq), dampaknya enteng banget buat laptop."
113
+ },
114
+ {
115
+ q: "Bagaimana caranya bikin fitur atau kemampuan baru buat Mark?",
116
+ a: "Ke menu Plugins > klik Buat Plugin Baru. Isi nama dan apa gunanya. Lalu ketik instruksi script sederhananya. Habis di-save, Mark otomatis jadi makin pinter dan ngerti pakai kemampuan baru itu."
117
+ },
118
+ {
119
+ q: "Apakah fitur Plugin tambahan bisa ambil bahan dari luar?",
120
+ a: "Bisa! Kalau butuh tambahan paket dari internet (NPM), cukup ketik namanya di kolom yang disediain. Nanti Mark otomatis download perlengkapannya sendiri sebelum pakai fiturnya."
121
+ },
122
+ {
123
+ q: "Berapa banyak ekstensi (Plugin) yang bisa saya tambahkan ke Mark?",
124
+ a: "Anda bisa membuat sebanyak apa pun yang Anda butuhkan! Mark cukup cerdas untuk menyortir dan hanya menggunakan plugin yang paling nyambung dengan perintah Anda saat itu. Jadi meski Anda punya puluhan plugin, pikiran Mark tidak akan terbebani apalagi bikin laptop nge-lag."
125
+ },
126
+ {
127
+ q: "Mark kadang gagal klik tombol di dalam website, kenapa ya?",
128
+ a: "Beberapa website dibikin dengan desain animasi rumit atau elemen yang tersembunyi. Kalau Mark bingung nggak nemu tombolnya, dia bakal baca ulang layarnya atau ujung-ujungnya minta tolong Anda."
129
+ },
130
+ {
131
+ q: "Apakah Mark ngintipin isi email pribadi saya diam-diam?",
132
+ a: "Jelas TIDAK. Mark cuma tahu hal yang Anda kasih tahu, file kerjaan yang Anda perbolehkan dia baca, atau sebatas apa yang lagi tampil di layar saat itu. Mark nggak punya sihir buat ngebobol password email."
133
+ },
134
+ {
135
+ q: "Apakah aplikasi Mark ini gratis selamanya?",
136
+ a: "Aplikasi Mark 100% gratis buat pribadi. Tapi kalau Anda milih pakai otak online pihak ketiga (seperti API dari Groq), nah itu ngikutin aturan dari pihak sananya, apakah masih gratis atau ada limit kuotanya."
137
+ },
138
+ {
139
+ q: "Bisa ganti suara robot ngomongnya Mark?",
140
+ a: "Suara bawaannya sudah cukup natural (dialek Indonesia). Buat sekarang fitur gonta-ganti suara belum nongol di tombol sederhana, tapi bisa diakalin lewat bongkar file pengaturannya."
141
+ },
142
+ {
143
+ q: "Kenapa kalau Mark ngomong kadang suaranya patah-patah putus?",
144
+ a: "Itu efek internet lagi ngos-ngosan nyedot data suaranya, atau bisa juga karena laptop Anda lagi berat banget mikir proses AI sehingga audio-nya ikutan macet-macet."
145
+ },
146
+ {
147
+ q: "Bisakah saya mengubah sifat asli Mark jadi manja atau agresif?",
148
+ a: "Kerangka sifat aslinya udah dipatenkan biar Mark tetep bisa kerja bener. Tapi sapaan dan nada bicaranya itu berevolusi ngikutin Anda. Kalau tiap hari Anda ramah banget, lama-lama gaya bicara dia ikutan jadi manis."
149
+ },
150
+ {
151
+ q: "Katakanlah Mark bikin error codingan saya, apa dia mau belajar?",
152
+ a: "Banget! Kalau dia eksekusi perintah terus dapet balasan error panjang berwarna merah, Mark sadar dia salah, nyoba perbaikin, dan kalau udah sukses, dia bakal nginget 'solusi fix' itu selamanya di otaknya."
153
+ },
154
+ {
155
+ q: "Aku udah hapus ingatan Mark di memori, kok dia di chat ini masih inget?",
156
+ a: "Mark punya dua ingatan: 'Ingatan Obrolan Aktif' (pesan yang baru aja diketik) dan 'Ingatan Jangka Panjang' (database). Ngehapus database nggak otomatis ngehapus tulisan yang masih nempel nangkring di atas layar chat Anda."
157
+ },
158
+ {
159
+ q: "Cara ngelihat jaringan urat nadi otaknya Mark pas mikir?",
160
+ a: "Di beberapa versi tampilan (kalau nggak disembunyiin), bakal kelihatan garis-garis nyala muter di wujud Orb Mark, itu menandakan sel otak neural-nya lagi sibuk ngeproses mikir keras."
161
+ },
162
+ {
163
+ q: "Apa bedanya Mark sama Siri di iPhone atau Google Assistant?",
164
+ a: "Siri itu kaku, cuma ngerjain 1 tugas (nyalain alarm) lalu tidur. Mark itu 'Agen Mandiri'. Kasih 1 tugas sulit (misal: 'Bikin kalkulator web'), Mark bakal mandiri ngetik, ngetes, dan kerja sendiri ngerampunginnya sambil Anda tinggal ngopi."
165
+ },
166
+ {
167
+ q: "Kenapa laptop saya butuh RAM gede banget buat jalanin mode Offline?",
168
+ a: "Otak AI (Large Language Models) itu ibarat buku ensiklopedia raksasa yang harus dibuka semua halamannya sekaligus biar otaknya bisa jalan. Jadi minimal banget butuh sisa RAM 8GB di laptop biar jalan mulus."
169
+ },
170
+ {
171
+ q: "Saya biasanya pakai aplikasi Ollama, bisa nyambung ke Mark?",
172
+ a: "Sangat bisa! Asalkan Ollama di laptop Anda sudah jalan, Anda tinggal masukin alamat settingan (URL) lokal Ollama-nya ke kolom penyedia AI di halaman pengaturan Mark."
173
+ },
174
+ {
175
+ q: "Kenapa tiba-tiba Mark bertingkah amnesia nanya 'Aku siapa?' ke diri sendiri?",
176
+ a: "Itu namanya efek 'Halusinasi AI'. Biasanya karena obrolan kalian udah kelewat panjang banget bikin ingatan pendeknya kepenuhan dan mulai pikun sesaat. Paling sering kejadian kalau pakai otak AI lokal yang speknya pas-pasan."
177
+ },
178
+ {
179
+ q: "Apa itu Aturan Etika (Proactive Proposal Boundary) di Mark?",
180
+ a: "Ini biar Mark peka sikon (situasi dan kondisi). Kalau Mark tahu Anda lagi repot (buka software berat, banyak meeting), dia bakal sadar diri nahan mulut biar nggak ganggu. Kalau Anda lagi gabut buka sosmed, baru dia berani ngoceh ngajak ngobrol."
181
+ },
182
+ {
183
+ q: "Biar Mark nggak rese tiba-tiba nyela pas saya ada meeting kampus gimana?",
184
+ a: "Paling gampang: matikan saklar Awareness Engine sebentar. Atau simpelnya ketik/omongin aja 'Mark, aku lagi meeting, diem ya'. Nanti dia nyatet pesen itu biar nggak ganggu."
185
+ },
186
+ {
187
+ q: "Kenapa fitur Mark jepret layar (Screenshot-to-WA) cuma aktif pas Mark dihubungi dari HP?",
188
+ a: "Fitur jepret itu emang sengaja dirancang buat kontrol jarak jauh. Jadi pas Anda lagi pergi keluar rumah dan chat bot Mark dari HP WA, Anda bisa nyuruh dia motoin layar laptop di rumah Anda buat ngecek kerjaan yang ditinggal."
189
+ },
190
+ {
191
+ q: "Bisakah Mark diajak mabar main game bareng?",
192
+ a: "Kalau gamenya model tebak teks kata, dia sangat pinter. Tapi kalau game aksi yang butuh kecepatan gerakan (FPS real-time), kemampuan lihat mata Mark belum bisa gerak refleks secepat atlet e-sport (masih ada jeda per detik)."
193
+ },
194
+ {
195
+ q: "Apakah Mark diem-diem bisa narik uang atau buka M-Banking saya?",
196
+ a: "Sama sekali nggak bisa. Mark ini asisten jujur yang cuma bisa meraba barang yang ada di folder kerjaannya, atau ngecek sesuatu yang Anda suruh tayangin terang-terangan di layar."
197
+ },
198
+ {
199
+ q: "Apa visi jangka panjang diciptakannya Mark?",
200
+ a: "Menciptakan asisten yang mengerti Anda lebih dari siapa pun, dan mampu menjadi sahabat sekaligus rekan kerja virtual seumur hidup."
201
+ }
202
+ ];