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

Feature request: add/edit/remove labels of article #16

Closed
thiswillbeyourgithub opened this issue Jun 1, 2024 · 12 comments · Fixed by #20
Closed

Feature request: add/edit/remove labels of article #16

thiswillbeyourgithub opened this issue Jun 1, 2024 · 12 comments · Fixed by #20
Labels
enhancement New feature or request

Comments

@thiswillbeyourgithub
Copy link

Hi,

I'm coding something to automatically optimize my reading queue based on ELO scores : https://github.com/thiswillbeyourgithub/mini_LiTOY/blob/main/examples/omnivore_litoy.py

But I'm currently stuck because I don't know how I can use the API to modify labels of an article. I also asked on omnivore repo.

Is that something that could be possible? Or could you tell me how I could use for example a simple python request?

Thanks!

@yazdipour yazdipour added the enhancement New feature or request label Jun 1, 2024
@yazdipour
Copy link
Owner

Currently the feature is not implemented in the python lib. But its a great feature to have. I can see there are already mutations in graphql schema of omnivore, so it should be possible.

createLabel(input: CreateLabelInput!): CreateLabelResult!
updateLabel(input: UpdateLabelInput!): UpdateLabelResult!
deleteLabel(id: ID!): DeleteLabelResult!
setLabels(input: SetLabelsInput!): SetLabelsResult!

@thiswillbeyourgithub
Copy link
Author

thiswillbeyourgithub commented Jun 1, 2024

Thanks! I'm not familiar with graphQL, so does that mean I can use a request right away?
For example gpt4 suggests this. Does that make sense?

import requests

url = 'https://your-graphql-endpoint.com/graphql'
headers = {'Content-Type': 'application/json'}

def create_label(name):
    query = '''
    mutation {
        createLabel(input: {name: "%s"}) {
            label {
                id
                name
            }
        }
    }
    ''' % name
    response = requests.post(url, json={'query': query}, headers=headers)
    return response.json()

def update_label(id, new_name):
    query = '''
    mutation {
        updateLabel(input: {id: "%s", name: "%s"}) {
            label {
                id
                name
            }
        }
    }
    ''' % (id, new_name)
    response = requests.post(url, json={'query': query}, headers=headers)
    return response.json()

def delete_label(id):
    query = '''
    mutation {
        deleteLabel(id: "%s") {
            success
        }
    }
    ''' % id
    response = requests.post(url, json={'query': query}, headers=headers)
    return response.json()

def set_labels(ids):
    query = '''
    mutation {
        setLabels(input: {ids: [%s]}) {
            success
        }
    }
    ''' % ','.join(f'"{id}"' for id in ids)
    response = requests.post(url, json={'query': query}, headers=headers)
    return response.json()

@yazdipour
Copy link
Owner

well simple answer is to just try it!
But my suggestion is to clone this repo, and use https://github.com/yazdipour/OmnivoreQL/blob/main/omnivoreql/omnivoreql.py as example and add you new methods that follows the same sorta structure!

@yazdipour yazdipour reopened this Jun 5, 2024
@thiswillbeyourgithub
Copy link
Author

Thank. So I tried and failed.

I notice that your schema seems to be not up to date anymore? https://github.com/omnivore-app/omnivore/blob/main/packages/api/src/schema.ts is linked from https://docs.omnivore.app/integrations/api.html

Anyhow I don't know anything about graphQL, only python so just in case here's what i tried:

I have the following code taken from graphql related files:

