Skip to content

Commit 147f8f5

Browse files
committed
Add intent server
1 parent b834da8 commit 147f8f5

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

wyoming/http/conf/intent.yaml

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
openapi: "3.0.0"
3+
info:
4+
title: 'Wyoming Intent'
5+
version: '1.0.0'
6+
description: 'API for Intent Recognition'
7+
paths:
8+
/api/info:
9+
get:
10+
summary: 'Get service information'
11+
responses:
12+
'200':
13+
description: OK
14+
content:
15+
application/json:
16+
schema:
17+
/api/recognize-intent:
18+
post:
19+
summary: 'Recognize or handle intent'
20+
requestBody:
21+
description: 'Text to process'
22+
required: true
23+
content:
24+
text/plain:
25+
schema:
26+
type: string
27+
parameters:
28+
- in: query
29+
name: language
30+
description: 'Language of text'
31+
schema:
32+
type: string
33+
- in: query
34+
name: uri
35+
description: 'URI of Wyoming intent service'
36+
schema:
37+
type: string
38+
responses:
39+
'200':
40+
description: OK
41+
content:
42+
text/plain:
43+
schema:
44+
type: string
45+
application/json:
46+
schema:
47+
get:
48+
summary: 'Recognize or handle intent'
49+
parameters:
50+
- in: query
51+
name: text
52+
description: 'Text to process'
53+
required: true
54+
schema:
55+
type: string
56+
- in: query
57+
name: language
58+
description: 'Language of text'
59+
schema:
60+
type: string
61+
- in: query
62+
name: uri
63+
description: 'URI of Wyoming intent service'
64+
schema:
65+
type: string
66+
responses:
67+
'200':
68+
description: OK
69+
content:
70+
text/plain:
71+
schema:
72+
type: string
73+
application/json:
74+
schema:

wyoming/http/intent_server.py

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""HTTP server for intent recognition/handling."""
2+
3+
import io
4+
import logging
5+
import wave
6+
from pathlib import Path
7+
from typing import Any, Dict, Optional
8+
9+
from flask import Response, request
10+
11+
from wyoming.asr import Transcript
12+
from wyoming.client import AsyncClient
13+
from wyoming.error import Error
14+
from wyoming.intent import Intent, NotRecognized
15+
from wyoming.handle import Handled, NotHandled
16+
17+
from .shared import get_app, get_argument_parser
18+
19+
_DIR = Path(__file__).parent
20+
CONF_PATH = _DIR / "conf" / "intent.yaml"
21+
22+
23+
def main():
24+
parser = get_argument_parser()
25+
parser.add_argument("--language", help="Language for text")
26+
args = parser.parse_args()
27+
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
28+
29+
app = get_app("intent", CONF_PATH, args)
30+
31+
@app.route("/api/recognize-intent", methods=["POST", "GET"])
32+
async def api_stt() -> Response:
33+
uri = request.args.get("uri", args.uri)
34+
if not uri:
35+
raise ValueError("URI is required")
36+
37+
if request.method == "POST":
38+
text = request.data.decode()
39+
else:
40+
text = request.args.get("text", "")
41+
42+
if not text:
43+
raise ValueError("Text is required")
44+
45+
language = request.args.get("language", args.language)
46+
47+
async with AsyncClient.from_uri(uri) as client:
48+
await client.write_event(Transcript(text=text, language=language).event())
49+
50+
while True:
51+
event = await client.read_event()
52+
if event is None:
53+
raise RuntimeError("Client disconnected")
54+
55+
success = False
56+
type_name = "unknown"
57+
result: Dict[str, Any] = {}
58+
59+
if Intent.is_type(event.type):
60+
success = True
61+
type_name = "intent"
62+
intent = Intent.from_event(event)
63+
result = intent.to_dict()
64+
elif Handled.is_type(event.type):
65+
success = True
66+
type_name = "handled"
67+
handled = Handled.from_event(event)
68+
result = handled.to_dict()
69+
elif NotRecognized.is_type(event.type):
70+
success = False
71+
type_name = "not-recognized"
72+
not_recognized = NotRecognized.from_event(event)
73+
result = not_recognized.to_dict()
74+
elif NotHandled.is_type(event.type):
75+
success = False
76+
type_name = "not-handled"
77+
not_handled = NotHandled.from_event(event)
78+
result = not_handled.to_dict()
79+
elif Error.is_type(event.type):
80+
error = Error.from_event(event)
81+
raise RuntimeError(
82+
f"Unexpected error from client: code={error.code}, text={error.text}"
83+
)
84+
85+
return {"success": success, "type": type_name, "result": result}
86+
87+
app.run(args.host, args.port)
88+
89+
90+
if __name__ == "__main__":
91+
main()

0 commit comments

Comments
 (0)