mirror of
https://github.com/System-End/nephthys.git
synced 2026-04-19 18:35:14 +00:00
Bring back AI titles! (#109)
* Rewrite ticket title gen to use the new HC AI * Use implicit string concatenation * Use async OpenAI * Guard against single-letter or all-whitespace AI responses * Add a singular space
This commit is contained in:
parent
c2b73dcb96
commit
4c3775d7c0
2 changed files with 35 additions and 16 deletions
|
|
@ -3,6 +3,7 @@ from datetime import datetime
|
|||
from typing import Any
|
||||
from typing import Dict
|
||||
|
||||
from openai import OpenAIError
|
||||
from slack_sdk.errors import SlackApiError
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
||||
|
|
@ -330,27 +331,35 @@ async def on_message(event: Dict[str, Any], client: AsyncWebClient):
|
|||
|
||||
|
||||
async def generate_ticket_title(text: str):
|
||||
async with env.session.post(
|
||||
"https://ai.hackclub.com/chat/completions",
|
||||
json={
|
||||
"messages": [
|
||||
if not env.ai_client:
|
||||
return "No title available from AI."
|
||||
|
||||
model = "qwen/qwen3-32b"
|
||||
try:
|
||||
response = await env.ai_client.chat.completions.create(
|
||||
model=model,
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a helpful assistant that helps organise tickets for Hack Club's support team. You're going to take in a message and give it a title. You will return no other content. Even if it's silly please summarise it. Use no more than 7 words, but as few as possible.",
|
||||
"content": (
|
||||
"You are a helpful assistant that helps organise tickets for Hack Club's support team. You're going to take in a message and give it a title. "
|
||||
"You will return no other content. Do *NOT* use title case. Avoid quote marks. Even if it's silly please summarise it. Use no more than 7 words, but as few as possible."
|
||||
),
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"Here is a message from a user: {text}\n\nPlease give this ticket a title.",
|
||||
},
|
||||
]
|
||||
},
|
||||
) as res:
|
||||
if res.status != 200:
|
||||
await send_heartbeat(
|
||||
f"Failed to get AI response for ticket creation: {res.status} - {await res.text()}"
|
||||
)
|
||||
title = "No title provided by AI."
|
||||
else:
|
||||
data = await res.json()
|
||||
title = data["choices"][0]["message"]["content"].strip()
|
||||
],
|
||||
)
|
||||
except OpenAIError as e:
|
||||
await send_heartbeat(f"Failed to get AI response for ticket creation: {e}")
|
||||
return "No title provided by AI."
|
||||
|
||||
if not (len(response.choices) and response.choices[0].message.content):
|
||||
await send_heartbeat(f"AI title generation is missing content: {response}")
|
||||
return "No title provided by AI."
|
||||
title = response.choices[0].message.content.strip()
|
||||
# Capitalise first letter
|
||||
title = title[0].upper() + title[1:] if len(title) > 1 else title.upper()
|
||||
return title
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from typing import Literal
|
|||
|
||||
from aiohttp import ClientSession
|
||||
from dotenv import load_dotenv
|
||||
from openai import AsyncOpenAI
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
||||
from nephthys.transcripts import transcripts
|
||||
|
|
@ -23,6 +24,7 @@ class Environment:
|
|||
self.uptime_url = os.environ.get("UPTIME_URL")
|
||||
self.site_url = os.environ.get("SITE_URL", "https://summer.hackclub.com")
|
||||
self.site_api_key = os.environ.get("SITE_API_KEY", "unset")
|
||||
self.hack_club_ai_api_key = os.environ.get("HACK_CLUB_AI_API_KEY")
|
||||
|
||||
self.environment = os.environ.get("ENVIRONMENT", "development")
|
||||
self.log_level = os.environ.get(
|
||||
|
|
@ -70,6 +72,14 @@ class Environment:
|
|||
)
|
||||
|
||||
self.slack_client = AsyncWebClient(token=self.slack_bot_token)
|
||||
self.ai_client = (
|
||||
AsyncOpenAI(
|
||||
base_url="https://ai.hackclub.com/proxy/v1",
|
||||
api_key=self.hack_club_ai_api_key,
|
||||
)
|
||||
if self.hack_club_ai_api_key
|
||||
else None
|
||||
)
|
||||
|
||||
# Cache whether the user token has workspace admin privileges
|
||||
self._workspace_admin_available: bool | Literal["unchecked"] = "unchecked"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue