Doccano: Dokumentasi apa pun tentang penggunaan sebagai layanan REST

Dibuat pada 20 Jul 2019  ·  14Komentar  ·  Sumber: doccano/doccano

Bagaimana bisa digunakan sebagai layanan REST API. Kirim teks mentah dan doccano menanggapi data yang diuraikan?

enhancement

Komentar yang paling membantu

@louisguitton @Hironsan

Saya membuat pembungkus API sederhana untuk penggunaan sementara saat tim bekerja membangun klien resmi.
https://github.com/afparsons/doccano_api_client

@luispsantos - Saya lupa menandai Anda tetapi Anda juga tertarik pada suatu saat saya pikir.

Semua 14 komentar

Pendokumentasian tentang API sedang berlangsung. Harap tunggu sebentar!

https://github.com/chakki-works/doccano/projects/3#card -22665439

Adakah pembaruan untuk rilis berikutnya dengan ini? Saya juga ingin fitur ini untuk proyek anotasi yang sedang saya kerjakan.

@luispsantos , @Hironsan di https://github.com/chakki-works/doccano/issues/6 memberikan contoh kelas untuk menggambarkan interaksi dengan doccano API. Dari pengalaman saya, ini cukup mudah digunakan dan dipahami.

Saya perhatikan bahwa karena perubahan terbaru, otentikasi berfungsi melalui token API sekarang, jadi Anda hanya perlu menyesuaikan skema otentikasi dalam kode itu dan meneruskan header otentikasi setiap kali dengan permintaan Anda.

class Client(object):
    def __init__(self, entrypoint, username=None, password=None):
        self.entrypoint = entrypoint
        self.client = requests.Session()

        api_token = self.get_api_token(username, password)
        self.auth_headers = {"Authorization": "Token {}".format(api_token)}

    def get_api_token(self, username, password):
        url = f"{self.entrypoint}/v1/auth-token"
        login = {"username": username, "password": password}
        response = self.client.post(url, json=login)
        return response.json()["token"]

    def fetch_projects(self):
        url = f"{self.entrypoint}/v1/projects"
        response = self.client.get(url, headers=self.auth_headers)
        return response

@rbagd Terima kasih untuk kelas contoh, ini akan bermanfaat bagi orang lain yang menemukan masalah ini tentang cara berinteraksi dengan Doccano di level API (terutama dengan otentikasi token tambahan pada contoh ini). Saya setuju bahwa contoh yang diberikan oleh @Hironsan cukup intuitif, dan sementara itu saya berhasil menyesuaikannya dengan kasus penggunaan saya menggunakan otentikasi token :+1:

Pertanyaan yang diajukan di #410 .

Pertanyaan 1: /v1/projects/{project_id}/titik akhir dokumen

Saya berhasil membuat proyek dan mengunggah dokumen menggunakan titik akhir ini
https://github.com/chakki-works/doccano/blob/master/app/api/urls.py#L27 -L28
tetapi metadata tidak diunggah.
Dari apa yang saya lihat di sini https://github.com/chakki-works/doccano/blob/master/app/api/views.py#L125 bidang meta tidak didukung oleh API meskipun dalam Serializer, yang akan menjelaskan bahwa metadata tidak diunggah. Apakah pemahaman saya benar?

Pertanyaan 2: /v1/projects/{project_id}/docs/upload endpoint

Saya mencoba mengunggah dokumen menggunakan titik akhir ini
https://github.com/chakki-works/doccano/blob/master/app/api/urls.py#L37 -L38

Apa jenis argumen file sini https://github.com/chakki-works/doccano/blob/master/app/api/views.py#L207 ?
Saya mencoba meneruskan file JSONLine sebagai string, dan saya mendapatkan {"detail":"Unsupported media type \"application/json\" in request."}

Untuk menindaklanjuti pertanyaan saya di atas, berikut adalah beberapa kode yang dapat direproduksi.

Klien yang saya gunakan

