בעיה בקוד apple script למקבוק
-
יצרתי יחד עם GPT אפליקציה קטנה ונחמדה למקבוק שכל מטרתה היא לחסוך למשתמש זמן בהמרת קבצי pages לdocx (וורד)
הבניה ב״ה עברה בהצלחה והאפליקציה רצה בלי שגיאות ונראית יפה
אבל הקוד שאחראי על ההמרה משום מה לא עובד
private func exportPagesToDocx(_ src: URL, to dir: URL) -> Bool { func esc(_ s: String) -> String { // בריחת מרכאות s.replacingOccurrences(of: "\"", with: "\\\"") } let dst = dir.appendingPathComponent( src.deletingPathExtension().lastPathComponent) .appendingPathExtension("docx") let script = """ try set srcFile to POSIX file "\(esc(src.path))" as alias set dstFile to POSIX file "\(esc(dst.path))" tell application "Pages" if not running then launch repeat until running delay 0.1 end repeat end if activate set theDoc to open srcFile repeat until exists front document delay 0.05 end repeat export theDoc to dstFile as Microsoft Word close theDoc saving no end tell return "OK" on error errMsg return errMsg end try """ let task = Process() task.launchPath = "/usr/bin/osascript" task.arguments = ["-e", script] let pipe = Pipe() task.standardOutput = pipe task.standardError = pipe task.launch(); task.waitUntilExit() let output = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? "" print("AppleScript-out:", output.trimmingCharacters(in: .whitespacesAndNewlines), "| status:", task.terminationStatus) return output.contains("OK") && FileManager.default.fileExists(atPath: dst.path) } // MARK:- פתיחת Share-Sheet private func openShareSheet(files: [URL], from view: NSView) { let picker = NSSharingServicePicker(items: files) picker.show(relativeTo: .zero, of: view, preferredEdge: .minY) }
זהו הקוד שאחרי על הסקשן של ההמרה
מטרתו היא לפתוח את pages ברקע ולעשות ייצוא של הקובץ הנבחר לdocxאשמח אם אי מי ממשתמשי הפורום שמכיר את הנושא יעזור לי (מכיוון שאני עושה את זה בתור לימוד הפלטפורמה מן המובן שאני גם לא אוכל לשלם..)
בתודה מראש
-
@יעקב-מ-פינס כתב בבעיה בקוד appscript למקבוק:
אבל הקוד שאחראי על ההמרה משום מה לא עובד
https://www.cs.utexas.edu/~theksong/posts/quick-tips/2023-12-18-doesnt-work/
https://www.danclarke.com/it-doesnt-work -
@יעקב-מ-פינס יש לך טעות בכותרת, זה apple script ולא appscript
ניסיתי להריץ את האפל סקריפט עצמו דרך Script Editor המובנה והוא עובד, לא נתת מספיק מידע כדי לעזור מכאן הלאה -
@dovid @צדיק-תמים
הוא אפי׳ לא פותח את pages (שזה דבר ראשון שהוא אמור לעשות)
אני מקבל את השגיאה AppleScript-out: Pages got an error: Application isn’t running. | status: 0 בכל פעם שאני מריץ את הקודנ.ב. זה מה שקורה ב Script Editor
נ.ב.ב. השגיאה הראשונה מופיעה גם כש pages רץ
-
@יעקב-מ-פינס כתב בבעיה בקוד apple script למקבוק:
נ.ב. זה מה שקורה ב Script Editor
תעלה צילום מסך בבקשה מאצלך -
@צדיק-תמים
בהרצה של הקוד ב Script Editor (נראה לי לא הכנסתי אותו טוב)
בקונסול ב Xcode
אני חושב שזה משהו שקשור בהרשאות גישה אבל לא הצלחתי להבין בכלל איך אני גורם לאפליקציה לבקש את האישור הזה
-
@יעקב-מ-פינס
רק משתף,
באמצעות Gemini נוצר הקוד הזהset pagesFilePath to POSIX path of (choose file with prompt "בחר קובץ Pages להמרה:") set saveFolderPath to POSIX path of (choose folder with prompt "בחר תיקיית יעד לשמירת קובץ ה-DOCX:") try set srcFile to POSIX file pagesFilePath as alias -- יצירת שם קובץ היעד set fileName to name of (info for srcFile) if fileName ends with ".pages" then set docName to text 1 thru -7 of fileName else set docName to fileName end if set dstPathString to saveFolderPath & docName & ".docx" -- אין צורך להפוך את זה לאובייקט POSIX file כאן אם נשתמש רק במחרוזת ב-shell -- set dstFile to POSIX file dstPathString -- וודא שהקובץ לא קיים כבר בנתיב היעד כדי למנוע בלבול -- נשתמש בפקודת shell לבדיקת קיום ומחיקה (עמידה מאוד) -- Check if file exists using 'test -f' set fileExists to (do shell script "test -f " & quoted form of dstPathString & " && echo true || echo false") as boolean if fileExists then do shell script "rm " & quoted form of dstPathString -- מחיקת הקובץ delay 0.1 -- המתן מעט שהמחיקה תתבצע end if -- הפעל את Pages וודא שהוא רץ tell application "Pages" activate -- המתן בסבלנות ש-Pages יהיה "מוכן" repeat 10 times -- נסה 10 פעמים עם השהייה של שנייה אחת delay 1 try -- נסה פקודה פשוטה כדי לבדוק תגובתיות set appVersion to version of it exit repeat on error -- עדיין לא מגיב, נמשיך לחכות end try end repeat if not (it is running) then error "Pages application could not be launched or is not responding." end if -- פתיחת המסמך set theDoc to open srcFile -- המתן עד שהמסמך ייפתח ויהיה פעיל repeat 20 times -- נסה 20 פעמים עם השהייה של 0.25 שניה (סה"כ 5 שניות) delay 0.25 try if exists theDoc then exit repeat on error -- המסמך עדיין לא נטען, אולי חלון לא מול end try end repeat if not (exists theDoc) then error "Failed to open Pages document within expected time." end if -- ייצוא המסמך (כאן עדיין נשתמש ב-POSIX file אובייקט כי Pages מצפה לו) export theDoc to (POSIX file dstPathString) as Microsoft Word -- סגור את המסמך המקורי close theDoc saving no end tell -- בדיקה סופית: וודא שהקובץ נוצר באמצעות פקודת shell set fileExists to (do shell script "test -f " & quoted form of dstPathString & " && echo true || echo false") as boolean if fileExists then display dialog "הקובץ נשמר בהצלחה כ-DOCX בנתיב: " & dstPathString with title "המרת Pages ל-DOCX" buttons {"אישור"} default button "אישור" return "OK" else error "ההמרה הסתיימה ללא שגיאה, אך קובץ ה-DOCX לא נמצא בנתיב: " & dstPathString end if on error errMsg number errNum display dialog "שגיאה: " & errMsg & " (קוד שגיאה: " & errNum & ")" with title "שגיאת המרה" buttons {"אישור"} default button "אישור" return "Error: " & errMsg end try
שנבדק ב Script Editor ועבד בהצלחה
-
@יעקב-מ-פינס כתבת שאתה מנסה ללמוד, הבעיה היא שבתוך המחרוזת של האפל סקריפט יש התייחסות למשתנה שמוגדר בקוד swift. אם היית פשוט זורק את הקוד לChatGPT (שם גנרי לצ'אט AI ברמה טובה) הוא היה רואה את זה מיד
אגב אני משתמש המון בAI לזה, אם יש שגיאה בקוד שכתבתי שאני לא מבין אני פשוט זורק את הקוד לAI ורואה אם הוא מציע משהו הגיוני, הרבה פעמים פשוט שכחתי נקודה או פסיק מיותר וכדומה, וכידוע הבאגים הכי קשים לגילוי הם הבאגים הכי טפשיים. אם אני רואה שהוא לא בכיוון לא נורא, אני מתחיל לחפש את הבעיה בעצמי, אבל הרבה פעמים זה טעות הקלדה טפשית או משהו בסגנון
לגבי השאלה עצמה, אם הסקריפט עובד בScript Editor ולא באפליקציה זה כנראה בעיית הרשאות, אמור לקפוץ לך כזה פופאפ:
אבל בדקתי את הקוד שהבאת והפופאפ של בקשת ההרשאה לא קופץ, כלומר זה חסימה ברמה יותר גבוהה, הסיבה לבעיה מפורטת כאן וכאן, בקיצור פרויקט חדש בXcode נמצא כברירת בתוך מנגנון ארגז חול שנקרא App Sandbox ומיועד להגביל את הנזק במקרה שאפליקציה מכילה בטעות קוד זדוני, נניח על ידי חבילה חיצונית, והארגז החול הנ"ל מונע מהאפליקציה לשלוח Apple Events לאפליקציות אחרות ואפילו לא מתריע על זה, אפילו לא בConsole.app... כן, חוויית הפיתוח באקוסיסטם של אפל היא נוראה.
הפתרון הקל הוא פשוט למחוק את ארגז החול:
הפתרון ה"נכון" (וגם ההכרחי כדי לשלוח לApple App Store - לא רלוונטי כאן, אתה לא תשלם 99$ לשנה על חשבון מפתח...) הוא להוסיף לקובל Entitlements של האפליקציה אתcom.apple.security.temporary-exception.apple-events
עם הbundleId של Pages (com.apple.iWork.Pages
) אבל תכלס זה לא עובד לי, עדיין מתקבלת שגיאתA privilege violation occurred
, ואין לי זמן לחקור את זה הלאה -
@צדיק-תמים
שכוייח
הנושא העיקרי הוא שבניתי הכל עם GPT והוא לא מצא שום שגיאהבנוגע לפיתרון השני זה רעיון ממש נחמד שלא חשבתי אפי׳ לנסות אותו
ב״ה מה שעשיתי בסוף זה הזרקה של הסקריפט הפעיל מקובץ חיצוני
האפליקציה תתפרסם מחר בעז״ה נשאר לי עוד כמה שינויים קלים -
רק מעדכן
ב״ה הצלחתי ליצור את האפליקציה באופן מלא בעיקר בזכות @צדיק-תמים שעזר לי רבות
לכל המעוניין ניתן להוריד את האפליקציה מכאן (נשלח לבדיקה בנטפרי) אשמח לשמוע רעיונות לשיפור
הקוד המלא נמצא בגיטהאב שלי
אשמח לשמוע הערות לשיפור (וגם הערות בכללי
️)
-
אשמח לעזרתכם שוב
הוספתי (כלומר gpt) תמיכה בשפות
רציתי שיוסיף לחצן globe לשינוי שפה (בחירה מתפריט)
אבל זה התוצאה שקיבלתי
זה הקוד של החלק האחראי על הכפתור הזה
אשמח לשמוע מה בדיוק הטעות שגורמת לזהMenu { ForEach(availableLanguages(), id: \.self) { lang in Button { languageManager.selectedLanguage = lang } label: { HStack { Text(Locale(identifier: lang) .localizedString(forLanguageCode: lang)? .capitalized(with: Locale(identifier: lang)) ?? lang) if languageManager.selectedLanguage == lang { Image(systemName: "checkmark") } } } } } label: { ZStack { Circle() .fill(Color.white.opacity(0.85)) .frame(width: 44, height: 44) .shadow(radius: 3) Image(systemName: "globe") .font(.system(size: 22, weight: .medium)) .foregroundColor(.accentColor) } } .padding(.top, 14) .padding(.trailing, 20)
תודה
-
ב״ה סוף סוף הסתדר ע״י הקוד הזה
// --- כפתור גלובוס --- VStack { HStack { Spacer() Menu { ForEach(availableLanguages(), id: \.self) { lang in Button { languageManager.selectedLanguage = lang } label: { HStack { Text(Locale(identifier: lang) .localizedString(forLanguageCode: lang)? .capitalized(with: Locale(identifier: lang)) ?? lang) if languageManager.selectedLanguage == lang { Image(systemName: "checkmark") } } } } } label: { ZStack { Circle() .fill(Color.white.opacity(0.88)) .frame(width: 44, height: 44) .shadow(radius: 3) Image(systemName: "globe") .font(.system(size: 23, weight: .medium)) .foregroundColor(.accentColor) } } .buttonStyle(.plain) .padding(.top, 16) .padding(.trailing, 16) } Spacer() }
ממש ברגעים אלו אני מעלה את הקוד לגיטהאב ואני אערוך כאן (או שאולי עדיף נושא חדש?)
-
@יעקב-מ-פינס במתכונת הזאת, אל תשאל בכלל.
תנסה צאטים אחרים, תקוף את הבעיה בניסוח שונה, רק לא לשאול פה בפורום בכזו צורה.
תשאל בדברים שאתה מבין אותם, או מתכונן להבין אותם, כמטרה די מרכזית.
אם רוב המטרה היא "שיעבוד וזהו", בפרט עם קוד, עדיף שלא יהיה פה. -
@יעקב-מ-פינס אני כעת קורא את דברי וחושש מאיך שהם נשמעים.
אני מאוד מכבד את ההתקדמות שלך המרשימה ממש בתכנות,
ומאוד מאמין גם בניסוי טעיה אפילו עם AI עם/בלי להבין,
רק שפה כחברה וכמקום דיון עם אנשים שלכל אחד יש את חייו, אם מביאים פה קוד, נראה לי שראוי לעמוד מאחוריו, להבין אותו יותר ולצפות לתשובה ולנימוקים טרחניים על הקוד ממש ולא על השורה התחתונה בלבד או בעיקר. הפוסטים שלך גם אם יש בהם רצון הבנה, הם מידי מזכירים את העידן החדש של הAI בו אין אפילו כח לנסח את השאלה...