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

✨ Apply embed specific tag on subjects for video, image and external #2703

Merged
merged 8 commits into from
Aug 29, 2024

Conversation

foysalit
Copy link
Contributor

@foysalit foysalit commented Aug 9, 2024

This PR refactors the existing subject language tagger to build a more generic subject tagger that is capable or running multiple taggers that evaulates the record content from the subject and applies necessary tags.
The current implementation adds tag for embed content type along with existing language tags.

Copy link
Collaborator

@devinivy devinivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the new tagging setup!

Comment on lines 32 to 35
if (tagger.isApplicable()) {
const newTags = await tagger.getTags()
if (newTags.length) tags.push(...newTags)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the intended behavior if you call tagger.getTags() without checking tagger.isApplicable()? It seems like isApplicable() may not need to be part of the public interface— the implementation of getTags() could alternatively check this itself and no-op by returning [].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I normally try to split these and let the consumer of the class have the option to perform necessary checks before invoking the getter. for getters like this, i often find use-cases down the line where we would wanna know "what would be the tags IF they were applicable?".
however, this isn't the case here... yet so I'm happy to make that check implicit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense—it just seemed like the class could be prone to misuse, as it seemed implementations of getTags() were assuming it was gated by isApplicable().

I think there's a way to get the best of both worlds using the abstract class, where there's a default implementation for getTags() that performs the isApplicable() check. And then there would be a separate method for implementers getTagsImple() that is used within the default implementation of getTags().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh I see what you mean. refactored it a bit to get that going.

return Boolean(
this.subjectStatus &&
this.subject.isRecord() &&
this.subject.uri.includes('app.bsky.feed.post') &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cozier if we either checked includes('/app.bsky.feed.post/'), or went ahead and parsed the URI and checked its collection.

const getCollection(uri: string) {
  return new AtUri(uri).collection
}

this.subjectStatus &&
this.subject.isRecord() &&
this.subject.uri.includes('app.bsky.feed.post') &&
!this.subjectStatus.tags?.find((tag) => tag.includes(this.tagPrefix)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little more specific!

Suggested change
!this.subjectStatus.tags?.find((tag) => tag.includes(this.tagPrefix)),
!this.subjectStatus.tags?.some((tag) => tag.startsWith(this.tagPrefix)),

Comment on lines 23 to 25
if (AppBskyEmbedImages.isView(recordValue)) {
tags.push(`${this.tagPrefix}image`)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If recordValue is a record then we don't have our hands on a view (isView()). I'd expect something roughly along these lines:

Suggested change
if (AppBskyEmbedImages.isView(recordValue)) {
tags.push(`${this.tagPrefix}image`)
}
if (
AppBskyFeedPost.isRecord(recordValue) &&
(AppBskyEmbedImages.isMain(recordValue.embed) ||
AppBskyEmbedRecordWithMedia.isMain(recordValue.embed))
) {
tags.push(`${this.tagPrefix}image`)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks. was gonna ask for the correct check here once we have the video stuff available on main.

// @TODO: check for video embed here
return tags
} catch (err) {
log.error({ subject: this.subject, err }, 'Error getting record langs')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call failing open 👍

isApplicable(): boolean {
return Boolean(
this.subjectStatus &&
!this.subjectStatus.tags?.find((tag) => tag.includes(this.tagPrefix)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little more specific!

Suggested change
!this.subjectStatus.tags?.find((tag) => tag.includes(this.tagPrefix)),
!this.subjectStatus.tags?.some((tag) => tag.startsWith(this.tagPrefix)),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, didn't like having to change this in 2 different places so refactored the class abstract class a bit more to move this logic in one place.

}
const tags: string[] = []
if (
AppBskyEmbedImages.isView(recordValue) &&
Copy link
Collaborator

@devinivy devinivy Aug 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want this:

Suggested change
AppBskyEmbedImages.isView(recordValue) &&
AppBskyFeedPost.isRecord(recordValue) &&

This functionality should be fairly testable, I think—maybe we should get a test going passing a post record through it.

Copy link
Contributor Author

@foysalit foysalit Aug 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah good idea, was easier to get the right checks through a test. LMK if the current checks look right. my reasoning was, we wanna check if the record is a post with media embed first. and then, apply tags based on the type of media.

Copy link
Collaborator

@devinivy devinivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! I think just need a final pass on that one check for image tags 👍

@foysalit foysalit changed the title 🚧 Refactor subject tagging to facilitate video content tagging ✨ Apply embed specific tag on subjects for video, image and external Aug 29, 2024
protected abstract buildTags(): Promise<string[]>

async getTags(): Promise<string[]> {
console.log(this.isApplicable(), 'isApplicable')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
console.log(this.isApplicable(), 'isApplicable')

Comment on lines 32 to 33
AppBskyFeedPost.isRecord(recordValue) &&
AppBskyEmbedRecordWithMedia.isMain(recordValue.embed)
Copy link
Collaborator

@devinivy devinivy Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are six cases for recordValue.embed we should be looking for:

  • image embed
  • video embed
  • external embed
  • "record with media" embed containing image media
  • "record with media" embed containing video media
  • "record with media" embed containing external media

Those last three are handled here, think we just need to handle the top three.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof tripping over this a little bit. hope this last implementation covers all.


describe('embed tagger', () => {
it('Adds image tag to post with image', async () => {
const post = sc.posts[sc.dids.carol][0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a record-with-media embed. if we add a test for sc.replies[sc.dids.bob][0] I think we'll hit the direct image embed case.

Copy link
Collaborator

@devinivy devinivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suuuuper duper close, think we just need to add cases for those additional embed types.

@foysalit foysalit merged commit 372ed4c into main Aug 29, 2024
10 checks passed
@foysalit foysalit deleted the ozone-subject-video-tag branch August 29, 2024 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants