AIConfigWindowController.swift 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. //
  2. // AIConfigWindowController.swift
  3. // PDF Reader Pro Edition
  4. //
  5. // Created by Niehaoyu on 2024/1/17.
  6. //
  7. import Cocoa
  8. @objcMembers class AIConfigWindowController: NSWindowController, NSTextFieldDelegate, NSTextViewDelegate {
  9. @IBOutlet weak var contendBox: NSBox!
  10. @IBOutlet weak var titleLabel: NSTextField!
  11. @IBOutlet weak var titleTipBtn: KMButton!
  12. @IBOutlet weak var uploadBGView: NSView!
  13. @IBOutlet weak var uploadItemBox: KMBox!
  14. @IBOutlet weak var uploadDesLabel: NSTextField!
  15. @IBOutlet weak var uploadPDFBtn: KMButton!
  16. @IBOutlet weak var fileBGView: NSView!
  17. @IBOutlet weak var fileEmptyImage: NSImageView!
  18. @IBOutlet weak var fileActionView: NSView!
  19. @IBOutlet weak var fileActionLabel: NSTextField!
  20. @IBOutlet weak var fileActionBtn: KMButton!
  21. @IBOutlet weak var filePDFBGView: NSView!
  22. @IBOutlet weak var filePDFHoverBtn: KMButton!
  23. @IBOutlet weak var pdfCoverView: NSView!
  24. @IBOutlet weak var pdfCoverImageView: NSImageView!
  25. @IBOutlet weak var removePDFBtn: NSButton!
  26. @IBOutlet weak var inputTextCountLabel: NSTextField!
  27. @IBOutlet weak var fileSizeTipView: NSView!
  28. @IBOutlet weak var fileSizeTipLabel: NSTextField!
  29. @IBOutlet weak var pdfNameLbl: NSTextField!
  30. @IBOutlet var fileEmptyTextView: NSTextView!
  31. @IBOutlet weak var filePlaceholdLabel: NSTextField!
  32. @IBOutlet weak var fileContendViewTopConst: NSLayoutConstraint!
  33. @IBOutlet weak var translateSepLineView: NSView!
  34. @IBOutlet weak var translateConfigView: NSView!
  35. @IBOutlet weak var fromLanguageView: NSView!
  36. @IBOutlet weak var fromLanguageLabel: NSTextField!
  37. @IBOutlet weak var fromLanguageBtn: NSButton!
  38. @IBOutlet weak var toLanguageView: NSView!
  39. @IBOutlet weak var toLanguageLabel: NSTextField!
  40. @IBOutlet weak var toLanguageBtn: NSButton!
  41. @IBOutlet weak var translateResultView: NSView!
  42. @IBOutlet weak var translateResultLabel: NSTextField!
  43. @IBOutlet weak var translateResultSubLabel: NSTextField!
  44. @IBOutlet weak var resultBGView: NSView!
  45. @IBOutlet weak var resultEmptyImage: NSImageView!
  46. // @IBOutlet weak var resultLabel: NSTextField!
  47. @IBOutlet var aiResultTextView: NSTextView!
  48. @IBOutlet weak var cancelBtn: NSButton!
  49. @IBOutlet weak var saveAsTextBtn: NSButton!
  50. @IBOutlet weak var saveAsPDFBtn: NSButton!
  51. static var currentWindowController: AIConfigWindowController!
  52. var popOver: NSPopover!
  53. var configType: AIConfigType = .none
  54. var cancelHandle: ((_ windowVC: AIConfigWindowController) -> Void)?
  55. var fileActionenAble: Bool = false
  56. var aiConvertFinish: Bool = true
  57. var filePath: String = ""
  58. var fromLanguage: String = ""
  59. var toLanguage: String = ""
  60. var translateFinish: Bool = false
  61. var translateFile: Bool = false
  62. var translateResultPath: String = ""
  63. @objc static func currentWC() -> AIConfigWindowController {
  64. if currentWindowController != nil {
  65. return currentWindowController
  66. } else {
  67. let configWC: AIConfigWindowController = AIConfigWindowController.init(windowNibName: "AIConfigWindowController")
  68. currentWindowController = configWC;
  69. return currentWindowController
  70. }
  71. }
  72. override func windowDidLoad() {
  73. super.windowDidLoad()
  74. // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
  75. self.titleLabel.font = NSFont.SFProTextSemiboldFont(13)
  76. self.titleTipBtn.mouseMoveCallback = {[unowned self] mouseEntered in
  77. if mouseEntered {
  78. var tipString = NSLocalizedString("Recommended file size: 10M or less.", comment: "")
  79. if self.configType == .reWriting {
  80. tipString = NSLocalizedString("No more than 2000 characters.", comment: "")
  81. } else if self.configType == .proofreading {
  82. tipString = NSLocalizedString("No more than 2000 characters.", comment: "")
  83. } else if self.configType == .translate {
  84. tipString = NSLocalizedString("No more than 30 pages of a document.", comment: "")
  85. }
  86. let popViewController = KMToolbarItemPopViewController.init()
  87. if self.popOver == nil {
  88. self.popOver = NSPopover.init()
  89. }
  90. self.popOver.contentViewController = popViewController
  91. self.popOver.animates = false
  92. self.popOver.behavior = .semitransient
  93. self.popOver.contentSize = (popViewController.view.frame.size)
  94. popViewController.updateWithHelpTip(helpTip: tipString)
  95. self.popOver.show(relativeTo: self.titleTipBtn.frame, of: (self.window?.contentView)!, preferredEdge: .maxY)
  96. } else {
  97. self.popOver.close()
  98. }
  99. }
  100. self.uploadItemBox.borderWidth = 0
  101. self.uploadItemBox.cornerRadius = 1
  102. self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S0()
  103. self.uploadDesLabel.font = NSFont.SFProTextRegularFont(13)
  104. self.uploadDesLabel.textColor = KMAppearance.KMColor_Layout_H0()
  105. self.uploadDesLabel.stringValue = NSLocalizedString("Choose", comment: "")
  106. self.uploadPDFBtn.mouseMoveCallback = {[unowned self] mouseEntered in
  107. if mouseEntered {
  108. self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S_1()
  109. } else {
  110. self.uploadItemBox.fillColor = KMAppearance.KMColor_Interactive_S0()
  111. }
  112. }
  113. self.fileBGView.wantsLayer = true
  114. self.fileBGView.layer?.cornerRadius = 6
  115. self.fileBGView.layer?.masksToBounds = true
  116. self.fileBGView.layer?.borderWidth = 1
  117. self.fileBGView.layer?.borderColor = KMAppearance.KMColor_Layout_L_2().cgColor
  118. self.fileSizeTipView.wantsLayer = true
  119. self.fileSizeTipLabel.font = NSFont.SFProTextRegularFont(12)
  120. self.fileSizeTipLabel.textColor = KMAppearance.KMColor_Layout_H0()
  121. self.fileSizeTipLabel.stringValue = NSLocalizedString("Please upload a file smaller than 10M.", comment: "")
  122. self.fileSizeTipView.isHidden = true
  123. self.pdfNameLbl.font = NSFont.SFProTextRegularFont(12)
  124. self.pdfNameLbl.textColor = KMAppearance.KMColor_Layout_H0()
  125. self.resultBGView.wantsLayer = true
  126. self.resultBGView.layer?.cornerRadius = 6
  127. self.resultBGView.layer?.masksToBounds = true
  128. self.fileActionView.wantsLayer = true
  129. self.fileActionView.layer?.cornerRadius = 1
  130. self.fileActionView.layer?.masksToBounds = true
  131. self.fileActionLabel.font = NSFont.SFProTextRegularFont(13)
  132. self.fileActionBtn.mouseMoveCallback = {[unowned self] mouseEntered in
  133. if self.fileActionenAble == true {
  134. if mouseEntered {
  135. self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M_1().cgColor
  136. } else {
  137. self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().cgColor
  138. }
  139. }
  140. }
  141. self.translateSepLineView.wantsLayer = true
  142. self.pdfCoverView.wantsLayer = true
  143. self.pdfCoverView.layer?.cornerRadius = 2
  144. self.pdfCoverView.layer?.borderWidth = 2
  145. let countFormatter = TextFieldFormatter.init()
  146. countFormatter.setMaximumLength(2000)
  147. self.inputTextCountLabel.formatter = countFormatter
  148. self.inputTextCountLabel.delegate = self
  149. if KMAppearance.isDarkMode() {
  150. self.contendBox.fillColor = NSColor(red: 44/255, green: 44/255, blue: 44/255, alpha: 1)
  151. self.titleLabel.textColor = NSColor.white
  152. self.resultBGView.layer?.backgroundColor = NSColor(red: 49/255, green: 49/255, blue: 49/255, alpha: 1).cgColor
  153. self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_W30()
  154. self.fileSizeTipView.layer?.backgroundColor = NSColor(red: 251/255, green: 166/255, blue: 0, alpha: 1).cgColor
  155. self.translateSepLineView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.05).cgColor
  156. self.translateResultView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.05).cgColor
  157. self.pdfCoverView.layer?.borderColor = NSColor.white.withAlphaComponent(0.2).cgColor
  158. self.pdfCoverView.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.1).cgColor
  159. } else {
  160. self.contendBox.fillColor = NSColor.white
  161. self.titleLabel.textColor = NSColor.black
  162. self.resultBGView.layer?.backgroundColor = NSColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
  163. self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_B30()
  164. self.fileSizeTipView.layer?.backgroundColor = NSColor(red: 253/255, green: 239/255, blue: 212/255, alpha: 1).cgColor
  165. self.translateSepLineView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.05).cgColor
  166. self.translateResultView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.05).cgColor
  167. self.pdfCoverView.layer?.borderColor = NSColor.black.withAlphaComponent(0.12).cgColor
  168. self.pdfCoverView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.04).cgColor
  169. }
  170. self.fileEmptyTextView.backgroundColor = NSColor.clear
  171. self.fileEmptyTextView.delegate = self
  172. self.window?.makeFirstResponder(nil)
  173. var languages = ["Automatic", "English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
  174. let menu = NSMenu.init()
  175. for idx in 0...languages.count-1 {
  176. let string = languages[idx]
  177. let menuItem = NSMenuItem.init(title: string, action: #selector(menuItemClick(_:)), keyEquivalent: "")
  178. menuItem.tag = 1000 + idx
  179. menu.addItem(menuItem)
  180. }
  181. self.fromLanguageView?.menu = menu
  182. self.fromLanguage = "Automatic"
  183. languages = ["English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
  184. var toMenu = NSMenu.init()
  185. for idx in 0...languages.count-1 {
  186. let string = languages[idx]
  187. let menuItem = NSMenuItem.init(title: string, action: #selector(menuItemClick(_:)), keyEquivalent: "")
  188. menuItem.tag = 3000 + idx
  189. toMenu.addItem(menuItem)
  190. }
  191. self.toLanguageView?.menu = toMenu
  192. self.toLanguage = "English"
  193. self.fromLanguageLabel.font = NSFont.SFProTextRegularFont(13)
  194. self.toLanguageLabel.font = NSFont.SFProTextRegularFont(13)
  195. self.fromLanguageLabel.textColor = KMAppearance.KMColor_Layout_H0()
  196. self.toLanguageLabel.textColor = KMAppearance.KMColor_Layout_H0()
  197. self.fromLanguageLabel.stringValue = self.fromLanguage
  198. self.toLanguageLabel.stringValue = self.toLanguage
  199. self.removePDFBtn.isHidden = true
  200. self.filePDFHoverBtn.mouseMoveCallback = {[unowned self] mouseEntered in
  201. if mouseEntered {
  202. self.removePDFBtn.isHidden = false
  203. } else {
  204. self.removePDFBtn.isHidden = true
  205. }
  206. }
  207. self.cancelBtn.title = NSLocalizedString("Cancel", comment: "")
  208. self.saveAsTextBtn.title = NSLocalizedString("Save as TXT", comment: "")
  209. self.saveAsPDFBtn.title = NSLocalizedString("Save as PDF", comment: "")
  210. self.translateResultLabel.stringValue = NSLocalizedString("Translation Completion", comment: "")
  211. self.translateResultSubLabel.stringValue = NSLocalizedString("Click \"Save as PDF\" to save the result as a PDF file.", comment: "")
  212. self.translateResultView.isHidden = true
  213. self.translateResultView.wantsLayer = true
  214. if KMAppearance.isDarkMode() {
  215. self.translateResultLabel.textColor = NSColor.white
  216. self.translateResultSubLabel.textColor = NSColor.white
  217. } else {
  218. self.translateResultLabel.textColor = NSColor.black.withAlphaComponent(0.5)
  219. self.translateResultSubLabel.textColor = NSColor.black.withAlphaComponent(0.5)
  220. }
  221. self.translateResultLabel.font = NSFont.SFProTextSemiboldFont(13)
  222. self.translateResultSubLabel.font = NSFont.SFProTextRegularFont(13)
  223. self.aiResultTextView.font = NSFont.SFProTextRegularFont(14)
  224. self.aiResultTextView.textColor = KMAppearance.KMColor_Layout_H0()
  225. self.aiResultTextView.backgroundColor = NSColor.clear
  226. self.aiResultTextView.isEditable = false
  227. self.fileEmptyTextView.font = NSFont.SFProTextRegularFont(14)
  228. self.fileEmptyTextView.textColor = KMAppearance.KMColor_Layout_H0()
  229. }
  230. func getFileSize(atPath filePath : String) -> CGFloat {
  231. guard let dict = try? FileManager.default.attributesOfItem(atPath: filePath) as NSDictionary else {
  232. return 0
  233. }
  234. return CGFloat(dict.fileSize())
  235. }
  236. func refreshUI() -> Void {
  237. if self.configType == .summarize {
  238. self.titleLabel.stringValue = NSLocalizedString("AI Summarize", comment: "")
  239. self.fileEmptyImage.image = NSImage(named: "ai_summary_Empty")
  240. } else if self.configType == .reWriting {
  241. self.titleLabel.stringValue = NSLocalizedString("AI Rewrite", comment: "")
  242. self.fileEmptyImage.image = NSImage(named: "ai_rewriting_empty")
  243. } else if self.configType == .proofreading {
  244. self.titleLabel.stringValue = NSLocalizedString("AI Proofread", comment: "")
  245. self.fileEmptyImage.image = NSImage(named: "ai_proofreading_empty")
  246. } else if self.configType == .translate {
  247. self.titleLabel.stringValue = NSLocalizedString("AI Translate", comment: "")
  248. self.fileEmptyImage.image = NSImage(named: "ai_translate_empty")
  249. }
  250. self.translateResultView.isHidden = true
  251. self.translateConfigView.isHidden = true
  252. self.translateSepLineView.isHidden = true
  253. if self.configType == .reWriting ||
  254. self.configType == .proofreading {
  255. self.uploadBGView.isHidden = true
  256. self.fileContendViewTopConst.constant = 52
  257. self.filePDFBGView.isHidden = true
  258. } else {
  259. self.uploadBGView.isHidden = false
  260. self.fileContendViewTopConst.constant = 92
  261. self.filePDFBGView.isHidden = false
  262. if self.configType == .translate {
  263. self.fileContendViewTopConst.constant = 137
  264. self.translateConfigView.isHidden = false
  265. self.translateSepLineView.isHidden = false
  266. }
  267. }
  268. self.reloadData()
  269. }
  270. func clearData() -> Void {
  271. self.fileEmptyTextView.string = ""
  272. self.aiResultTextView.string = ""
  273. self.filePath = ""
  274. self.translateFinish = false
  275. self.translateFile = false
  276. }
  277. func reloadData() -> Void {
  278. self.clearData()
  279. self.fileEmptyTextView.isEditable = true
  280. self.inputTextCountLabel.isHidden = true
  281. if self.configType == .summarize {
  282. self.fileEmptyTextView.isEditable = false
  283. self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by uploading a document (pdf).", comment: "")
  284. } else if self.configType == .reWriting {
  285. self.inputTextCountLabel.isHidden = false
  286. self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text", comment: "")
  287. } else if self.configType == .proofreading {
  288. self.inputTextCountLabel.isHidden = false
  289. self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text", comment: "")
  290. } else if self.configType == .translate {
  291. self.inputTextCountLabel.isHidden = false
  292. self.filePlaceholdLabel.placeholderString = NSLocalizedString("Start by typing, pasting (⌘ + V) text, or uploading a document (pdf).", comment: "")
  293. }
  294. self.updateActionViewUI()
  295. self.updateResultViewUI()
  296. }
  297. //MARK: 更新左侧UI
  298. func updateActionViewUI() -> Void{
  299. self.fileSizeTipView.isHidden = true
  300. if self.filePath.count > 0 || self.fileEmptyTextView.string.count > 0 {
  301. self.enableActionView(true)
  302. self.filePlaceholdLabel.isHidden = true
  303. } else {
  304. self.enableActionView(false)
  305. self.filePlaceholdLabel.isHidden = false
  306. }
  307. if self.filePath.count > 0 {
  308. self.fileEmptyTextView.isHidden = true
  309. self.filePDFBGView.isHidden = false
  310. let document = CPDFDocument.init(url: URL(fileURLWithPath: self.filePath))
  311. if document?.isLocked == true || document == nil {
  312. self.filePath = ""
  313. self.updateActionViewUI()
  314. return
  315. }
  316. DispatchQueue.main.async {
  317. let page = document?.page(at: 0)
  318. let image = page?.thumbnail(of: page!.size)
  319. self.pdfCoverImageView.image = image
  320. }
  321. let filePathURL = URL(fileURLWithPath: self.filePath)
  322. let parentDirectory = filePathURL.lastPathComponent
  323. self.pdfNameLbl.stringValue = parentDirectory
  324. self.inputTextCountLabel.isHidden = true
  325. } else {
  326. self.fileEmptyTextView.isHidden = false
  327. self.filePDFBGView.isHidden = true
  328. self.pdfCoverImageView.image = nil
  329. self.inputTextCountLabel.isHidden = false
  330. if self.configType == .summarize {
  331. self.inputTextCountLabel.isHidden = true
  332. }
  333. }
  334. self.inputTextCountLabel.stringValue = String(format: "%ld", self.fileEmptyTextView.string.count) + "/2000"
  335. if self.fileEmptyTextView.string.count == 2000 {
  336. self.inputTextCountLabel.textColor = KMAppearance.KMColor_Status_Err()
  337. } else {
  338. if KMAppearance.isDarkMode() {
  339. self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_W30()
  340. } else {
  341. self.inputTextCountLabel.textColor = KMAppearance.KMColor_Layout_B30()
  342. }
  343. }
  344. if self.aiResultTextView.string.count > 0 && (self.fileEmptyTextView.string.count > 0 || self.filePath.count > 0){
  345. self.fileActionLabel.stringValue = NSLocalizedString("Redo (1 credit)", comment: "")
  346. self.fileActionLabel.stringValue = NSLocalizedString("Redo (1 credit)", comment: "")
  347. } else {
  348. if self.configType == .summarize {
  349. self.fileActionLabel.stringValue = NSLocalizedString("Summarize", comment: "") + NSLocalizedString("(1 credit)", comment: "")
  350. } else if self.configType == .reWriting {
  351. self.fileActionLabel.stringValue = NSLocalizedString("Rewrite", comment: "") + NSLocalizedString("(1 credit)", comment: "")
  352. } else if self.configType == .proofreading {
  353. self.fileActionLabel.stringValue = NSLocalizedString("Proofread", comment: "") + NSLocalizedString("(1 credit)", comment: "")
  354. } else if self.configType == .translate {
  355. self.fileActionLabel.stringValue = NSLocalizedString("Translate", comment: "") + NSLocalizedString("(1 credit)", comment: "")
  356. }
  357. }
  358. }
  359. func enableActionView(_ enable: Bool) -> Void {
  360. if enable {
  361. self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().cgColor
  362. self.fileActionLabel.textColor = NSColor.white
  363. self.fileActionBtn.isEnabled = true
  364. } else {
  365. self.fileActionView.layer?.backgroundColor = KMAppearance.KMColor_Interactive_M0().withAlphaComponent(0.4).cgColor
  366. self.fileActionLabel.textColor = NSColor.white.withAlphaComponent(0.4)
  367. self.fileActionBtn.isEnabled = false
  368. }
  369. self.fileActionenAble = enable
  370. if self.filePath.count > 0 || self.fileEmptyTextView.string.count > 0 {
  371. self.filePlaceholdLabel.isHidden = true
  372. self.fileEmptyImage.isHidden = true
  373. } else {
  374. self.filePlaceholdLabel.isHidden = false
  375. self.fileEmptyImage.isHidden = false
  376. }
  377. }
  378. func updateResultViewUI() -> Void{
  379. if self.aiResultTextView.string.count > 0 {
  380. self.resultEmptyImage.isHidden = true
  381. self.saveAsTextBtn.isEnabled = true
  382. self.saveAsPDFBtn.isEnabled = true
  383. } else {
  384. self.resultEmptyImage.isHidden = false
  385. self.saveAsTextBtn.isEnabled = false
  386. self.saveAsPDFBtn.isEnabled = false
  387. }
  388. if self.configType == .translate && self.translateFinish == true {
  389. self.saveAsTextBtn.isEnabled = true
  390. self.saveAsPDFBtn.isEnabled = true
  391. if self.translateFile == true {
  392. self.translateResultView.isHidden = false
  393. self.saveAsTextBtn.isEnabled = false
  394. } else {
  395. self.translateResultView.isHidden = true
  396. }
  397. if translateResultView.isHidden == false {
  398. self.resultEmptyImage.isHidden = true
  399. }
  400. }
  401. }
  402. func addWaingView(_ view: NSView) -> Void {
  403. self.removeWaitingView(view)
  404. let wView = WaitingView.init(frame: view.bounds)
  405. wView.autoresizingMask = [.width, .height]
  406. view.addSubview(wView)
  407. wView.startAnimation()
  408. }
  409. func removeWaitingView(_ view: NSView) -> Void {
  410. for view in view.subviews {
  411. if view.className == WaitingView.className() {
  412. view.removeFromSuperview()
  413. break
  414. }
  415. }
  416. }
  417. //MARK: - IBAction
  418. @IBAction func chooseFileAction(_ sender: KMButton) {
  419. let openPanel = NSOpenPanel()
  420. openPanel.canChooseDirectories = true
  421. openPanel.canChooseFiles = true
  422. openPanel.allowsMultipleSelection = false;
  423. openPanel.allowedFileTypes = ["pdf"]
  424. openPanel.beginSheetModal(for: self.window!) { result in
  425. if result == .OK {
  426. let fileURL = openPanel.urls.first
  427. let fileSize = self.getFileSize(atPath: fileURL!.path)
  428. if fileSize/(1024*1024) > 10 {
  429. self.fileSizeTipView.isHidden = false
  430. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
  431. self.fileSizeTipView.isHidden = true
  432. }
  433. } else {
  434. self.filePath = fileURL!.path
  435. self.fileEmptyTextView.string = ""
  436. self.updateActionViewUI()
  437. }
  438. }
  439. }
  440. }
  441. @IBAction func chooseLanguageAction(_ sender: NSButton) {
  442. if sender == self.fromLanguageBtn {
  443. let menu = self.fromLanguageView?.menu
  444. menu?.popUp(positioning: menu?.item(at: 0), at: CGPoint(x: 0, y: 15), in: sender)
  445. } else if sender == self.toLanguageBtn {
  446. let menu = self.toLanguageView?.menu
  447. menu?.popUp(positioning: menu?.item(at: 0), at: CGPoint(x: 0, y: 15), in: sender)
  448. }
  449. }
  450. @objc func menuItemClick(_ item: NSMenuItem) {
  451. if item.tag < 2000 {
  452. self.fromLanguage = item.title
  453. } else {
  454. self.toLanguage = item.title
  455. }
  456. self.fromLanguageLabel.stringValue = self.fromLanguage
  457. self.toLanguageLabel.stringValue = self.toLanguage
  458. }
  459. @IBAction func removePDFAction(_ sender: NSButton) {
  460. self.filePath = ""
  461. self.updateActionViewUI()
  462. self.updateResultViewUI()
  463. }
  464. @IBAction func startAIFunction(_ sender: KMButton) {
  465. let newStatus: Bool = KMCloudServer.isConnectionAvailable()
  466. if !newStatus {
  467. let alert = NSAlert()
  468. alert.alertStyle = .critical
  469. alert.messageText = NSLocalizedString("Please make sure your internet connection is available.", comment: "")
  470. alert.runModal()
  471. return
  472. }
  473. if self.configType == .summarize {
  474. if FileManager.default.fileExists(atPath: self.filePath) {
  475. self.aiResultTextView.string = ""
  476. self.addWaingView(self.resultBGView)
  477. self.enableActionView(false)
  478. self.removePDFBtn.isEnabled = false
  479. self.aiConvertFinish = false
  480. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
  481. KMAIRequestServerManager.defaultManager.aiAction(content: self.filePath, state: .extractSummaryFile) { wrapper in
  482. DispatchQueue.main.async {
  483. self.aiConvertFinish = true
  484. self.removePDFBtn.isEnabled = true
  485. self.removeWaitingView(self.resultBGView)
  486. self.updateActionViewUI()
  487. let success = wrapper.success
  488. if success {
  489. let resultStr = wrapper.content
  490. self.aiResultTextView.string = resultStr
  491. self.updateActionViewUI()
  492. self.updateResultViewUI()
  493. } else {
  494. let alert = NSAlert()
  495. alert.alertStyle = .critical
  496. alert.messageText = wrapper.content
  497. alert.runModal()
  498. return
  499. }
  500. }
  501. }
  502. }
  503. } else if self.configType == .reWriting {
  504. self.aiResultTextView.string = ""
  505. self.addWaingView(self.resultBGView)
  506. self.enableActionView(false)
  507. self.removePDFBtn.isEnabled = false
  508. self.aiConvertFinish = false
  509. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
  510. KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
  511. state: .rewrite) { wrapper in
  512. DispatchQueue.main.async {
  513. self.aiConvertFinish = true
  514. self.removePDFBtn.isEnabled = true
  515. self.removeWaitingView(self.resultBGView)
  516. self.updateActionViewUI()
  517. let success = wrapper.success
  518. if success {
  519. let resultStr = wrapper.content
  520. self.aiResultTextView.string = resultStr
  521. self.updateActionViewUI()
  522. self.updateResultViewUI()
  523. } else {
  524. let alert = NSAlert()
  525. alert.alertStyle = .critical
  526. alert.messageText = wrapper.content
  527. alert.runModal()
  528. return
  529. }
  530. }
  531. }
  532. } else if self.configType == .proofreading {
  533. self.aiResultTextView.string = ""
  534. self.addWaingView(self.resultBGView)
  535. self.enableActionView(false)
  536. self.removePDFBtn.isEnabled = false
  537. self.aiConvertFinish = false
  538. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
  539. KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
  540. state: .correctTypos) { wrapper in
  541. DispatchQueue.main.async {
  542. self.aiConvertFinish = true
  543. self.removePDFBtn.isEnabled = true
  544. self.removeWaitingView(self.resultBGView)
  545. self.updateActionViewUI()
  546. let success = wrapper.success
  547. if success {
  548. let resultStr = wrapper.content
  549. self.aiResultTextView.string = resultStr
  550. self.updateActionViewUI()
  551. self.updateResultViewUI()
  552. } else {
  553. let alert = NSAlert()
  554. alert.alertStyle = .critical
  555. alert.messageText = wrapper.content
  556. alert.runModal()
  557. return
  558. }
  559. }
  560. }
  561. } else if self.configType == .translate {
  562. self.aiResultTextView.string = ""
  563. self.addWaingView(self.resultBGView)
  564. self.enableActionView(false)
  565. self.translateFinish = false
  566. self.translateResultView.isHidden = true
  567. // if self.filePath.count > 0 {
  568. self.translateFile = true
  569. self.removePDFBtn.isEnabled = false
  570. self.aiConvertFinish = false
  571. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
  572. // KMAIRequestServerManager.defaultManager.aiAction(content: self.filePath,
  573. // state: .fileTranslate,
  574. // from: self.fromLanguage,
  575. // to: self.toLanguage) { wrapper in
  576. DispatchQueue.main.async {
  577. self.aiConvertFinish = true
  578. self.removePDFBtn.isEnabled = true
  579. self.removeWaitingView(self.resultBGView)
  580. self.updateActionViewUI()
  581. // let success = wrapper.success
  582. // if success {
  583. self.translateFinish = true
  584. self.translateResultView.isHidden = false
  585. // let resultStr = wrapper.content
  586. let resultStr = "wrapper.content"
  587. self.translateResultPath = resultStr
  588. self.updateActionViewUI()
  589. self.updateResultViewUI()
  590. // } else {
  591. // let alert = NSAlert()
  592. // alert.alertStyle = .critical
  593. // alert.messageText = wrapper.content
  594. // alert.runModal()
  595. // return
  596. // }
  597. }
  598. };
  599. // } else {
  600. // self.translateFile = false
  601. // self.removePDFBtn.isEnabled = false
  602. // self.aiConvertFinish = false
  603. //// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
  604. // KMAIRequestServerManager.defaultManager.aiAction(content: self.fileEmptyTextView.string,
  605. // state: .textTranslate,
  606. // from: self.fromLanguage,
  607. // to: self.toLanguage) { wrapper in
  608. // DispatchQueue.main.async {
  609. // self.aiConvertFinish = true
  610. // self.removePDFBtn.isEnabled = true
  611. // self.removeWaitingView(self.resultBGView)
  612. // self.updateActionViewUI()
  613. //
  614. // let success = wrapper.success
  615. // if success {
  616. // self.translateFinish = true
  617. // self.translateResultView.isHidden = false
  618. //
  619. // let resultStr = wrapper.content
  620. // self.aiResultTextView.string = resultStr
  621. //
  622. // self.updateActionViewUI()
  623. // self.updateResultViewUI()
  624. // } else {
  625. // let alert = NSAlert()
  626. // alert.alertStyle = .critical
  627. // alert.messageText = wrapper.content
  628. // alert.runModal()
  629. //
  630. // self.updateResultViewUI()
  631. // return
  632. // }
  633. // }
  634. // };
  635. // }
  636. }
  637. }
  638. @IBAction func languageChangeAction(_ sender: Any) {
  639. let curLan = self.fromLanguage
  640. self.fromLanguage = self.toLanguage
  641. self.toLanguage = curLan
  642. self.fromLanguageLabel.stringValue = self.fromLanguage
  643. self.toLanguageLabel.stringValue = self.toLanguage
  644. }
  645. @IBAction func cancelAction(_ sender: NSButton) {
  646. DispatchQueue.main.async {
  647. self.removeWaitingView(self.resultBGView)
  648. self.updateActionViewUI()
  649. }
  650. if self.aiConvertFinish == false {
  651. let alert = NSAlert()
  652. alert.alertStyle = .critical
  653. alert.messageText = NSLocalizedString("The task is already in process, if you cancel the process, AI Credit will not be returned, please confirm if you still need to cancel?", comment: "")
  654. alert.addButton(withTitle: NSLocalizedString("Back ", comment: ""))
  655. alert.addButton(withTitle: NSLocalizedString("Confirm Cancel", comment: ""))
  656. let response = alert.runModal()
  657. if response.rawValue == 1001 {
  658. self.confirmCancelAction()
  659. }
  660. return
  661. }
  662. if self.aiResultTextView.string.count > 0 {
  663. if KMFunctionGuideWindowController.availableShow(.aiInfoResultSave) == true {
  664. KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
  665. let alert = NSAlert()
  666. alert.alertStyle = .critical
  667. alert.messageText = NSLocalizedString("The results are not saved. Do you want to save them in other formats?", comment: "")
  668. alert.addButton(withTitle: NSLocalizedString("Yes", comment: ""))
  669. alert.addButton(withTitle: NSLocalizedString("No", comment: ""))
  670. let response = alert.runModal()
  671. if response.rawValue == 1001 {
  672. self.cancelAction(self.cancelBtn)
  673. }
  674. return
  675. }
  676. }
  677. self.clearData()
  678. guard let callBack = self.cancelHandle else {
  679. return
  680. }
  681. callBack(self)
  682. }
  683. func confirmCancelAction() -> Void {
  684. self.clearData()
  685. guard let callBack = self.cancelHandle else {
  686. return
  687. }
  688. callBack(self)
  689. }
  690. @IBAction func saveAsTextAction(_ sender: Any) {
  691. let fileName = "Untitled"
  692. let outputSavePanel = NSSavePanel()
  693. outputSavePanel.allowedFileTypes = ["txt"]
  694. outputSavePanel.nameFieldStringValue = fileName
  695. let result = outputSavePanel.runModal()
  696. if result == .OK {
  697. let filePath = outputSavePanel.url?.path
  698. do {
  699. try self.aiResultTextView.string.write(to: outputSavePanel.url!, atomically: true, encoding: .utf8)
  700. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
  701. KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
  702. } catch {
  703. }
  704. }
  705. }
  706. @IBAction func saveAsPDFAction(_ sender: Any) {
  707. let fileName = "Untitled"
  708. let outputSavePanel = NSSavePanel()
  709. outputSavePanel.allowedFileTypes = ["pdf"]
  710. outputSavePanel.nameFieldStringValue = fileName
  711. let result = outputSavePanel.runModal()
  712. if result == .OK {
  713. let filePath = outputSavePanel.url?.path
  714. do {
  715. if self.translateFile == true {
  716. do {
  717. if self.translateResultPath.count > 0 {
  718. if FileManager.default.fileExists(atPath: filePath!) {
  719. do {
  720. try FileManager.default.removeItem(atPath: filePath!)
  721. // print("删除旧文件成功")
  722. } catch {
  723. // print("删除旧文件失败:\(error)")
  724. }
  725. }
  726. try FileManager.default.copyItem(atPath: self.translateResultPath, toPath: filePath!)
  727. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
  728. }
  729. } catch {
  730. }
  731. } else {
  732. let text = self.aiResultTextView.string
  733. self.createPDF(from: text, saveTo: filePath!)
  734. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: filePath!)])
  735. }
  736. KMFunctionGuideWindowController.setDidShowFor(.aiInfoResultSave)
  737. } catch {
  738. }
  739. }
  740. }
  741. func textDidChange(_ notification: Notification) {
  742. if let textView = notification.object as? NSTextView, textView == self.fileEmptyTextView {
  743. // 获取文本字段的当前字符数
  744. let currentText = textView.string
  745. let currentCount = currentText.count
  746. // 如果超过最大字符数,将文本截断为最大字符数,并设置回文本字段
  747. if currentCount > 2000 {
  748. let endIndex = currentText.index(currentText.startIndex, offsetBy: 2000)
  749. let truncatedText = String(currentText[..<endIndex])
  750. textView.string = truncatedText
  751. }
  752. }
  753. self.updateActionViewUI()
  754. }
  755. override func mouseDown(with event: NSEvent) {
  756. super.mouseDown(with: event)
  757. self.window?.makeFirstResponder(nil)
  758. }
  759. func createPDF(from text: String, saveTo path: String) {
  760. let attributedText = NSAttributedString(string: text)
  761. let pdfData = NSMutableData()
  762. let pdfConsumer = CGDataConsumer(data: pdfData)!
  763. var mediaBox = CGRect(x: 0, y: 0, width: 612, height: 792) // 设置页面尺寸,这里使用默认的美国信纸尺寸
  764. let pdfContext = CGContext(consumer: pdfConsumer, mediaBox: &mediaBox, nil)!
  765. pdfContext.beginPage(mediaBox: &mediaBox)
  766. pdfContext.textMatrix = .identity
  767. pdfContext.setShouldAntialias(true)
  768. let frame = mediaBox.insetBy(dx: 20, dy: 20) // 设置文字边距
  769. let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString)
  770. let framePath = CGPath(rect: frame, transform: nil)
  771. let frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedText.length), framePath, nil)
  772. CTFrameDraw(frameRef, pdfContext)
  773. pdfContext.endPage()
  774. pdfContext.closePDF()
  775. pdfData.write(toFile: path, atomically: true)
  776. print("PDF 文件已保存至:\(path)")
  777. }
  778. }