class Client(object):
    """
    Client code was inspired by: https://github.com/chakki-works/doccano/issues/6#issuecomment-489924577
    Endpoints can be found here: https://github.com/chakki-works/doccano/blob/master/app/api/urls.py
    """
    def __init__(self, entrypoint, username=None, password=None):
        self.entrypoint = entrypoint
        self.client = requests.Session()
        self._login(username, password)

    def _login(self, username, password):
        url = f"{self.entrypoint}/v1/auth-token"
        login = {"username": username, "password": password}
        response = self.client.post(url, json=login)
        api_token = response.json()["token"]
        self.client.headers.update({"Authorization": f"Token {api_token}"})

    def add_document(self, project_id, data):
        url = f'{self.entrypoint}/v1/projects/{project_id}/docs'
        response = self.client.post(url, data=data)
        return response.json()

    def upload_data(self, project_id, file, file_format='csv'):
        """
        file is (?) of type file object (BytesIO or StringIO ...)
        """
        data = {
            'file': file,
            'format': file_format
        }
        url = f'{self.entrypoint}/v1/projects/{project_id}/docs/upload'
        response = self.client.post(url, data=data)
        return response

pertanyaan 1

>>> c = Client(
    'https://labelling-onefootball.herokuapp.com', 
    os.environ.get('DOCANNO_ADMIN'), 
    os.environ.get('DOCANNO_PWD')
)
>>> doc = {'text': 'Mercato / PSG\xa0: ce qu’a dit Tuchel à Neymar va vous surprendre',
 'meta': {'article_id': 27551814,
  'published_at_str': '2019-10-08 08:23:35',
  'provider_name': 'InfoMercato',
  'article_link': 'https://consumer-web.onefootball.com/cms/fr/27551814'}}
>>> c.add_document(project_id, doc)
# meta fields are not uploaded

Pertanyaan 2

>>> jsonline_dataset = '{"text":"Mercato \\/ PSG\\u00a0: ce qu\\u2019a dit Tuchel \\u00e0 Neymar va vous surprendre","meta":{"article_id":27551814,"published_at_str":"2019-10-08 08:23:35","provider_name":"InfoMercato","article_link":"https:\\/\\/consumer-web.onefootball.com\\/cms\\/fr\\/27551814"}}\n{"text":"Bingo Challenge : Le num\\u00e9ro \\u00ab\\u00a0Tres\\u00a0\\u00bb","meta":{"article_id":27577681,"published_at_str":"2019-10-10 10:30:01","provider_name":"Furia Liga","article_link":"https:\\/\\/consumer-web.onefootball.com\\/cms\\/fr\\/27577681"}}'
>>> file_obj = io.StringIO(jsonline_dataset)
>>> r = c.upload_data(4, file_obj, 'json')
# I get <iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>

@louisguitton Apakah Anda pernah dapat menemukan solusi? Saya menggunakan kode yang sangat mirip dan sayangnya menerima respons berikut dengan /upload :

{'detail': 'Unsupported media type "application/x-www-form-urlencoded" in request.'}

Permintaan get untuk titik akhir seperti /me berfungsi dengan baik.

@icoxfog417 Anda mereferensikan dokumentasi pada bulan Juni; dapatkah saya menemukan dokumentasi ini di suatu tempat?

@louisguitton Apakah Anda pernah dapat menemukan solusi?

Tidak, menunggu dokumentasi juga. Tapi mereka cukup sibuk berurusan dengan refactoring frontend untuk v1.0.0 jadi saya tidak keberatan menunggu.

@louisguitton

Pembaruan kecil: Saya pikir itu mungkin dari Content-Type multipart/form-data . Saya sudah mencoba dengan itu dan menerima:

{'detail': 'Empty content'}

Jadi itu setidaknya _different_ . Kita lihat saja apakah itu termasuk kemajuan atau tidak.


Pembaruan 2: Saya mendapat <Response [201]> :

requests.post(
        'http://<URL>/v1/projects/1/docs/upload',
        files={'file': ('d1.json', open('d1.json', 'rb'))},
        data={'file': ('d1.json', open('d1.json', 'rb')), 'format': 'json'},
        headers = {
            'Authorization': 'Token {token}'.format(token=token)
        }
    )

Meskipun tanggapannya positif, dokumen tersebut tampaknya tidak ditambahkan ke proyek.


Pembaruan 3: Dikonfirmasi berfungsi! Ini juga berfungsi dengan requests.Session() pra-otorisasi, seperti yang ditunjukkan di bawah ini.

