Skip to content

Commit 2b2870b

Browse files
committed
Add WordPressIntelligence module and enable locale support
1 parent ceec1fe commit 2b2870b

15 files changed

+74
-278
lines changed
Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import Foundation
22
import FoundationModels
33

4-
/// Service for AI-powered content generation and analysis features.
5-
///
6-
/// This service provides tag suggestions, post summaries, excerpt generation,
7-
/// and other intelligence features using Foundation Models (iOS 26+).
8-
public actor IntelligenceService {
4+
public enum IntelligenceService {
95
/// Maximum context size for language model sessions (in tokens).
106
///
117
/// A single token corresponds to three or four characters in languages like
@@ -36,33 +32,21 @@ public actor IntelligenceService {
3632
}
3733
}
3834

39-
public init() {}
40-
41-
// MARK: - Public API
42-
43-
/// Suggests tags for a WordPress post.
44-
@available(iOS 26, *)
45-
public func suggestTags(post: String, siteTags: [String] = [], postTags: [String] = []) async throws -> [String] {
46-
try await TagSuggestion().generate(post: post, siteTags: siteTags, postTags: postTags)
47-
}
48-
49-
/// Summarizes a support ticket to a short title.
50-
@available(iOS 26, *)
51-
public func summarizeSupportTicket(content: String) async throws -> String {
52-
try await SupportTicketSummary.execute(content: content)
53-
}
54-
55-
/// Extracts relevant text from post content (removes HTML, limits size).
56-
public nonisolated func extractRelevantText(from post: String, ratio: CGFloat = 0.6) -> String {
57-
Self.extractRelevantText(from: post, ratio: ratio)
58-
}
59-
60-
// MARK: - Shared Utilities
61-
6235
/// Extracts relevant text from post content, removing HTML and limiting size.
63-
public nonisolated static func extractRelevantText(from post: String, ratio: CGFloat = 0.6) -> String {
36+
static func extractRelevantText(from post: String, ratio: CGFloat = 0.6) -> String {
6437
let extract = try? ContentExtractor.extractRelevantText(from: post)
6538
let postSizeLimit = Double(IntelligenceService.contextSizeLimit) * ratio
6639
return String((extract ?? post).prefix(Int(postSizeLimit)))
6740
}
41+
42+
// As documented in https://developer.apple.com/documentation/foundationmodels/supporting-languages-and-locales-with-foundation-models?changes=_10_5#Use-Instructions-to-set-the-locale-and-language
43+
static func makeLocaleInstructions(for locale: Locale = Locale.current) -> String {
44+
if Locale.Language(identifier: "en_US").isEquivalent(to: locale.language) {
45+
// Skip the locale phrase for U.S. English.
46+
return ""
47+
} else {
48+
// Specify the person's locale with the exact phrase format.
49+
return "The person's locale is \(locale.identifier)."
50+
}
51+
}
6852
}

Modules/Sources/WordPressIntelligence/UseCases/ExcerptGeneration.swift renamed to Modules/Sources/WordPressIntelligence/UseCases/PostExcerptGenerator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import FoundationModels
77
/// length and writing style. Supports session-based usage (for UI with continuity)
88
/// and one-shot generation (for tests and background tasks).
99
@available(iOS 26, *)
10-
public struct ExcerptGeneration {
10+
public struct PostExcerptGenerator {
1111
public var length: ContentLength
1212
public var style: WritingStyle
1313
public var options: GenerationOptions
@@ -51,7 +51,7 @@ public struct ExcerptGeneration {
5151
- TARGET_LENGTH: MANDATORY sentence count (primary) and word count (secondary) for each excerpt
5252
- GENERATION_STYLE: the writing style to follow
5353
54-
\(PromptHelper.makeLocaleInstructions())
54+
\(IntelligenceService.makeLocaleInstructions())
5555
5656
**CRITICAL Requirements (MUST be followed exactly)**
5757
1. ⚠️ LANGUAGE: Generate excerpts in the SAME language as POST_CONTENT. NO translation. NO defaulting to English. Match input language EXACTLY.

Modules/Sources/WordPressIntelligence/UseCases/PostSummary.swift renamed to Modules/Sources/WordPressIntelligence/UseCases/PostSummaryGenerator.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import FoundationModels
1212
/// let result = try await summary.generate(content: postContent)
1313
/// ```
1414
@available(iOS 26, *)
15-
public struct PostSummary {
15+
public struct PostSummaryGenerator {
1616
public var options: GenerationOptions
1717

1818
public init(options: GenerationOptions = GenerationOptions(temperature: 0.3)) {
@@ -47,7 +47,7 @@ public struct PostSummary {
4747
Generate a concise summary that captures the main points and key information.
4848
The summary should be clear, informative, and written in a neutral tone.
4949
50-
\(PromptHelper.makeLocaleInstructions())
50+
\(IntelligenceService.makeLocaleInstructions())
5151
5252
Do not include anything other than the summary in the response.
5353
"""
@@ -76,6 +76,6 @@ extension IntelligenceService {
7676
/// - Returns: A concise summary
7777
/// - Throws: If summarization fails
7878
public func summarize(content: String) async throws -> String {
79-
try await PostSummary().generate(content: content)
79+
try await PostSummaryGenerator().generate(content: content)
8080
}
8181
}

Modules/Sources/WordPressIntelligence/UseCases/SupportTicketSummary.swift

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import Foundation
2+
import FoundationModels
3+
4+
/// Support ticket summarization.
5+
///
6+
/// Generates short, concise titles (fewer than 10 words) for support
7+
/// conversations based on the opening message.
8+
@available(iOS 26, *)
9+
public enum SupportTicketSummaryGenerator {
10+
static func execute(content: String) async throws -> String {
11+
let instructions = """
12+
You are helping a user by summarizing their support request down to a single sentence
13+
with fewer than 10 words.
14+
15+
The summary should be clear, informative, and written in a neutral tone.
16+
You MUST generate the summary in the same language as the support request.
17+
18+
Do not include anything other than the summary in the response.
19+
"""
20+
21+
let session = LanguageModelSession(
22+
model: .init(guardrails: .permissiveContentTransformations),
23+
instructions: instructions
24+
)
25+
26+
let prompt = """
27+
Give me an appropriate conversation title for the following opening message of the conversation:
28+
29+
\(content)
30+
"""
31+
32+
return try await session.respond(
33+
to: prompt,
34+
generating: Result.self,
35+
options: GenerationOptions(temperature: 1.0)
36+
).content.title
37+
}
38+
39+
@Generable
40+
struct Result {
41+
@Guide(description: "The conversation title")
42+
var title: String
43+
}
44+
}

Modules/Sources/WordPressIntelligence/UseCases/TagSuggestion.swift renamed to Modules/Sources/WordPressIntelligence/UseCases/TagSuggestionGenerator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import WordPressShared
77
/// Generates relevant tags based on post content and existing site tags,
88
/// matching the language and formatting pattern of existing tags.
99
@available(iOS 26, *)
10-
public struct TagSuggestion {
10+
public struct TagSuggestionGenerator {
1111
public var options: GenerationOptions
1212

1313
public init(options: GenerationOptions = GenerationOptions(temperature: 0.2)) {
@@ -50,7 +50,7 @@ public struct TagSuggestion {
5050
- SITE_TAGS: case-sensitive comma-separated list of the existing tags used elsewhere on the site (not always relevant to the post)
5151
- EXISTING_POST_TAGS: tags already added to the post
5252
53-
\(PromptHelper.makeLocaleInstructions())
53+
\(IntelligenceService.makeLocaleInstructions())
5454
5555
**Steps**
5656
- 1. Identify the specific formatting pattern used (e.g., lowercase with underscores, capitalized words with spaces, etc)

Modules/Sources/WordPressIntelligence/Utilities/PromptHelper.swift

Lines changed: 0 additions & 14 deletions
This file was deleted.

Modules/Tests/WordPressIntelligenceTests/SummaryTestOutput.swift renamed to Modules/Tests/WordPressIntelligenceTests/Helpers/SummaryTestOutput.swift

File renamed without changes.

Modules/Tests/WordPressIntelligenceTests/Helpers/TestHelperLevenshteinDistanceTests.swift

Lines changed: 0 additions & 157 deletions
This file was deleted.

Modules/Tests/WordPressIntelligenceTests/Helpers/TestHelpers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ enum TestHelpers {
111111
static func printExcerptResults(
112112
_ title: String,
113113
excerpts: [String],
114-
generator: ExcerptGeneration,
114+
generator: PostExcerptGenerator,
115115
expectedLanguage: NLLanguage,
116116
duration: Duration
117117
) {

0 commit comments

Comments
 (0)