|
""" |
|
このコードは以下のコードをLinear.appに対応させたものです。公式のコードではありません。 |
|
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py |
|
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py |
|
|
|
まだ、Issue Objectのごく一部しか対応してません。 |
|
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue |
|
|
|
.envファイルに、api_key = linear-api-key および、webhook_secret = linear-webhook-secretの設定が必要です。 |
|
|
|
ローカルは起動ごとにURLが変わるので、起動時にLinear-APIでURLを更新しています。 |
|
target_webhook_label(デフォルト値はGradio)で指定したラベルのwebhookを実行時に上書きます。 |
|
|
|
gradio,fastapi,pydanticをあらかじめインストールしておく必要があります。 |
|
.envにlinear api_keyおよび、linear-webhook secretを記述する必要があります。 |
|
また、このExampleはUpdateのみなので、最初にラベルGradioでWebhookを作っておいてください。 |
|
|
|
** Linear.app 対応部分の著作権表示 ** |
|
# Copyright 2025-present, Akihito Miyazaki |
|
# |
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
# you may not use this file except in compliance with the License. |
|
# You may obtain a copy of the License at |
|
# |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
|
# |
|
# Unless required by applicable law or agreed to in writing, software |
|
# distributed under the License is distributed on an "AS IS" BASIS, |
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
# See the License for the specific language governing permissions and |
|
# limitations under the License. |
|
|
|
** Hugging Face Hub ライブラリのライセンス表示 ** |
|
# Copyright 2023-present, the HuggingFace Inc. team. |
|
# |
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
# you may not use this file except in compliance with the License. |
|
# You may obtain a copy of the License at |
|
# |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
|
# |
|
# Unless required by applicable law or agreed to in writing, software |
|
# distributed under the License is distributed on an "AS IS" BASIS, |
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
# See the License for the specific language governing permissions and |
|
# limitations under the License. |
|
|
|
このコードには Hugging Face Hub ライブラリの一部が含まれており、Apache License, Version 2.0 の下でライセンスされています。 |
|
ライセンスの全文は以下から確認できます: http://www.apache.org/licenses/LICENSE-2.0 |
|
""" |
|
|
|
import os |
|
from pprint import pprint |
|
|
|
import gradio as gr |
|
from smolagents import CodeAgent, HfApiModel |
|
|
|
from linear_api_utils import execute_query |
|
from gradio_webhook_server import WebhooksServer |
|
from gradio_webhook_payload import WebhookPayload |
|
from sleep_per_last_token_model import SleepPerLastTokenModelLiteLLM |
|
|
|
|
|
def getenv(key, is_value_error_on_null=True): |
|
value = os.getenv(key) |
|
if value is None: |
|
from dotenv import load_dotenv |
|
|
|
load_dotenv() |
|
value = os.getenv(key) |
|
if is_value_error_on_null and value is None: |
|
raise ValueError(f"Need {key} on secret or .env(If running on local)") |
|
return value |
|
|
|
|
|
|
|
LINEAR_ISSUE_LABEL = "huggingface-public" |
|
LINEAR_WEBHOOK_LABEL = "Huggingface" |
|
|
|
|
|
groq_api_key = getenv("GROQ_API_KEY") |
|
api_key = getenv("LINEAR_API_KEY") |
|
webhook_key = getenv("LINEAR_WEBHOOK_KEY") |
|
|
|
|
|
if api_key is None: |
|
raise ValueError("Need LINEAR_API_KEY on secret") |
|
if webhook_key is None: |
|
raise ValueError("Need LINEAR_WEBHOOK_KEY on secret") |
|
|
|
webhook_query_text = """ |
|
query { |
|
webhooks{ |
|
nodes { |
|
id |
|
label |
|
url |
|
} |
|
} |
|
} |
|
""" |
|
target_webhook_label = LINEAR_WEBHOOK_LABEL |
|
target_webhook_id = None |
|
result = execute_query("webhook", webhook_query_text, api_key) |
|
for webhook in result["data"]["webhooks"]["nodes"]: |
|
if target_webhook_label == webhook["label"]: |
|
target_webhook_id = webhook["id"] |
|
|
|
|
|
app = None |
|
|
|
model = SleepPerLastTokenModelLiteLLM( |
|
max_tokens=100, |
|
temperature=0.5, |
|
model_id="groq/llama3-8b-8192", |
|
api_base="https://api.groq.com/openai/v1/", |
|
api_key=groq_api_key, |
|
) |
|
|
|
""" |
|
model = HfApiModel( |
|
max_tokens=100, |
|
temperature=0.5, |
|
model_id="google/gemma-2-2b-it", |
|
custom_role_conversions=None, |
|
token=hf_token, |
|
) |
|
""" |
|
|
|
agent = CodeAgent( |
|
model=model, |
|
tools=[], |
|
max_steps=1, |
|
verbosity_level=1, |
|
grammar=None, |
|
planning_interval=None, |
|
name=None, |
|
description=None, |
|
) |
|
|
|
|
|
def update(): |
|
result = agent.run(f"how to solve this issue:{app.text}") |
|
return app.text, result |
|
|
|
|
|
with gr.Blocks() as ui: |
|
gr.HTML("""<h1>Linear.app Webhook Server</h1> |
|
<p>This is Demo of Direct Webhook-triggered AIAgen</p> |
|
<p>it's still just simple code,sadly you have to click to show updates.</p> |
|
<p><b>Imagine an agent, responding instantly.</b></p> |
|
<p>Technically Gradio have no way to update without action<p> |
|
<p></p><br> |
|
<p>I'm confused by Hugging Face's new pricing system. I'm worried about potentially massive inference API bills, so I switched to Groq.</p> |
|
<p>I believe my use of the Groq API is currently compliant with Hugging Face's Content Policy.</p> |
|
<p>If you have any questions, please disable the Space or contact me before taking any action against my account. Thank you for your understanding.</p> |
|
""") |
|
with gr.Row(): |
|
issue_box = gr.Textbox(label="Issue") |
|
output_box = gr.Textbox(label="出力") |
|
bt = gr.Button("Ask AI") |
|
bt.click(update, outputs=[issue_box, output_box]) |
|
|
|
app = WebhooksServer( |
|
ui=ui, |
|
webhook_secret=webhook_key, |
|
) |
|
app.text = "nothing" |
|
|
|
|
|
@app.add_webhook("/linear_webhook") |
|
async def updated(payload: WebhookPayload): |
|
pprint(payload.dict(), indent=4) |
|
|
|
data = payload.dict()["data"] |
|
has_label = True |
|
if LINEAR_ISSUE_LABEL: |
|
has_label = False |
|
for label in data["labels"]: |
|
if label["name"] == LINEAR_ISSUE_LABEL: |
|
has_label = True |
|
|
|
if has_label: |
|
text = data["description"] |
|
app.text = text |
|
return {"message": "ok"} |
|
|
|
|
|
def webhook_update(url): |
|
webhook_update_text = """ |
|
mutation { |
|
webhookUpdate( |
|
id: "%s" |
|
input:{ |
|
url:"%s" |
|
} |
|
) { |
|
success |
|
} |
|
} |
|
""" % (target_webhook_id, url) |
|
result = execute_query("webhook_update", webhook_update_text, api_key) |
|
|
|
|
|
app.launch(webhook_update=webhook_update) |
|
|