Просмотр исходного кода

Fix job search results visibility and simplify assistant response.

Render the listings scroll section in the main layout so result cards appear after search, and replace verbose row/JSON chat output with a concise card-focused summary.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 2 месяцев назад
Родитель
Сommit
a57976258d
1 измененных файлов с 8 добавлено и 32 удалено
  1. 8 32
      App for Indeed/Views/DashboardView.swift

+ 8 - 32
App for Indeed/Views/DashboardView.swift

@@ -259,6 +259,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         mainOverlay.addArrangedSubview(chatStatusStack)
         mainOverlay.addArrangedSubview(listingsTopSpacer)
         mainOverlay.addArrangedSubview(chatScrollView)
+        mainOverlay.addArrangedSubview(jobListingsScrollView)
         mainOverlay.addArrangedSubview(searchBarShadowHost)
 
         contentStack.addArrangedSubview(sidebar)
@@ -291,10 +292,12 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             searchBarShadowHost.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
             chatStatusStack.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
             chatScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
+            jobListingsScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
 
             jobListingsContainer.topAnchor.constraint(equalTo: jobListingsScrollView.contentView.topAnchor),
             jobListingsContainer.leadingAnchor.constraint(equalTo: jobListingsScrollView.contentView.leadingAnchor),
             jobListingsContainer.widthAnchor.constraint(equalTo: jobListingsScrollView.contentView.widthAnchor),
+            jobListingsScrollView.heightAnchor.constraint(greaterThanOrEqualToConstant: 200),
 
             greetingLabel.leadingAnchor.constraint(equalTo: mainOverlay.leadingAnchor, constant: 16),
             greetingLabel.trailingAnchor.constraint(equalTo: mainOverlay.trailingAnchor, constant: -16),
@@ -1209,7 +1212,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
                 case .success(let output):
                     let normalizedJobs = self.normalizedJobs(output.jobs)
                     self.configureJobListings(normalizedJobs, noResultsForQuery: prompt)
-                    let reply = self.makeAssistantSearchReply(query: prompt, jobs: normalizedJobs, jsonResult: output.rawJSON)
+                    let reply = self.makeAssistantSearchReply(query: prompt, jobs: normalizedJobs)
                     self.chatMessages.append(ChatMessage(role: "assistant", content: reply))
                     self.appendChatBubble(text: reply, isUser: false)
                     self.chatStatusLabel.stringValue = "Ask for another job, company, or skill match"
@@ -1234,42 +1237,16 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         return trimmed.filter { !$0.title.isEmpty && !$0.description.isEmpty }
     }
 
-    private func makeAssistantSearchReply(query: String, jobs: [JobListing], jsonResult: String) -> String {
+    private func makeAssistantSearchReply(query: String, jobs: [JobListing]) -> String {
         if jobs.isEmpty {
-            return """
-            No jobs were found for "\(query)".
-
-            JSON result:
-            \(jsonResult)
-            """
-        }
-        let rows = jobs.prefix(8).enumerated().map { index, job in
-            let fallback = "https://www.indeed.com/jobs?q=\(job.title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")"
-            let link = (job.url?.isEmpty == false) ? job.url! : fallback
-            let compactDescription = compactSingleLine(job.description, maxCharacters: 110)
-            return "\(index + 1)) \(job.title) | \(compactDescription) | \(link)"
+            return "No jobs were found for \"\(query)\". Try another title, skill, company, or location."
         }
         return """
         Found \(jobs.count) job result(s) for "\(query)".
-
-        Row-wise results:
-        \(rows.joined(separator: "\n"))
-
-        JSON result:
-        \(jsonResult)
+        Each result is shown as a card with the role, job description, and an Apply button that opens the job link.
         """
     }
 
-    private func compactSingleLine(_ text: String, maxCharacters: Int) -> String {
-        let single = text
-            .replacingOccurrences(of: "\n", with: " ")
-            .replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
-            .trimmingCharacters(in: .whitespacesAndNewlines)
-        guard single.count > maxCharacters, maxCharacters > 1 else { return single }
-        let end = single.index(single.startIndex, offsetBy: maxCharacters - 1)
-        return String(single[..<end]) + "…"
-    }
-
     func controlTextDidBeginEditing(_ obj: Notification) {
         applySearchFieldInsertionPoint(obj.object)
         if (obj.object as? NSTextField) === jobKeywordsField {
@@ -1665,7 +1642,7 @@ private final class OpenAIJobSearchService {
                 let cleanedText = Self.extractJSONObject(from: text)
                 let jsonData = Data(cleanedText.utf8)
                 let jobsPayload = try JSONDecoder().decode(JobSearchResultsPayload.self, from: jsonData)
-                completion(.success(JobSearchOutput(jobs: jobsPayload.jobs, rawJSON: cleanedText)))
+                completion(.success(JobSearchOutput(jobs: jobsPayload.jobs)))
             } catch {
                 let rawBody = String(data: data, encoding: .utf8) ?? "<non-utf8 response>"
                 let message = "The API response could not be parsed as job JSON. Raw response: \(rawBody.prefix(600))"
@@ -1772,7 +1749,6 @@ private struct JobSearchResultsPayload: Codable {
 
 private struct JobSearchOutput {
     let jobs: [JobListing]
-    let rawJSON: String
 }
 
 private struct OpenAIAPIErrorResponse: Codable {