Skip to content

Commit 5ba9612

Browse files
committed
Update the tests
1 parent 7b4abe2 commit 5ba9612

File tree

9 files changed

+74
-88
lines changed

9 files changed

+74
-88
lines changed

Modules/Sources/WordPressIntelligence/IntelligenceService.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public actor IntelligenceService {
4848

4949
/// Summarizes a WordPress post.
5050
@available(iOS 26, *)
51-
public func summarizePost(content: String) -> LanguageModelSession.ResponseStream<String> {
52-
PostSummary.execute(content: content)
51+
public func summarizePost(content: String) async throws -> String {
52+
try await PostSummary.execute(content: content)
5353
}
5454

5555
/// Summarizes a support ticket to a short title.
@@ -67,7 +67,7 @@ public actor IntelligenceService {
6767

6868
/// Extracts relevant text from post content, removing HTML and limiting size.
6969
public nonisolated static func extractRelevantText(from post: String, ratio: CGFloat = 0.6) -> String {
70-
let extract = try? IntelligenceUtilities.extractRelevantText(from: post)
70+
let extract = try? ContentExtractor.extractRelevantText(from: post)
7171
let postSizeLimit = Double(IntelligenceService.contextSizeLimit) * ratio
7272
return String((extract ?? post).prefix(Int(postSizeLimit)))
7373
}

Modules/Sources/WordPressIntelligence/UseCases/ExcerptGeneration.swift

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import Foundation
22
import FoundationModels
33

4-
/// Excerpt generation for WordPress posts.
5-
///
6-
/// Generates multiple excerpt variations for blog posts with customizable
7-
/// length and writing style. Supports session-based usage (for UI with continuity)
8-
/// and one-shot generation (for tests and background tasks).
9-
@available(iOS 26, *)
4+
/// Excerpt generation for WordPress posts.
5+
///
6+
/// Generates multiple excerpt variations for blog posts with customizable
7+
/// length and writing style. Supports session-based usage (for UI with continuity)
8+
/// and one-shot generation (for tests and background tasks).
9+
@available(iOS 26, *)
1010
public struct ExcerptGeneration {
1111
public let length: ContentLength
1212
public let style: WritingStyle
@@ -18,7 +18,20 @@ public struct ExcerptGeneration {
1818
self.options = options
1919
}
2020

21-
// MARK: - Instance Methods
21+
/// Generates excerpts with this configuration.
22+
public func generate(for content: String) async throws -> [String] {
23+
let extractedContent = IntelligenceService.extractRelevantText(from: content)
24+
let session = makeSession()
25+
26+
let response = try await session.respond(
27+
to: makePrompt(content: extractedContent),
28+
generating: Result.self,
29+
options: options
30+
)
31+
32+
return response.content.excerpts
33+
}
34+
2235

2336
/// Creates a language model session configured for excerpt generation.
2437
public func makeSession() -> LanguageModelSession {
@@ -32,57 +45,41 @@ public struct ExcerptGeneration {
3245
public func makePrompt(content: String) -> String {
3346
"""
3447
Generate three different excerpts for the given post and parameters
35-
48+
3649
GENERATED_CONTENT_LENGTH: \(length.promptModifier)
37-
50+
3851
GENERATION_STYLE: \(style.promptModifier)
39-
52+
4053
POST_CONTENT: '''
4154
\(content)
4255
"""
4356
}
4457

45-
/// Generates excerpts with this configuration.
46-
public func generate(content: String) async throws -> [String] {
47-
let extractedContent = IntelligenceService.extractRelevantText(from: content)
48-
let session = makeSession()
49-
50-
let response = try await session.respond(
51-
to: makePrompt(content: extractedContent),
52-
generating: Result.self,
53-
options: options
54-
)
55-
56-
return response.content.excerpts
57-
}
58-
59-
// MARK: - Building Blocks (for UI with session continuity)
60-
6158
/// Instructions for the language model session.
6259
public static var instructions: String {
63-
"""
64-
Generate exactly 3 excerpts for the blog post and follow the instructions from the prompt regarding the length and the style.
65-
66-
Generate excerpts in the same language as the POST_CONTENT.
67-
68-
**Paramters**
69-
- POST_CONTENT: contents of the post (HTML or plain text)
70-
- GENERATED_CONTENT_LENGTH: the length of the generated content
71-
- GENERATION_STYLE: the writing style to follow
72-
73-
**Requirements**
74-
- Each excerpt must follow the provided GENERATED_CONTENT_LENGTH and use GENERATION_STYLE
75-
76-
**Excerpt best practices**
77-
- Follow the best practices for post excerpts esteblished in the WordPress ecosystem
78-
- Include the post's main value proposition
79-
- Use active voice (avoid "is", "are", "was", "were" when possible)
80-
- End with implicit promise of more information
81-
- Do not use ellipsis (...) at the end
82-
- Focus on value, not summary
83-
- Include strategic keywords naturally
84-
- Write independently from the introduction – excerpt shouldn't just duplicate your opening paragraph. While your introduction eases readers into the topic, your excerpt needs to work as standalone copy that makes sense out of context—whether it appears in search results, social media cards, or email newsletters.
85-
"""
60+
"""
61+
Generate exactly 3 excerpts for the blog post and follow the instructions from the prompt regarding the length and the style.
62+
63+
Generate excerpts in the same language as the POST_CONTENT.
64+
65+
**Paramters**
66+
- POST_CONTENT: contents of the post (HTML or plain text)
67+
- GENERATED_CONTENT_LENGTH: the length of the generated content
68+
- GENERATION_STYLE: the writing style to follow
69+
70+
**Requirements**
71+
- Each excerpt must follow the provided GENERATED_CONTENT_LENGTH and use GENERATION_STYLE
72+
73+
**Excerpt best practices**
74+
- Follow the best practices for post excerpts esteblished in the WordPress ecosystem
75+
- Include the post's main value proposition
76+
- Use active voice (avoid "is", "are", "was", "were" when possible)
77+
- End with implicit promise of more information
78+
- Do not use ellipsis (...) at the end
79+
- Focus on value, not summary
80+
- Include strategic keywords naturally
81+
- Write independently from the introduction – excerpt shouldn't just duplicate your opening paragraph. While your introduction eases readers into the topic, your excerpt needs to work as standalone copy that makes sense out of context—whether it appears in search results, social media cards, or email newsletters.
82+
"""
8683
}
8784

8885
/// Prompt for generating additional excerpt options.

Modules/Sources/WordPressIntelligence/UseCases/PostSummary.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ extension IntelligenceService {
88
/// Generates concise summaries that capture the main points and key information
99
/// from WordPress post content in the same language as the source.
1010
public enum PostSummary {
11-
static func execute(content: String) -> LanguageModelSession.ResponseStream<String> {
11+
static func execute(content: String) async throws -> String {
1212
let content = IntelligenceService.extractRelevantText(from: content, ratio: 0.8)
1313

1414
let instructions = """
@@ -31,7 +31,7 @@ extension IntelligenceService {
3131
\(content)
3232
"""
3333

34-
return session.streamResponse(to: prompt)
34+
return try await session.respond(to: prompt).content
3535
}
3636
}
3737
}

Modules/Sources/WordPressIntelligence/IntelligenceUtilities.swift renamed to Modules/Sources/WordPressIntelligence/Utilities/ContentExtractor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import SwiftSoup
33

4-
public struct IntelligenceUtilities {
4+
public enum ContentExtractor {
55
/// Extracts semantically meaningful content from HTML for LLM processing.
66
///
77
/// Optimized for language models by:

Modules/Tests/WordPressIntelligenceTests/IntelligenceUtilitiesTests.swift renamed to Modules/Tests/WordPressIntelligenceTests/ContentExtractorTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Testing
22
@testable import WordPressIntelligence
33

4-
struct IntelligenceUtilitiesTests {
4+
struct ContentExtractorTests {
55
@Test func extractRelevantText() throws {
6-
let text = try IntelligenceUtilities.extractRelevantText(from: IntelligenceUtilities.post)
6+
let text = try ContentExtractor.extractRelevantText(from: ContentExtractor.post)
77

88
#expect(text == """
99
<h1>The Art of Making Perfect Sourdough Bread at Home</h1>
@@ -52,7 +52,7 @@ struct IntelligenceUtilitiesTests {
5252

5353
/// Blockquote contain nested block and the implementation should account for that.
5454
@Test func blockquotes() throws {
55-
let text = try IntelligenceUtilities.extractRelevantText(from: """
55+
let text = try ContentExtractor.extractRelevantText(from: """
5656
<!-- wp:paragraph -->
5757
<p>Welcome to <strong><em>WordPress</em></strong>! This is your first post. Edit or delete it to take the first step in your blogging journey.</p>
5858
<!-- /wp:paragraph -->
@@ -71,13 +71,13 @@ struct IntelligenceUtilitiesTests {
7171
}
7272

7373
@Test func extractRelevantTextFromPlainText() throws {
74-
let text = try IntelligenceUtilities.extractRelevantText(from: "This is a plain text post")
74+
let text = try ContentExtractor.extractRelevantText(from: "This is a plain text post")
7575

7676
#expect(text == "This is a plain text post")
7777
}
7878
}
7979

80-
extension IntelligenceUtilities {
80+
extension ContentExtractor {
8181
static let post = """
8282
<!-- wp:heading {"level":1} -->
8383
<h1>The Art of Making Perfect Sourdough Bread at Home</h1>

Modules/Tests/WordPressIntelligenceTests/ExcerptGenerationTests.swift

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,8 @@ struct IntelligenceExcerptGenerationTests {
4848
@available(iOS 26, *)
4949
@Test(arguments: ExcerptTestCase.allCases)
5050
func excerptGeneration(testCase: ExcerptTestCase) async throws {
51-
let excerpts = try await generateExcerpts(
52-
content: testCase.testData.content,
53-
length: testCase.length,
54-
style: testCase.style
55-
)
51+
let generator = ExcerptGeneration(length: testCase.length, style: testCase.style)
52+
let excerpts = try await generator.generate(for: testCase.testData.content)
5653

5754
IntelligenceTestHelpers.printExcerptResults(
5855
testCase.testDescription,
@@ -72,7 +69,7 @@ struct IntelligenceExcerptGenerationTests {
7269
let testData = Data.spanishPost
7370
var rows: [[String]] = []
7471

75-
for style in IntelligenceService.ExcerptGeneration.Style.allCases {
72+
for style in WritingStyle.allCases {
7673
let excerpts = try await generateExcerpts(
7774
content: testData.content,
7875
length: .medium,
@@ -104,7 +101,7 @@ struct IntelligenceExcerptGenerationTests {
104101
let testData = Data.englishTechPost
105102
var rows: [[String]] = []
106103

107-
for length in IntelligenceService.ExcerptGeneration.Length.allCases {
104+
for length in ContentLength.allCases {
108105
let excerpts = try await generateExcerpts(
109106
content: testData.content,
110107
length: length,
@@ -207,20 +204,20 @@ struct IntelligenceExcerptGenerationTests {
207204
@available(iOS 26, *)
208205
private func generateExcerpts(
209206
content: String,
210-
length: IntelligenceService.ExcerptGeneration.Length,
211-
style: IntelligenceService.ExcerptGeneration.Style
207+
length: ContentLength,
208+
style: WritingStyle
212209
) async throws -> [String] {
213-
let generator = IntelligenceService.ExcerptGeneration(length: length, style: style)
214-
return try await generator.generate(content: content)
210+
let generator = ExcerptGeneration(length: length, style: style)
211+
return try await generator.generate(for: content)
215212
}
216213
}
217214

218215
// MARK: - Test Cases
219216

220217
struct ExcerptTestCase: CustomTestStringConvertible {
221218
let testData: TestContent
222-
let length: IntelligenceService.ExcerptGeneration.Length
223-
let style: IntelligenceService.ExcerptGeneration.Style
219+
let length: ContentLength
220+
let style: WritingStyle
224221

225222
var testDescription: String {
226223
"\(testData.title) - \(length.displayName) \(style.displayName)"

Modules/Tests/WordPressIntelligenceTests/IntelligencePostSummaryTests.swift

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,8 @@ struct IntelligencePostSummaryTests {
9999
@available(iOS 26, *)
100100
private func summarizePost(content: String) async throws -> String {
101101
let service = IntelligenceService()
102-
var summary = ""
103-
104-
for try await chunk in await service.summarizePost(content: content) {
105-
summary = chunk.content
106-
print(chunk.content, terminator: "")
107-
}
108-
102+
let summary = try await service.summarizePost(content: content)
103+
print(summary)
109104
return summary
110105
}
111106
}

Modules/Tests/WordPressIntelligenceTests/IntelligenceServiceTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct IntelligenceServiceTests {
77
func suggestTags() async throws {
88
let tags = try await IntelligenceService()
99
.suggestTags(
10-
post: IntelligenceUtilities.post,
10+
post: ContentExtractor.post,
1111
siteTags: ["cooking", "healthy-foods"]
1212
)
1313
print(tags)

WordPress/Classes/ViewRelated/Reader/Views/ReaderSummarizePostView.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import SwiftUI
22
import WordPressUI
33
import WordPressData
4-
import FoundationModels
54

65
@available(iOS 26, *)
76
struct ReaderSummarizePostView: View {
@@ -72,13 +71,11 @@ struct ReaderSummarizePostView: View {
7271

7372
do {
7473
let content = post.content ?? ""
75-
let stream = await IntelligenceService().summarizePost(content: content)
74+
let result = try await IntelligenceService().summarizePost(content: content)
7675

77-
for try await result in stream {
78-
guard !Task.isCancelled else { return }
79-
withAnimation(.smooth) {
80-
summary = result.content
81-
}
76+
guard !Task.isCancelled else { return }
77+
withAnimation(.smooth) {
78+
summary = result
8279
}
8380
} catch {
8481
guard !Task.isCancelled else { return }

0 commit comments

Comments
 (0)