Skip to content

Commit

Permalink
Introducing Periphery (#58)
Browse files Browse the repository at this point in the history
# Introducing Periphery

## ♻️ Current situation & Problem
- There was no tool for detecting unused code in the specified target.
- The `build-and-test` workflow contains jobs that are outside its
intended scope.
- Merging #53 left some code unused and with unnecessary access
modifiers.
## ⚙️ Release Notes 
- [Periphery](https://github.com/peripheryapp/periphery) will scan the
specified target for unused code. This is the initial step towards
addressing #56.
- The CI pipeline is now split into two distinct workflows:
`build-and-test` jobs for building and running the tests, and
`static-analysis` jobs for code quality checks.
- Resolved `Periphery` warnings.

### Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
jdisho authored Jan 23, 2025
1 parent 5a3b793 commit 7b5486f
Show file tree
Hide file tree
Showing 20 changed files with 110 additions and 161 deletions.
17 changes: 1 addition & 16 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,6 @@ on:
workflow_call:

jobs:
reuse_action:
name: REUSE Compliance Check
uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
swiftlint:
name: SwiftLint
uses: StanfordBDHG/.github/.github/workflows/swiftlint.yml@v2
codeql:
name: CodeQL
uses: StanfordBDHG/.github/.github/workflows/xcodebuild-or-fastlane.yml@v2
with:
codeql: true
fastlanelane: codeql
permissions:
security-events: write
actions: read
buildandtest:
name: Build and Test
uses: StanfordBDHG/.github/.github/workflows/xcodebuild-or-fastlane.yml@v2
Expand All @@ -43,4 +28,4 @@ jobs:
with:
coveragereports: LLMonFHIR.xcresult
secrets:
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
42 changes: 42 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# This source file is part of the Stanford LLM on FHIR project
#
# SPDX-FileCopyrightText: 2025 Stanford University
#
# SPDX-License-Identifier: MIT
#

name: Static Analysis

on:
pull_request:
workflow_dispatch:
workflow_call:

jobs:
reuse_action:
name: REUSE Compliance Check
uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
permissions:
contents: read
swiftlint:
name: SwiftLint
uses: StanfordBDHG/.github/.github/workflows/swiftlint.yml@v2
permissions:
contents: read
periphery:
name: Periphery
uses: StanfordBDHG/.github/.github/workflows/periphery.yml@v2
permissions:
contents: read
with:
runsonlabels: '["macOS", "self-hosted"]'
codeql:
name: CodeQL
uses: StanfordBDHG/.github/.github/workflows/xcodebuild-or-fastlane.yml@v2
with:
codeql: true
fastlanelane: codeql
permissions:
security-events: write
actions: read
11 changes: 11 additions & 0 deletions .periphery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#
# This source file is part of the Stanford LLM on FHIR project
#
# SPDX-FileCopyrightText: 2025 Stanford University
#
# SPDX-License-Identifier: MIT
#

project: LLMonFHIR.xcodeproj
schemes:
- LLMonFHIR
8 changes: 0 additions & 8 deletions LLMonFHIR.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
2FE5DC3A29EDD7CA004B9AB4 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3429EDD7CA004B9AB4 /* Welcome.swift */; };
2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */; };
2FE5DC4129EDD7EE004B9AB4 /* StorageKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */; };
2FE5DC4629EDD7F2004B9AB4 /* Bundle+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */; };
2FE5DC4729EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */; };
2FE5DC7229EDD8D3004B9AB4 /* SpeziHealthKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC7129EDD8D3004B9AB4 /* SpeziHealthKit */; };
2FE5DC8129EDD91D004B9AB4 /* SpeziOnboarding in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */; };
Expand All @@ -39,7 +38,6 @@
44E18E8E2CEBEC9500829A26 /* SpeziLLMLocalDownload in Frameworks */ = {isa = PBXBuildFile; productRef = 44E18E8D2CEBEC9500829A26 /* SpeziLLMLocalDownload */; };
44E18E902CEBEC9500829A26 /* SpeziLLMOpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = 44E18E8F2CEBEC9500829A26 /* SpeziLLMOpenAI */; };
44E18E932CEBF29200829A26 /* SpeziLocalStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 44E18E922CEBF29200829A26 /* SpeziLocalStorage */; };
44E18E952CEBFD3C00829A26 /* InterpretationModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E18E942CEBFD3A00829A26 /* InterpretationModelType.swift */; };
44E55E9E2CEBC191008A7BD3 /* FHIRGetResourceLLMFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E55E802CEBC191008A7BD3 /* FHIRGetResourceLLMFunction.swift */; };
44E55E9F2CEBC191008A7BD3 /* FHIRResourceProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E55E872CEBC191008A7BD3 /* FHIRResourceProcessor.swift */; };
44E55EA02CEBC191008A7BD3 /* InspectResourceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E55E982CEBC191008A7BD3 /* InspectResourceView.swift */; };
Expand Down Expand Up @@ -115,9 +113,7 @@
2FE5DC3429EDD7CA004B9AB4 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = "<group>"; };
2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = "<group>"; };
2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageKeys.swift; sourceTree = "<group>"; };
2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Image.swift"; sourceTree = "<group>"; };
2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CodableArray+RawRepresentable.swift"; sourceTree = "<group>"; };
44E18E942CEBFD3A00829A26 /* InterpretationModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterpretationModelType.swift; sourceTree = "<group>"; };
44E55E802CEBC191008A7BD3 /* FHIRGetResourceLLMFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FHIRGetResourceLLMFunction.swift; sourceTree = "<group>"; };
44E55E812CEBC191008A7BD3 /* FHIRMultipleResourceInterpreter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FHIRMultipleResourceInterpreter.swift; sourceTree = "<group>"; };
44E55E822CEBC191008A7BD3 /* MultipleResourcesChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleResourcesChatView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -267,7 +263,6 @@
44E55E8D2CEBC191008A7BD3 /* Binding+Negate.swift */,
44E55E8E2CEBC191008A7BD3 /* FHIRResource+Identifier.swift */,
44E55E8F2CEBC191008A7BD3 /* FHIRStore+Interpretation.swift */,
2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */,
2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */,
);
path = Helper;
Expand All @@ -294,7 +289,6 @@
44E55E862CEBC191008A7BD3 /* FHIRInterpretation */ = {
isa = PBXGroup;
children = (
44E18E942CEBFD3A00829A26 /* InterpretationModelType.swift */,
44E55E832CEBC191008A7BD3 /* MultipleResources */,
44E55E852CEBC191008A7BD3 /* SingleResource */,
);
Expand Down Expand Up @@ -610,7 +604,6 @@
44E55EA52CEBC191008A7BD3 /* FHIRStore+Interpretation.swift in Sources */,
44E55EA62CEBC191008A7BD3 /* MultipleResourcesChatView.swift in Sources */,
44E55EA72CEBC191008A7BD3 /* FHIRResource+Identifier.swift in Sources */,
44E18E952CEBFD3C00829A26 /* InterpretationModelType.swift in Sources */,
44E55EA82CEBC191008A7BD3 /* FHIRResourceInterpreter.swift in Sources */,
44E55EA92CEBC191008A7BD3 /* FHIRResourceSummaryView.swift in Sources */,
44E55EAA2CEBC191008A7BD3 /* FHIRResourcesView.swift in Sources */,
Expand All @@ -623,7 +616,6 @@
2FE5DC4729EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift in Sources */,
2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */,
97B6C1A52B7F382C0092B0F4 /* FHIRResourcesInstructionsView.swift in Sources */,
2FE5DC4629EDD7F2004B9AB4 /* Bundle+Image.swift in Sources */,
2F4E23832989D51F0013F3D9 /* LLMonFHIRTestingSetup.swift in Sources */,
2FD8E8272A1AAD9B00357F4E /* LLMonFHIRStandard.swift in Sources */,
2F5E32BD297E05EA003432F8 /* LLMonFHIRDelegate.swift in Sources */,
Expand Down
8 changes: 4 additions & 4 deletions LLMonFHIR/FHIR Views/FHIRResourcesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import SwiftUI
/// }
/// }
/// ```
public struct FHIRResourcesView<ContentView: View, ActionView: View>: View {
struct FHIRResourcesView<ContentView: View, ActionView: View>: View {
@Environment(FHIRStore.self) private var fhirStore
@State private var searchText = ""

Expand All @@ -46,7 +46,7 @@ public struct FHIRResourcesView<ContentView: View, ActionView: View>: View {
private let actionView: ActionView


public var body: some View {
var body: some View {
List {
Section {
contentView
Expand Down Expand Up @@ -93,7 +93,7 @@ public struct FHIRResourcesView<ContentView: View, ActionView: View>: View {
/// - navigationTitle: The localized title displayed for purposes of navigation.
/// - contentView: A custom content `View` that is displayed as the first `Section` of the `List`.
/// - actionView: A custom action `View` that is displayed as the second `Section` of the `List`. Only shown if no search `String` is present.
public init(
init(
navigationTitle: LocalizedStringResource,
@ViewBuilder contentView: () -> ContentView = { EmptyView() },
@ViewBuilder _ actionView: () -> ActionView = { EmptyView() }
Expand All @@ -110,7 +110,7 @@ public struct FHIRResourcesView<ContentView: View, ActionView: View>: View {
/// - contentView: A custom content `View` that is displayed as the first `Section` of the `List`.
/// - actionView: A custom action `View` that is displayed as the second `Section` of the `List`. Only shown if no search `String` is present.
@_disfavoredOverload
public init<Title: StringProtocol>(
init<Title: StringProtocol>(
navigationTitle: Title,
@ViewBuilder contentView: () -> ContentView = { EmptyView() },
@ViewBuilder _ actionView: () -> ActionView = { EmptyView() }
Expand Down
23 changes: 0 additions & 23 deletions LLMonFHIR/FHIRInterpretation/InterpretationModelType.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private enum FHIRMultipleResourceInterpreterConstants {

/// Used to interpret multiple FHIR resources via a chat-based interface with an LLM.
@Observable
public class FHIRMultipleResourceInterpreter {
class FHIRMultipleResourceInterpreter {
static let logger = Logger(subsystem: "edu.stanford.spezi.fhir", category: "SpeziFHIRLLM")

private let localStorage: LocalStorage
Expand Down Expand Up @@ -102,7 +102,7 @@ public class FHIRMultipleResourceInterpreter {

/// Change the `LLMSchema` used by the ``FHIRMultipleResourceInterpreter``.
@MainActor
public func changeLLMSchema(
func changeLLMSchema(
openAIModel model: LLMOpenAIModelType,
resourceCountLimit: Int,
resourceSummary: FHIRResourceSummary,
Expand Down Expand Up @@ -135,7 +135,7 @@ extension FHIRPrompt {
/// Prompt used to interpret multiple FHIR resources
///
/// This prompt is used by the ``FHIRMultipleResourceInterpreter``.
public static let interpretMultipleResources: FHIRPrompt = {
static let interpretMultipleResources: FHIRPrompt = {
FHIRPrompt(
storageKey: "prompt.interpretMultipleResources",
localizedDescription: String(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import SpeziViews
import SwiftUI


public struct MultipleResourcesChatView: View {
struct MultipleResourcesChatView: View {
@Environment(FHIRMultipleResourceInterpreter.self) private var multipleResourceInterpreter
@Environment(\.dismiss) private var dismiss

@Binding private var textToSpeech: Bool
private let navigationTitle: Text


public var body: some View {
var body: some View {
@Bindable var multipleResourceInterpreter = multipleResourceInterpreter
NavigationStack {
Group {
Expand Down Expand Up @@ -88,25 +88,11 @@ public struct MultipleResourcesChatView: View {
/// - Parameters:
/// - navigationTitle: The localized title displayed for purposes of navigation.
/// - textToSpeech: Indicates if the output of the LLM is converted to speech and outputted to the user.
public init(
init(
navigationTitle: LocalizedStringResource,
textToSpeech: Binding<Bool>
) {
self.navigationTitle = Text(navigationTitle)
self._textToSpeech = textToSpeech
}

/// Creates a ``MultipleResourcesChatView`` displaying a Spezi `Chat` with all available FHIR resources via a Spezi LLM..
///
/// - Parameters:
/// - navigationTitle: The title displayed for purposes of navigation.
/// - textToSpeech: Indicates if the output of the LLM is converted to speech and outputted to the user.
@_disfavoredOverload
public init<Title: StringProtocol>(
navigationTitle: Title,
textToSpeech: Binding<Bool>
) {
self.navigationTitle = Text(verbatim: String(navigationTitle))
self._textToSpeech = textToSpeech
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import SpeziLocalStorage

/// Responsible for interpreting FHIR resources.
@Observable
public final class FHIRResourceInterpreter: Sendable {
final class FHIRResourceInterpreter: Sendable {
private let resourceProcessor: FHIRResourceProcessor<String>


/// - Parameters:
/// - localStorage: Local storage module that needs to be passed to the ``FHIRResourceInterpreter`` to allow it to cache interpretations.
/// - openAIModel: OpenAI module that needs to be passed to the ``FHIRResourceInterpreter`` to allow it to retrieve interpretations.
public init(localStorage: LocalStorage, llmRunner: LLMRunner, llmSchema: any LLMSchema) {
init(localStorage: LocalStorage, llmRunner: LLMRunner, llmSchema: any LLMSchema) {
self.resourceProcessor = FHIRResourceProcessor(
localStorage: localStorage,
llmRunner: llmRunner,
Expand All @@ -39,23 +39,23 @@ public final class FHIRResourceInterpreter: Sendable {
/// - forceReload: A boolean value that indicates whether to reload and reprocess the resource.
/// - Returns: An asynchronous `String` representing the interpretation of the resource.
@discardableResult
public func interpret(resource: FHIRResource, forceReload: Bool = false) async throws -> String {
func interpret(resource: FHIRResource, forceReload: Bool = false) async throws -> String {
try await resourceProcessor.process(resource: resource, forceReload: forceReload)
}

/// Retrieve the cached interpretation of a given FHIR resource. Returns a human-readable interpretation or `nil` if it is not present.
///
/// - Parameter resource: The resource where the cached interpretation should be loaded from.
/// - Returns: The cached interpretation. Returns `nil` if the resource is not present.
public func cachedInterpretation(forResource resource: FHIRResource) -> String? {
func cachedInterpretation(forResource resource: FHIRResource) -> String? {
resourceProcessor.results[resource.id]
}

/// Adjust the LLM schema used by the ``FHIRResourceInterpreter``.
///
/// - Parameters:
/// - schema: The to-be-used `LLMSchema`.
public func changeLLMSchema<Schema: LLMSchema>(to schema: Schema) {
func changeLLMSchema<Schema: LLMSchema>(to schema: Schema) {
self.resourceProcessor.llmSchema = schema
}
}
Expand All @@ -65,7 +65,7 @@ extension FHIRPrompt {
/// Prompt used to interpret FHIR resources
///
/// This prompt is used by the ``FHIRResourceInterpreter``.
public static let interpretation: FHIRPrompt = {
static let interpretation: FHIRPrompt = {
FHIRPrompt(
storageKey: "prompt.interpretation",
localizedDescription: String(
Expand Down
13 changes: 7 additions & 6 deletions LLMonFHIR/FHIRInterpretationModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import SpeziLocalStorage
import SwiftUI


public class FHIRInterpretationModule: Module, DefaultInitializable {
public enum Defaults {
public static var llmSchema: LLMOpenAISchema {
// periphery:ignore - Properties are used through dependency injection and @Model configuration in `configure()`
class FHIRInterpretationModule: Module, DefaultInitializable {
enum Defaults {
static var llmSchema: LLMOpenAISchema {
.init(
parameters: .init(
modelType: .gpt4_turbo,
Expand All @@ -43,7 +44,7 @@ public class FHIRInterpretationModule: Module, DefaultInitializable {


/// - Warning: Ensure that passed LLM schema's don't contain a system prompt! This will be configured by the ``FHIRInterpretationModule``.
public init<SummaryLLM: LLMSchema, InterpretationLLM: LLMSchema>(
init<SummaryLLM: LLMSchema, InterpretationLLM: LLMSchema>(
summaryLLMSchema: SummaryLLM = Defaults.llmSchema,
interpretationLLMSchema: InterpretationLLM = Defaults.llmSchema, // swiftlint:disable:this function_default_parameter_at_end
multipleResourceInterpretationOpenAIModel: LLMOpenAIModelType, // swiftlint:disable:this identifier_name
Expand All @@ -58,7 +59,7 @@ public class FHIRInterpretationModule: Module, DefaultInitializable {
}


public required convenience init() {
required convenience init() {
self.init(
summaryLLMSchema: Defaults.llmSchema,
interpretationLLMSchema: Defaults.llmSchema,
Expand All @@ -67,7 +68,7 @@ public class FHIRInterpretationModule: Module, DefaultInitializable {
}


public func configure() {
func configure() {
resourceSummary = FHIRResourceSummary(
localStorage: localStorage,
llmRunner: llmRunner,
Expand Down
Loading

0 comments on commit 7b5486f

Please sign in to comment.