93 lines
3.1 KiB
Python
93 lines
3.1 KiB
Python
# services/dify_client.py
|
|
import os, json, re, requests
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
DIFY_BASE = os.getenv("DIFY_API_BASE_URL", "https://api.dify.ai/v1")
|
|
TIMEOUT = 60
|
|
|
|
def _post_request(endpoint: str, api_key: str, payload: dict):
|
|
"""Generic function to post a request to a Dify endpoint."""
|
|
if not api_key:
|
|
raise RuntimeError("Dify API key is not set")
|
|
|
|
url = f"{DIFY_BASE}{endpoint}"
|
|
headers = {
|
|
"Authorization": f"Bearer {api_key}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
# For debugging the exact payload sent to the API
|
|
print(f"Sending Dify request to {url}: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
|
|
|
resp = requests.post(url, headers=headers, json=payload, timeout=TIMEOUT)
|
|
|
|
if resp.status_code != 200:
|
|
print(f"Dify API Error Response: {resp.text}")
|
|
resp.raise_for_status()
|
|
|
|
data = resp.json()
|
|
return data.get("answer") or data
|
|
|
|
def translate_text(text: str, target_lang: str, user_id: str = "system") -> str:
|
|
"""
|
|
Calls the Dify CHAT API for translation, mimicking a user query.
|
|
"""
|
|
api_key = os.getenv("DIFY_TRANSLATOR_API_KEY")
|
|
# Combine all information into a single query string, as expected by the prompt
|
|
query = f"目標語言:{target_lang}\n需翻譯內容:\n{text}"
|
|
|
|
payload = {
|
|
"inputs": {}, # Chatbot apps generally don't use inputs here
|
|
"response_mode": "blocking",
|
|
"user": user_id,
|
|
"query": query,
|
|
# conversation_id is optional for single-turn interactions
|
|
}
|
|
return _post_request("/chat-messages", api_key, payload)
|
|
|
|
def summarize_text(text: str, user_id: str = "system") -> str:
|
|
api_key = os.getenv("DIFY_SUMMARIZER_API_KEY")
|
|
payload = {
|
|
"inputs": {},
|
|
"response_mode": "blocking",
|
|
"user": user_id,
|
|
"query": text,
|
|
}
|
|
return _post_request("/chat-messages", api_key, payload)
|
|
|
|
def extract_action_items(text: str, user_id: str = "system") -> list[dict]:
|
|
api_key = os.getenv("DIFY_ACTION_EXTRACTOR_API_KEY")
|
|
payload = {
|
|
"inputs": {},
|
|
"response_mode": "blocking",
|
|
"user": user_id,
|
|
"query": text,
|
|
}
|
|
raw = _post_request("/chat-messages", api_key, payload)
|
|
|
|
# Fault tolerance for JSON parsing
|
|
s = str(raw).strip()
|
|
s = re.sub(r"^```(?:json)?|```$", "", s, flags=re.IGNORECASE|re.MULTILINE).strip()
|
|
if not (s.startswith("[") and s.endswith("]")):
|
|
m = re.search(r"[\s\S]*\[[\s\S]*\][\s\S]*", s)
|
|
if m: s = m.group(0)
|
|
|
|
items = json.loads(s)
|
|
if not isinstance(items, list):
|
|
raise ValueError("Extractor did not return a list")
|
|
|
|
# Normalize keys for database storage
|
|
normalized = []
|
|
for i in items:
|
|
for k in ("item", "action", "owner", "duedate"):
|
|
if k not in i:
|
|
raise ValueError(f"Extractor item is missing required key: {k}")
|
|
normalized.append({
|
|
"item": i["item"],
|
|
"action": i["action"],
|
|
"owner": i["owner"],
|
|
"due_date": i["duedate"],
|
|
})
|
|
return normalized |