chore: added mime-type in gql (#13414)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved file and image attachment handling by including MIME type
information for uploads.
* Added a new query to fetch document summaries by workspace and
document IDs.

* **Refactor**
* Minor adjustments to method signatures and property initializations to
streamline code and maintain consistency.
* Updated access levels for certain properties and methods to internal,
enhancing encapsulation.

* **Style**
  * Formatting and whitespace clean-up for improved code readability.

No changes to user-facing functionality or behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Lakr
2025-08-05 16:10:40 +08:00
committed by GitHub
parent 36d58cd6c5
commit d398aa9a71
9 changed files with 118 additions and 19 deletions

View File

@@ -9,9 +9,9 @@ import Intelligents
import UIKit
extension AFFiNEViewController: IntelligentsButtonDelegate {
func onIntelligentsButtonTapped(_ button: IntelligentsButton) {
func onIntelligentsButtonTapped(_: IntelligentsButton) {
// if it shows up then we are ready to go
let controller = IntelligentsController()
self.present(controller, animated: true)
present(controller, animated: true)
}
}

View File

@@ -0,0 +1,74 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetDocSummaryQuery: GraphQLQuery {
public static let operationName: String = "getDocSummary"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getDocSummary($workspaceId: String!, $docId: String!) { workspace(id: $workspaceId) { __typename doc(docId: $docId) { __typename summary } } }"#
))
public var workspaceId: String
public var docId: String
public init(
workspaceId: String,
docId: String
) {
self.workspaceId = workspaceId
self.docId = docId
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("doc", Doc.self, arguments: ["docId": .variable("docId")]),
] }
/// Get get with given id
public var doc: Doc { __data["doc"] }
/// Workspace.Doc
///
/// Parent Type: `DocType`
public struct Doc: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.DocType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("summary", String?.self),
] }
public var summary: String? { __data["summary"] }
}
}
}
}

View File

@@ -12,6 +12,7 @@ import EventSource
import Foundation
import MarkdownParser
import MarkdownView
import UniformTypeIdentifiers
private let loadingIndicator = ""
@@ -175,16 +176,26 @@ private extension ChatManager {
let attachmentFieldName = attachmentCount > 1 && attachmentCount != 0 ? "options.blobs" : "options.blob"
let uploadableAttachments: [GraphQLFile] = [
editorData.fileAttachments.map { file -> GraphQLFile in
.init(fieldName: attachmentFieldName, originalName: file.name, data: file.data ?? .init())
.init(
fieldName: attachmentFieldName,
originalName: file.name,
mimeType: mimeType(text: file.name),
data: file.data ?? .init()
)
},
editorData.imageAttachments.map { image -> GraphQLFile in
.init(fieldName: attachmentFieldName, originalName: "image.jpg", data: image.imageData)
.init(
fieldName: attachmentFieldName,
originalName: "image.jpg",
mimeType: mimeType(pathExtension: "jpg"),
data: image.imageData
)
},
].flatMap(\.self)
assert(uploadableAttachments.allSatisfy { !($0.data?.isEmpty ?? true) })
guard let input = try? CreateChatMessageInput(
attachments: [],
blob: .none,
blob: attachmentCount == 1 ? "" : .none,
blobs: attachmentCount > 1 && attachmentCount != 0 ? .some([]) : .none,
content: .some(contextSnippet.isEmpty ? editorData.text : "\(contextSnippet)\n\(editorData.text)"),
params: .some(AffineGraphQL.JSON(_jsonValue: messageParameters)),
@@ -216,6 +227,20 @@ private extension ChatManager {
}
}
}
private func pathExtension(for text: String) -> String {
(text as NSString).pathExtension
}
private func mimeType(pathExtension: String) -> String {
let type = UTType(filenameExtension: pathExtension) ?? .data
return type.preferredMIMEType ?? "application/octet-stream"
}
private func mimeType(text: String) -> String {
let pathExt = pathExtension(for: text)
return mimeType(pathExtension: pathExt)
}
}
private extension ChatManager {

View File

@@ -68,7 +68,7 @@ public class ChatManager: ObservableObject, @unchecked Sendable {
}
}
}
public func delete(sessionId: String, vmId: UUID) {
with(sessionId: sessionId) { $0.removeValue(forKey: vmId) }
}

View File

@@ -10,7 +10,7 @@ import Foundation
extension QLService {
final class URLSessionCookieClient: URLSessionClient {
public init() {
init() {
super.init()
session.configuration.httpCookieStorage = .init()
HTTPCookieStorage.shared.cookies?.forEach { cookie in

View File

@@ -12,7 +12,7 @@ import UIKit
class ErrorCell: ChatBaseCell {
let label = UILabel()
override func prepareContentView(inside contentView: UIView) {
super.prepareContentView(inside: contentView)
contentView.addSubview(label)
@@ -33,7 +33,7 @@ class ErrorCell: ChatBaseCell {
height: bounds.height
)
}
override func configure(with viewModel: any ChatCellViewModel) {
super.configure(with: viewModel)
guard let vm = viewModel as? ErrorCellViewModel else {
@@ -44,16 +44,16 @@ class ErrorCell: ChatBaseCell {
}
static func attributeText(for text: String) -> NSAttributedString {
return .init(string: text, attributes: [
.init(string: text, attributes: [
.font: UIFont.preferredFont(forTextStyle: .footnote),
.foregroundColor: UIColor.affineTextSecondary,
.paragraphStyle: NSMutableParagraphStyle().then {
$0.lineBreakMode = .byWordWrapping
$0.alignment = .center
}
},
])
}
override class func heightForContent(
for viewModel: any ChatCellViewModel,
width: CGFloat

View File

@@ -6,7 +6,7 @@ import UIKit
class InputBox: UIView {
weak var delegate: InputBoxDelegate?
public let viewModel = InputBoxViewModel()
let viewModel = InputBoxViewModel()
var cancellables = Set<AnyCancellable>()
lazy var containerView = UIView().then {
@@ -257,7 +257,7 @@ class InputBox: UIView {
// MARK: - Public Methods
public func addImageAttachment(_ image: UIImage) {
func addImageAttachment(_ image: UIImage) {
let attachment = ImageAttachment(image: image)
performWithAnimation { [self] in
@@ -266,7 +266,7 @@ class InputBox: UIView {
}
}
public func addFileAttachment(_ url: URL) throws {
func addFileAttachment(_ url: URL) throws {
// check less then 15mb
let fileSizeLimit: Int64 = 15 * 1024 * 1024 // 15 MB
let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path)
@@ -292,14 +292,14 @@ class InputBox: UIView {
}
}
public func addDocumentAttachment(_ documentAttachment: DocumentAttachment) {
func addDocumentAttachment(_ documentAttachment: DocumentAttachment) {
performWithAnimation { [self] in
viewModel.addDocumentAttachment(documentAttachment)
layoutIfNeeded()
}
}
public var inputBoxData: InputBoxData {
var inputBoxData: InputBoxData {
viewModel.prepareSendData()
}
}

View File

@@ -26,7 +26,7 @@ public class IntelligentsButton: UIView {
lazy var activityIndicator = UIActivityIndicatorView()
public weak var delegate: (any IntelligentsButtonDelegate)? = nil {
public weak var delegate: (any IntelligentsButtonDelegate)? {
didSet { assert(Thread.isMainThread) }
}

View File

@@ -20,7 +20,7 @@ class DarkActionButton: UIView {
let titleLabel = UILabel()
let iconView = UIImageView()
var action: (() -> Void)? = nil
var action: (() -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)