# this is part of the Client class

    def upload(
        self,
        project_id: str,
        file_format: str,
        file_name: str,
        file_path: str = './',
    ) -> requests.models.Response:
        """        
        """
        url = '{}/v1/projects/{}/docs/upload'.format(self.entrypoint, project_id)
        files = {'file': (file_name, open(os.path.join(file_path, file_name), 'rb'))}
        data = {'file': (file_name, open(os.path.join(file_path, file_name), 'rb')), 'format': file_format}
        return self.client.post(url, files=files, data=data)

Rencana

  • Gunakan drf-yasg untuk membuat dokumentasi API.
  • Buat paket doccano-client untuk memanggil API.

@louisguitton @Hironsan

Saya membuat pembungkus API sederhana untuk penggunaan sementara saat tim bekerja membangun klien resmi.
https://github.com/afparsons/doccano_api_client

@luispsantos - Saya lupa menandai Anda tetapi Anda juga tertarik pada suatu saat saya pikir.

Saya perhatikan bahwa titik akhir get_doc_download tidak memformat data menggunakan pemformatan JSON.

Adakah saran untuk mengimplementasikan kelas JSONPainter untuk mengembalikan struktur data yang sama dari titik akhir ini?

Hai @Hironsan , di mana dokumen API tersedia? Hanya spesifikasi OpenAPI yang akan dihargai juga. Terima kasih!

Saya telah menggunakan doccano ke aws dan sekarang mencoba menggunakan klien untuk mengunggah data dari pipa aliran udara tetapi sepertinya saya tidak dapat terhubung dengan klien doccano. Saya mengikuti instruksi tetapi saya terus mendapatkan kesalahan:

from doccano_api_client import DoccanoClient

doccano_client = DoccanoClient(
    'https://doccano-dev.test.com/', 
    os.environ.get('DOCANNO_ADMIN'), 
    os.environ.get('DOCANNO_PWD')
)

Saya kemudian mendapatkan kesalahan di bawah ini

JSONDecodeError                           Traceback (most recent call last)
<ipython-input-100-60f5cf7a0cc5> in <module>
      4     'https://doccano-dev.test.com/',
      5     os.environ.get('DOCANNO_ADMIN'),
----> 6     os.environ.get('DOCANNO_PWD')
      7 )

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/doccano_api_client/__init__.py in __init__(self, baseurl, username, password)
    107         self.baseurl = baseurl if baseurl[-1] == '/' else baseurl+'/'
    108         self.session = requests.Session()
--> 109         self._login(username, password)
    110 
    111     def _login(

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/doccano_api_client/__init__.py in _login(self, username, password)
    125         url = 'v1/auth-token'
    126         auth = {'username': username, 'password': password}
--> 127         response = self.post(url, auth)
    128         token = response['token']
    129         self.session.headers.update(

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/doccano_api_client/__init__.py in post(self, endpoint, data, json, files)
     62         request_url = urljoin(self.baseurl, endpoint)
     63         return self.session.post(
---> 64                 request_url, data=data, files=files, json=json).json()
     65 
     66     def delete(

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/requests/models.py in json(self, **kwargs)
    896                     # used.
    897                     pass
--> 898         return complexjson.loads(self.text, **kwargs)
    899 
    900     <strong i="9">@property</strong>

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/simplejson/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, use_decimal, **kw)
    523             parse_constant is None and object_pairs_hook is None
    524             and not use_decimal and not kw):
--> 525         return _default_decoder.decode(s)
    526     if cls is None:
    527         cls = JSONDecoder

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/simplejson/decoder.py in decode(self, s, _w, _PY3)
    368         if _PY3 and isinstance(s, bytes):
    369             s = str(s, self.encoding)
--> 370         obj, end = self.raw_decode(s)
    371         end = _w(s, end).end()
    372         if end != len(s):

~/.pyenv/versions/3.6.10/lib/python3.6/site-packages/simplejson/decoder.py in raw_decode(self, s, idx, _w, _PY3)
    398             elif ord0 == 0xef and s[idx:idx + 3] == '\xef\xbb\xbf':
    399                 idx += 3
--> 400         return self.scan_once(s, idx=_w(s, idx).end())

JSONDecodeError: Expecting value: line 2 column 1 (char 1)
Apakah halaman ini membantu?
0 / 5 - 0 peringkat