Ver código fonte

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 3 semanas atrás
pai
commit
a57976258d
1 arquivos alterados com 8 adições e 32 exclusões
  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 {
259 259
         mainOverlay.addArrangedSubview(chatStatusStack)
260 260
         mainOverlay.addArrangedSubview(listingsTopSpacer)
261 261
         mainOverlay.addArrangedSubview(chatScrollView)
262
+        mainOverlay.addArrangedSubview(jobListingsScrollView)
262 263
         mainOverlay.addArrangedSubview(searchBarShadowHost)
263 264
 
264 265
         contentStack.addArrangedSubview(sidebar)
@@ -291,10 +292,12 @@ final class DashboardView: NSView, NSTextFieldDelegate {
291 292
             searchBarShadowHost.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
292 293
             chatStatusStack.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
293 294
             chatScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
295
+            jobListingsScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
294 296
 
295 297
             jobListingsContainer.topAnchor.constraint(equalTo: jobListingsScrollView.contentView.topAnchor),
296 298
             jobListingsContainer.leadingAnchor.constraint(equalTo: jobListingsScrollView.contentView.leadingAnchor),
297 299
             jobListingsContainer.widthAnchor.constraint(equalTo: jobListingsScrollView.contentView.widthAnchor),
300
+            jobListingsScrollView.heightAnchor.constraint(greaterThanOrEqualToConstant: 200),
298 301
 
299 302
             greetingLabel.leadingAnchor.constraint(equalTo: mainOverlay.leadingAnchor, constant: 16),
300 303
             greetingLabel.trailingAnchor.constraint(equalTo: mainOverlay.trailingAnchor, constant: -16),
@@ -1209,7 +1212,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1209 1212
                 case .success(let output):
1210 1213
                     let normalizedJobs = self.normalizedJobs(output.jobs)
1211 1214
                     self.configureJobListings(normalizedJobs, noResultsForQuery: prompt)
1212
-                    let reply = self.makeAssistantSearchReply(query: prompt, jobs: normalizedJobs, jsonResult: output.rawJSON)
1215
+                    let reply = self.makeAssistantSearchReply(query: prompt, jobs: normalizedJobs)
1213 1216
                     self.chatMessages.append(ChatMessage(role: "assistant", content: reply))
1214 1217
                     self.appendChatBubble(text: reply, isUser: false)
1215 1218
                     self.chatStatusLabel.stringValue = "Ask for another job, company, or skill match"
@@ -1234,42 +1237,16 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1234 1237
         return trimmed.filter { !$0.title.isEmpty && !$0.description.isEmpty }
1235 1238
     }
1236 1239
 
1237
-    private func makeAssistantSearchReply(query: String, jobs: [JobListing], jsonResult: String) -> String {
1240
+    private func makeAssistantSearchReply(query: String, jobs: [JobListing]) -> String {
1238 1241
         if jobs.isEmpty {
1239
-            return """
1240
-            No jobs were found for "\(query)".
1241
-
1242
-            JSON result:
1243
-            \(jsonResult)
1244
-            """
1245
-        }
1246
-        let rows = jobs.prefix(8).enumerated().map { index, job in
1247
-            let fallback = "https://www.indeed.com/jobs?q=\(job.title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")"
1248
-            let link = (job.url?.isEmpty == false) ? job.url! : fallback
1249
-            let compactDescription = compactSingleLine(job.description, maxCharacters: 110)
1250
-            return "\(index + 1)) \(job.title) | \(compactDescription) | \(link)"
1242
+            return "No jobs were found for \"\(query)\". Try another title, skill, company, or location."
1251 1243
         }
1252 1244
         return """
1253 1245
         Found \(jobs.count) job result(s) for "\(query)".
1254
-
1255
-        Row-wise results:
1256
-        \(rows.joined(separator: "\n"))
1257
-
1258
-        JSON result:
1259
-        \(jsonResult)
1246
+        Each result is shown as a card with the role, job description, and an Apply button that opens the job link.
1260 1247
         """
1261 1248
     }
1262 1249
 
1263
-    private func compactSingleLine(_ text: String, maxCharacters: Int) -> String {
1264
-        let single = text
1265
-            .replacingOccurrences(of: "\n", with: " ")
1266
-            .replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
1267
-            .trimmingCharacters(in: .whitespacesAndNewlines)
1268
-        guard single.count > maxCharacters, maxCharacters > 1 else { return single }
1269
-        let end = single.index(single.startIndex, offsetBy: maxCharacters - 1)
1270
-        return String(single[..<end]) + "…"
1271
-    }
1272
-
1273 1250
     func controlTextDidBeginEditing(_ obj: Notification) {
1274 1251
         applySearchFieldInsertionPoint(obj.object)
1275 1252
         if (obj.object as? NSTextField) === jobKeywordsField {
@@ -1665,7 +1642,7 @@ private final class OpenAIJobSearchService {
1665 1642
                 let cleanedText = Self.extractJSONObject(from: text)
1666 1643
                 let jsonData = Data(cleanedText.utf8)
1667 1644
                 let jobsPayload = try JSONDecoder().decode(JobSearchResultsPayload.self, from: jsonData)
1668
-                completion(.success(JobSearchOutput(jobs: jobsPayload.jobs, rawJSON: cleanedText)))
1645
+                completion(.success(JobSearchOutput(jobs: jobsPayload.jobs)))
1669 1646
             } catch {
1670 1647
                 let rawBody = String(data: data, encoding: .utf8) ?? "<non-utf8 response>"
1671 1648
                 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 {
1772 1749
 
1773 1750
 private struct JobSearchOutput {
1774 1751
     let jobs: [JobListing]
1775
-    let rawJSON: String
1776 1752
 }
1777 1753
 
1778 1754
 private struct OpenAIAPIErrorResponse: Codable {