Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing Periphery #58

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@

/// 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 @@

/// 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 @@
/// Prompt used to interpret multiple FHIR resources
///
/// This prompt is used by the ``FHIRMultipleResourceInterpreter``.
public static let interpretMultipleResources: FHIRPrompt = {
static let interpretMultipleResources: FHIRPrompt = {

Check warning on line 138 in LLMonFHIR/FHIRInterpretation/MultipleResources/FHIRMultipleResourceInterpreter.swift

View check run for this annotation

Codecov / codecov/patch

LLMonFHIR/FHIRInterpretation/MultipleResources/FHIRMultipleResourceInterpreter.swift#L138

Added line #L138 was not covered by tests
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 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 {

Check warning on line 26 in LLMonFHIR/FHIRInterpretation/MultipleResources/MultipleResourcesChatView.swift

View check run for this annotation

Codecov / codecov/patch

LLMonFHIR/FHIRInterpretation/MultipleResources/MultipleResourcesChatView.swift#L26

Added line #L26 was not covered by tests
@Bindable var multipleResourceInterpreter = multipleResourceInterpreter
NavigationStack {
Group {
Expand Down Expand Up @@ -88,25 +88,11 @@
/// - 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 @@

/// 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 @@
/// - 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 {

Check warning on line 42 in LLMonFHIR/FHIRInterpretation/SingleResource/FHIRResourceInterpreter.swift

View check run for this annotation

Codecov / codecov/patch

LLMonFHIR/FHIRInterpretation/SingleResource/FHIRResourceInterpreter.swift#L42

Added line #L42 was not covered by tests
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) {

Check warning on line 58 in LLMonFHIR/FHIRInterpretation/SingleResource/FHIRResourceInterpreter.swift

View check run for this annotation

Codecov / codecov/patch

LLMonFHIR/FHIRInterpretation/SingleResource/FHIRResourceInterpreter.swift#L58

Added line #L58 was not covered by tests
self.resourceProcessor.llmSchema = schema
}
}
Expand All @@ -65,7 +65,7 @@
/// 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 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 @@


/// - 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 required convenience init() {
required convenience init() {

Check warning on line 62 in LLMonFHIR/FHIRInterpretationModule.swift

View check run for this annotation

Codecov / codecov/patch

LLMonFHIR/FHIRInterpretationModule.swift#L62

Added line #L62 was not covered by tests
self.init(
summaryLLMSchema: Defaults.llmSchema,
interpretationLLMSchema: Defaults.llmSchema,
Expand All @@ -67,7 +68,7 @@
}


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