update
Browse files- .gitignore +5 -0
- app.py +84 -42
- gradio_webhook_payload.py +13 -8
- gradio_webhook_server.py +34 -27
- linear_api_utils.py +3 -1
.gitignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
.gradio
|
3 |
+
.env
|
4 |
+
webhook_header.json
|
5 |
+
webhook_request.json
|
app.py
CHANGED
@@ -1,21 +1,21 @@
|
|
1 |
"""
|
2 |
-
|
3 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py
|
4 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py
|
5 |
|
6 |
-
|
7 |
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue
|
8 |
|
9 |
-
|
10 |
|
11 |
-
|
12 |
-
target_webhook_label(
|
13 |
|
14 |
-
gradio,fastapi,pydantic
|
15 |
-
|
16 |
-
|
17 |
|
18 |
-
** Linear.app
|
19 |
# Copyright 2025-present, Akihito Miyazaki
|
20 |
#
|
21 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -30,7 +30,7 @@ gradio,fastapi,pydanticをあらかじめインストールしておく必要が
|
|
30 |
# See the License for the specific language governing permissions and
|
31 |
# limitations under the License.
|
32 |
|
33 |
-
** Hugging Face Hub
|
34 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
35 |
#
|
36 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -45,8 +45,8 @@ gradio,fastapi,pydanticをあらかじめインストールしておく必要が
|
|
45 |
# See the License for the specific language governing permissions and
|
46 |
# limitations under the License.
|
47 |
|
48 |
-
|
49 |
-
|
50 |
"""
|
51 |
|
52 |
import os
|
@@ -60,6 +60,14 @@ from gradio_webhook_server import WebhooksServer
|
|
60 |
from gradio_webhook_payload import WebhookPayload
|
61 |
from sleep_per_last_token_model import SleepPerLastTokenModelLiteLLM
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
def get_env_value(key, is_value_error_on_null=True):
|
65 |
value = os.getenv(key)
|
@@ -109,13 +117,6 @@ for webhook in result["data"]["webhooks"]["nodes"]:
|
|
109 |
|
110 |
app = None
|
111 |
|
112 |
-
model = SleepPerLastTokenModelLiteLLM(
|
113 |
-
max_tokens=100,
|
114 |
-
temperature=0.5,
|
115 |
-
model_id="groq/llama3-8b-8192",
|
116 |
-
api_base="https://api.groq.com/openai/v1/",
|
117 |
-
api_key=groq_api_key,
|
118 |
-
)
|
119 |
|
120 |
"""
|
121 |
model = HfApiModel(
|
@@ -127,27 +128,32 @@ model = HfApiModel(
|
|
127 |
)
|
128 |
"""
|
129 |
|
130 |
-
agent = CodeAgent(
|
131 |
-
model=model,
|
132 |
-
tools=[], ## add your tools here (don't remove final answer)
|
133 |
-
max_steps=1,
|
134 |
-
verbosity_level=1,
|
135 |
-
grammar=None,
|
136 |
-
planning_interval=None,
|
137 |
-
name=None,
|
138 |
-
description=None,
|
139 |
-
)
|
140 |
-
|
141 |
|
142 |
def update():
|
143 |
-
result = agent.run(f"how to solve this issue:{app.text}")
|
144 |
-
return app.text, result
|
|
|
145 |
|
146 |
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
gr.HTML("""<h1>Linear.app Webhook Server</h1>
|
149 |
<p>This is Demo of Direct Webhook-triggered AIAgen</p>
|
150 |
-
<p>it's still just simple code,
|
151 |
<p><b>Imagine an agent, responding instantly.</b></p>
|
152 |
<p>Technically Gradio have no way to update without action<p>
|
153 |
<p></p><br>
|
@@ -156,20 +162,50 @@ with gr.Blocks() as ui:
|
|
156 |
<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>
|
157 |
""")
|
158 |
with gr.Row():
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
|
164 |
app = WebhooksServer(
|
165 |
-
ui=
|
166 |
webhook_secret=webhook_key, # loaded by load_api_key
|
167 |
)
|
168 |
-
|
|
|
|
|
169 |
|
170 |
|
171 |
@app.add_webhook("/linear_webhook")
|
172 |
async def updated(payload: WebhookPayload):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
pprint(payload.dict(), indent=4)
|
174 |
|
175 |
data = payload.dict()["data"]
|
@@ -182,7 +218,12 @@ async def updated(payload: WebhookPayload):
|
|
182 |
|
183 |
if has_label:
|
184 |
text = data["description"]
|
185 |
-
app.
|
|
|
|
|
|
|
|
|
|
|
186 |
return {"message": "ok"}
|
187 |
|
188 |
|
@@ -202,4 +243,5 @@ mutation {
|
|
202 |
result = execute_query("webhook_update", webhook_update_text, api_key)
|
203 |
|
204 |
|
205 |
-
|
|
|
|
1 |
"""
|
2 |
+
This code adapts the following code for Linear.app. It is not official code.
|
3 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py
|
4 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py
|
5 |
|
6 |
+
Currently, it only supports a small subset of the Issue Object.
|
7 |
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue
|
8 |
|
9 |
+
You need to set `api_key = linear-api-key` and `webhook_secret = linear-webhook-secret` in your `.env` file.
|
10 |
|
11 |
+
Since the local URL changes with each startup, the URL is updated in the Linear API at startup.
|
12 |
+
At startup, it overwrites the webhook with the label specified by `target_webhook_label` (default value: Gradio).
|
13 |
|
14 |
+
You need to pre-install gradio, fastapi, and pydantic.
|
15 |
+
You need to describe your Linear API key and Linear webhook secret in the `.env` file.
|
16 |
+
Also, since this example is only for Update, please create a Webhook with the label Gradio beforehand.
|
17 |
|
18 |
+
** Copyright Notice for Linear.app Adaptation **
|
19 |
# Copyright 2025-present, Akihito Miyazaki
|
20 |
#
|
21 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
30 |
# See the License for the specific language governing permissions and
|
31 |
# limitations under the License.
|
32 |
|
33 |
+
** License Notice for Hugging Face Hub Library **
|
34 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
35 |
#
|
36 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
45 |
# See the License for the specific language governing permissions and
|
46 |
# limitations under the License.
|
47 |
|
48 |
+
This code includes parts of the Hugging Face Hub library, which is licensed under the Apache License, Version 2.0.
|
49 |
+
The full text of the license can be found at: http://www.apache.org/licenses/LICENSE-2.0
|
50 |
"""
|
51 |
|
52 |
import os
|
|
|
60 |
from gradio_webhook_payload import WebhookPayload
|
61 |
from sleep_per_last_token_model import SleepPerLastTokenModelLiteLLM
|
62 |
|
63 |
+
# .env
|
64 |
+
"""
|
65 |
+
LINEAR_API_KEY="lin_api_***"
|
66 |
+
HF_TOKEN = "hf_***"
|
67 |
+
LINEAR_WEBHOOK_KEY="lin_wh_***"
|
68 |
+
GROQ_API_KEY = "gsk_***"
|
69 |
+
"""
|
70 |
+
|
71 |
|
72 |
def get_env_value(key, is_value_error_on_null=True):
|
73 |
value = os.getenv(key)
|
|
|
117 |
|
118 |
app = None
|
119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
"""
|
122 |
model = HfApiModel(
|
|
|
128 |
)
|
129 |
"""
|
130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
def update():
|
133 |
+
# result = agent.run(f"how to solve this issue:{app.text}")
|
134 |
+
# return app.text, result
|
135 |
+
return "", ""
|
136 |
|
137 |
|
138 |
+
# still testing file or memory
|
139 |
+
def load_text(path):
|
140 |
+
with open(path, "r") as f:
|
141 |
+
return f.read()
|
142 |
+
|
143 |
+
|
144 |
+
def save_text(path, text):
|
145 |
+
with open(path, "w") as f:
|
146 |
+
f.write(text)
|
147 |
+
|
148 |
+
|
149 |
+
def update_text():
|
150 |
+
return app.issue, app.output
|
151 |
+
|
152 |
+
|
153 |
+
with gr.Blocks() as demo:
|
154 |
gr.HTML("""<h1>Linear.app Webhook Server</h1>
|
155 |
<p>This is Demo of Direct Webhook-triggered AIAgen</p>
|
156 |
+
<p>it's still just simple code,you have to reload when webhooked.</p>
|
157 |
<p><b>Imagine an agent, responding instantly.</b></p>
|
158 |
<p>Technically Gradio have no way to update without action<p>
|
159 |
<p></p><br>
|
|
|
162 |
<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>
|
163 |
""")
|
164 |
with gr.Row():
|
165 |
+
with gr.Column():
|
166 |
+
gr.Markdown("## Issue")
|
167 |
+
# issue = gr.Markdown(load_text("issue.md"))
|
168 |
+
issue = gr.Markdown("issue")
|
169 |
+
with gr.Column():
|
170 |
+
gr.Markdown("## Agent advice(Don't trust them completely)")
|
171 |
+
# output = gr.Markdown(load_text("output.md"))
|
172 |
+
output = gr.Markdown("agent result")
|
173 |
+
demo.load(update_text, inputs=None, outputs=[issue, output])
|
174 |
+
|
175 |
+
# bt = gr.Button("Ask AI")
|
176 |
+
# bt.click(update, outputs=[issue_box, output_box])
|
177 |
|
178 |
app = WebhooksServer(
|
179 |
+
ui=demo,
|
180 |
webhook_secret=webhook_key, # loaded by load_api_key
|
181 |
)
|
182 |
+
|
183 |
+
app.output = "join course"
|
184 |
+
app.issue = "how to learn smolagent"
|
185 |
|
186 |
|
187 |
@app.add_webhook("/linear_webhook")
|
188 |
async def updated(payload: WebhookPayload):
|
189 |
+
def generate_agent():
|
190 |
+
model = SleepPerLastTokenModelLiteLLM(
|
191 |
+
max_tokens=250,
|
192 |
+
temperature=0.5,
|
193 |
+
model_id="groq/llama3-8b-8192",
|
194 |
+
api_base="https://api.groq.com/openai/v1/",
|
195 |
+
api_key=groq_api_key,
|
196 |
+
)
|
197 |
+
agent = CodeAgent(
|
198 |
+
model=model,
|
199 |
+
tools=[], ## add your tools here (don't remove final answer)
|
200 |
+
max_steps=1,
|
201 |
+
verbosity_level=1,
|
202 |
+
grammar=None,
|
203 |
+
planning_interval=None,
|
204 |
+
name=None,
|
205 |
+
description=None,
|
206 |
+
)
|
207 |
+
return agent
|
208 |
+
|
209 |
pprint(payload.dict(), indent=4)
|
210 |
|
211 |
data = payload.dict()["data"]
|
|
|
218 |
|
219 |
if has_label:
|
220 |
text = data["description"]
|
221 |
+
app.issue = text
|
222 |
+
# save_text("issue.md", text)
|
223 |
+
agent = generate_agent()
|
224 |
+
result = agent.run(f"how to solve this issue:{text}")
|
225 |
+
app.output = result
|
226 |
+
# save_text("output.md", result)
|
227 |
return {"message": "ok"}
|
228 |
|
229 |
|
|
|
243 |
result = execute_query("webhook_update", webhook_update_text, api_key)
|
244 |
|
245 |
|
246 |
+
if __name__ == "__main__": # without main call twice
|
247 |
+
app.launch(webhook_update=webhook_update)
|
gradio_webhook_payload.py
CHANGED
@@ -1,16 +1,21 @@
|
|
1 |
"""
|
2 |
-
|
|
|
3 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py
|
4 |
|
5 |
-
|
6 |
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue
|
7 |
|
8 |
-
|
9 |
|
10 |
-
|
|
|
11 |
|
|
|
|
|
|
|
12 |
|
13 |
-
** Linear.app
|
14 |
# Copyright 2025-present, Akihito Miyazaki
|
15 |
#
|
16 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -25,7 +30,7 @@ Issueの新規・更新・削除は確認しました。
|
|
25 |
# See the License for the specific language governing permissions and
|
26 |
# limitations under the License.
|
27 |
|
28 |
-
** Hugging Face Hub
|
29 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
30 |
#
|
31 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -40,8 +45,8 @@ Issueの新規・更新・削除は確認しました。
|
|
40 |
# See the License for the specific language governing permissions and
|
41 |
# limitations under the License.
|
42 |
|
43 |
-
|
44 |
-
|
45 |
"""
|
46 |
|
47 |
"""Contains data structures to parse the webhooks payload."""
|
|
|
1 |
"""
|
2 |
+
This code adapts the following code for Linear.app. It is not official code.
|
3 |
+
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py
|
4 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py
|
5 |
|
6 |
+
Currently, it only supports a small subset of the Issue Object.
|
7 |
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue
|
8 |
|
9 |
+
You need to set `api_key = linear-api-key` and `webhook_secret = linear-webhook-secret` in your `.env` file.
|
10 |
|
11 |
+
Since the local URL changes with each startup, the URL is updated in the Linear API at startup.
|
12 |
+
At startup, it overwrites the webhook with the label specified by `target_webhook_label` (default value: Gradio).
|
13 |
|
14 |
+
You need to pre-install gradio, fastapi, and pydantic.
|
15 |
+
You need to describe your Linear API key and Linear webhook secret in the `.env` file.
|
16 |
+
Also, since this example is only for Update, please create a Webhook with the label Gradio beforehand.
|
17 |
|
18 |
+
** Copyright Notice for Linear.app Adaptation **
|
19 |
# Copyright 2025-present, Akihito Miyazaki
|
20 |
#
|
21 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
30 |
# See the License for the specific language governing permissions and
|
31 |
# limitations under the License.
|
32 |
|
33 |
+
** License Notice for Hugging Face Hub Library **
|
34 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
35 |
#
|
36 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
45 |
# See the License for the specific language governing permissions and
|
46 |
# limitations under the License.
|
47 |
|
48 |
+
This code includes parts of the Hugging Face Hub library, which is licensed under the Apache License, Version 2.0.
|
49 |
+
The full text of the license can be found at: http://www.apache.org/licenses/LICENSE-2.0
|
50 |
"""
|
51 |
|
52 |
"""Contains data structures to parse the webhooks payload."""
|
gradio_webhook_server.py
CHANGED
@@ -1,14 +1,21 @@
|
|
1 |
"""
|
2 |
-
|
3 |
-
Local Gradioの動作のみ確認・Spaceでのテストはまだしていません。
|
4 |
-
特に verify_signature 関数と、webhook 呼び出し時の request ヘッダーの取り扱いを変更しています。
|
5 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py
|
|
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
webhook_request.json
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
# Copyright 2025-present, Akihito Miyazaki
|
13 |
#
|
14 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -23,7 +30,7 @@ webhook_request.json
|
|
23 |
# See the License for the specific language governing permissions and
|
24 |
# limitations under the License.
|
25 |
|
26 |
-
** Hugging Face Hub
|
27 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
28 |
#
|
29 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -38,8 +45,8 @@ webhook_request.json
|
|
38 |
# See the License for the specific language governing permissions and
|
39 |
# limitations under the License.
|
40 |
|
41 |
-
|
42 |
-
|
43 |
"""
|
44 |
|
45 |
"""Contains `WebhooksServer` and `webhook_endpoint` to create a webhook server easily."""
|
@@ -58,46 +65,46 @@ from fastapi.encoders import jsonable_encoder
|
|
58 |
|
59 |
def verify_signature(request_headers, payload, webhook_secret):
|
60 |
"""
|
61 |
-
|
62 |
|
63 |
Args:
|
64 |
-
request_headers:
|
65 |
-
payload:
|
66 |
-
webhook_secret:
|
67 |
|
68 |
Returns:
|
69 |
-
True:
|
70 |
-
False:
|
71 |
"""
|
72 |
|
73 |
-
#
|
74 |
-
#
|
75 |
-
#
|
|
|
76 |
|
77 |
-
#
|
78 |
if isinstance(payload, str):
|
79 |
payload = payload.encode("utf-8")
|
80 |
|
81 |
# HMAC署名を生成
|
82 |
signature = hmac.new(
|
83 |
-
webhook_secret.encode("utf-8"),
|
84 |
payload,
|
85 |
hashlib.sha256,
|
86 |
).hexdigest()
|
87 |
|
88 |
-
#
|
89 |
-
#
|
90 |
linear_signature = request_headers.get("linear-signature")
|
91 |
if not linear_signature:
|
92 |
linear_signature = request_headers.get(
|
93 |
"Linear-Signature"
|
94 |
-
) #
|
95 |
if not linear_signature:
|
96 |
print("Error: linear-signature header not found")
|
97 |
return False
|
98 |
|
99 |
-
|
100 |
-
return hmac.compare_digest(signature, linear_signature) # 脆弱性対策
|
101 |
|
102 |
|
103 |
# from .utils import experimental, is_fastapi_available, is_gradio_available
|
@@ -466,7 +473,7 @@ def _wrap_webhook_to_check_secret(func: Callable, webhook_secret: str) -> Callab
|
|
466 |
|
467 |
data = json.loads(request_text.decode())
|
468 |
|
469 |
-
#
|
470 |
with open("webhook_header.json", "w", encoding="utf-8") as f:
|
471 |
serialized = jsonable_encoder(request.headers)
|
472 |
json.dump(serialized, f, indent=2, ensure_ascii=False)
|
|
|
1 |
"""
|
2 |
+
This code adapts the following code for Linear.app. It is not official code.
|
|
|
|
|
3 |
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py
|
4 |
+
https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py
|
5 |
|
6 |
+
Currently, it only supports a small subset of the Issue Object.
|
7 |
+
https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/objects/Issue
|
|
|
8 |
|
9 |
+
You need to set `api_key = linear-api-key` and `webhook_secret = linear-webhook-secret` in your `.env` file.
|
10 |
+
|
11 |
+
Since the local URL changes with each startup, the URL is updated in the Linear API at startup.
|
12 |
+
At startup, it overwrites the webhook with the label specified by `target_webhook_label` (default value: Gradio).
|
13 |
+
|
14 |
+
You need to pre-install gradio, fastapi, and pydantic.
|
15 |
+
You need to describe your Linear API key and Linear webhook secret in the `.env` file.
|
16 |
+
Also, since this example is only for Update, please create a Webhook with the label Gradio beforehand.
|
17 |
+
|
18 |
+
** Copyright Notice for Linear.app Adaptation **
|
19 |
# Copyright 2025-present, Akihito Miyazaki
|
20 |
#
|
21 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
30 |
# See the License for the specific language governing permissions and
|
31 |
# limitations under the License.
|
32 |
|
33 |
+
** License Notice for Hugging Face Hub Library **
|
34 |
# Copyright 2023-present, the HuggingFace Inc. team.
|
35 |
#
|
36 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
45 |
# See the License for the specific language governing permissions and
|
46 |
# limitations under the License.
|
47 |
|
48 |
+
This code includes parts of the Hugging Face Hub library, which is licensed under the Apache License, Version 2.0.
|
49 |
+
The full text of the license can be found at: http://www.apache.org/licenses/LICENSE-2.0
|
50 |
"""
|
51 |
|
52 |
"""Contains `WebhooksServer` and `webhook_endpoint` to create a webhook server easily."""
|
|
|
65 |
|
66 |
def verify_signature(request_headers, payload, webhook_secret):
|
67 |
"""
|
68 |
+
Verifies if the request is valid by comparing the signature in the request header with the signature generated from the payload.
|
69 |
|
70 |
Args:
|
71 |
+
request_headers: Request headers (dict-like object, e.g., `request.headers`)
|
72 |
+
payload: Request payload (bytes or string)
|
73 |
+
webhook_secret: Webhook secret key (string)
|
74 |
|
75 |
Returns:
|
76 |
+
True: If the signatures match (request is valid)
|
77 |
+
False: If the signatures do not match (request is invalid)
|
78 |
"""
|
79 |
|
80 |
+
# Retrieve WEBHOOK_SECRET from environment variables
|
81 |
+
# (Alternative to Netlify.env.get('WEBHOOK_SECRET'))
|
82 |
+
# e.g., webhook_secret = os.environ.get('WEBHOOK_SECRET')
|
83 |
+
# Please adjust to match your actual environment variable name
|
84 |
|
85 |
+
# If the payload is a string, convert it to bytes
|
86 |
if isinstance(payload, str):
|
87 |
payload = payload.encode("utf-8")
|
88 |
|
89 |
# HMAC署名を生成
|
90 |
signature = hmac.new(
|
91 |
+
webhook_secret.encode("utf-8"),
|
92 |
payload,
|
93 |
hashlib.sha256,
|
94 |
).hexdigest()
|
95 |
|
96 |
+
# Retrieve the signature from the request headers
|
97 |
+
# Note that header names might be case-insensitive
|
98 |
linear_signature = request_headers.get("linear-signature")
|
99 |
if not linear_signature:
|
100 |
linear_signature = request_headers.get(
|
101 |
"Linear-Signature"
|
102 |
+
) # Check for case variations in header names.
|
103 |
if not linear_signature:
|
104 |
print("Error: linear-signature header not found")
|
105 |
return False
|
106 |
|
107 |
+
return hmac.compare_digest(signature, linear_signature)
|
|
|
108 |
|
109 |
|
110 |
# from .utils import experimental, is_fastapi_available, is_gradio_available
|
|
|
473 |
|
474 |
data = json.loads(request_text.decode())
|
475 |
|
476 |
+
# フ
|
477 |
with open("webhook_header.json", "w", encoding="utf-8") as f:
|
478 |
serialized = jsonable_encoder(request.headers)
|
479 |
json.dump(serialized, f, indent=2, ensure_ascii=False)
|
linear_api_utils.py
CHANGED
@@ -24,7 +24,7 @@ import json
|
|
24 |
import os
|
25 |
import time
|
26 |
|
27 |
-
#
|
28 |
from pprint import pprint
|
29 |
import requests
|
30 |
|
@@ -56,6 +56,8 @@ def request_linear(
|
|
56 |
|
57 |
def load_api_key(dir="./"):
|
58 |
print(f"{dir}.env")
|
|
|
|
|
59 |
load_dotenv(dotenv_path=f"{dir}.env")
|
60 |
if "api_key" in os.environ:
|
61 |
api_key = os.environ["api_key"]
|
|
|
24 |
import os
|
25 |
import time
|
26 |
|
27 |
+
#
|
28 |
from pprint import pprint
|
29 |
import requests
|
30 |
|
|
|
56 |
|
57 |
def load_api_key(dir="./"):
|
58 |
print(f"{dir}.env")
|
59 |
+
from dotenv import load_dotenv
|
60 |
+
|
61 |
load_dotenv(dotenv_path=f"{dir}.env")
|
62 |
if "api_key" in os.environ:
|
63 |
api_key = os.environ["api_key"]
|