input CreateLabelInput {
  name: String! @sanitize(maxLength: 64)
  color: String @sanitize(pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")
  description: String @sanitize(maxLength: 100)
}
input UpdateLabelInput {
  labelId: ID!
  color: String!
  description: String
  name: String!
}
input SetLabelsInput {
  pageId: ID!
  labelIds: [ID!]
  labels: [CreateLabelInput!]
  source: String
}

createLabel(input: CreateLabelInput!): CreateLabelResult!
updateLabel(input: UpdateLabelInput!): UpdateLabelResult!
setLabels(input: SetLabelsInput!): SetLabelsResult!

Here are a few reference method:

    def save_url(self, url: str):
        """
        Save a URL to Omnivore.

        :param url: The URL to save.
        """
        mutation = gql(
            """
            mutation {
                saveUrl(input: { clientRequestId: "%s", source: "api", url: "%s" }) {
                    ... on SaveSuccess {
                        url
                        clientRequestId
                    }
                    ... on SaveError {
                        errorCodes
                        message
                    }
                }
            }
        """
            % (uuid.uuid4(), url)
        )
        return self.client.execute(mutation)

    def save_page(self, url: str, original_content: str):
        """
        Save a page with html content to Omnivore.

        :param url: The URL of the page to save.
        :param original_content: The original html content of the page.
        """
        mutation = gql(
            """
            mutation {
                savePage(input: { clientRequestId: "%s", source: "api", url: "%s", originalContent:"%s" }) {
                    ... on SaveSuccess {
                        url
                        clientRequestId
                    }
                    ... on SaveError {
                        errorCodes
                        message
                    }
                }
            }
        """
            % (uuid.uuid4(), url, original_content)
        )
        return self.client.execute(mutation)

I want you to write the methods needed to manage the labels

To which GPT-4o replied:

    def create_label(self, name: str, color: str = None, description: str = None):
        mutation = gql(
            """
            mutation {
                createLabel(input: { 
                    name: "%s", 
                    color: "%s", 
                    description: "%s" 
                }) {
                    ... on CreateLabelResult {
                        label {
                            id
                            name
                            color
                            description
                        }
                    }
                    ... on CreateLabelError {
                        errorCodes
                        message
                    }
                }
            }
            """ % (name, color, description)
        )
        return self.client.execute(mutation)

    def update_label(self, label_id: str, name: str, color: str = None, description: str = None):
        mutation = gql(
            """
            mutation {
                updateLabel(input: { 
                    labelId: "%s", 
                    name: "%s", 
                    color: "%s", 
                    description: "%s" 
                }) {
                    ... on UpdateLabelResult {
                        label {
                            id
                            name
                            color
                            description
                        }
                    }
                    ... on UpdateLabelError {
                        errorCodes
                        message
                    }
                }
            }
            """ % (label_id, name, color, description)
        )
        return self.client.execute(mutation)

    def set_labels(self, page_id: str, label_ids: list, labels: list, source: str = "api"):
        label_inputs = ", ".join([
            '{ name: "%s", color: "%s", description: "%s" }' % (label['name'], label.get('color', ''), label.get('description', ''))
            for label in labels
        ])
        mutation = gql(
            """
            mutation {
                setLabels(input: { 
                    pageId: "%s", 
                    labelIds: [%s], 
                    labels: [%s], 
                    source: "%s" 
                }) {
                    ... on SetLabelsResult {
                        success
                    }
                    ... on SetLabelsError {
                        errorCodes
                        message
                    }
                }
            }
            """ % (page_id, ', '.join(label_ids), label_inputs, source)
        )
        return self.client.execute(mutation)

But no matter what I try I seem to get gql.transport.exceptions.TransportQueryError: {'message': 'Unexpected server error'} which is not at all informative!

Not knowing anything about graphQL and being super short on time, I don't have time to investigate more sadly.

@thiswillbeyourgithub
Copy link
Author

thiswillbeyourgithub commented Jun 9, 2024

update:

I dug up the android mutation used:

I think a part of my issue is that an argument "pageId" seems to be required even though all my article have "pageId" set to None apparently. Or maybe it's a parsing issue on omnivoreql's side?

Also I can't for the life of me understand what kind of arguments should go as "label_ids" and "label_inputs" even though label_inputs is a list of dict so could completely contain the label ids and not doing so could lead to unexpected errors.

@yazdipour
Copy link
Owner

Hey. This weekend i had a bit of time to work on this. And i added some new features like createLabel, updateLabel, deleteLabel.
But i am still struggling with setLabel and its WIP.
Regarding pageid: server return clientRequestId as pageid if i am not mistaken.

@thiswillbeyourgithub
Copy link
Author

Thanks a lot!

@yazdipour
Copy link
Owner

You are welcome. Btw you can now set your labels while using save_url.

And for the setlabel, pull request is in here but still wip. #21

@thiswillbeyourgithub
Copy link
Author

Just to be sure: that means I can currently decide what labels to apply when saving a url, but I can't modify the label of an article I already saved in the past. Correct?

@yazdipour
Copy link
Owner

Yes.

@yazdipour
Copy link
Owner

yazdipour commented Jun 18, 2024

@thiswillbeyourgithub set_page_labels, set_page_labels_by_ids are now added in v0.3.3

@thiswillbeyourgithub
Copy link
Author

Thank you so much! I'll finally be able to move forward my project now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants