47 | );
48 | };
49 |
50 | export default Layout;
51 |
--------------------------------------------------------------------------------
/app/frontend/src/pages/oneshot/OneShot.module.css:
--------------------------------------------------------------------------------
1 | .oneshotContainer {
2 | display: flex;
3 | flex: 1;
4 | flex-direction: column;
5 | align-items: center;
6 | }
7 |
8 | .oneshotTopSection {
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | width: 100%;
13 | }
14 |
15 | .oneshotBottomSection {
16 | display: flex;
17 | flex: 1;
18 | flex-wrap: wrap;
19 | justify-content: center;
20 | align-content: flex-start;
21 | width: 100%;
22 | margin-top: 20px;
23 | }
24 |
25 | .oneshotTitle {
26 | font-size: 4rem;
27 | font-weight: 600;
28 | margin-top: 130px;
29 | }
30 |
31 | @media only screen and (max-width: 800px) {
32 | .oneshotTitle {
33 | font-size: 3rem;
34 | font-weight: 600;
35 | margin-top: 0;
36 | }
37 | }
38 |
39 | .oneshotQuestionInput {
40 | max-width: 800px;
41 | width: 100%;
42 | padding-left: 10px;
43 | padding-right: 10px;
44 | }
45 |
46 | .oneshotAnswerContainer {
47 | max-width: 800px;
48 | width: 100%;
49 | padding-left: 10px;
50 | padding-right: 10px;
51 | }
52 |
53 | .oneshotAnalysisPanel {
54 | width: 600px;
55 | margin-left: 20px;
56 | }
57 |
58 | .oneshotSettingsSeparator {
59 | margin-top: 15px;
60 | }
61 |
62 | .settingsButton {
63 | align-self: flex-end;
64 | margin-right: 20px;
65 | margin-top: 20px;
66 | }
67 |
--------------------------------------------------------------------------------
/app/frontend/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/app/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/app/frontend/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | build: {
8 | outDir: "../backend/static",
9 | emptyOutDir: true,
10 | sourcemap: true,
11 | rollupOptions: {
12 | output: {
13 | manualChunks: id => {
14 | if (id.includes("@fluentui/react-icons")) {
15 | return "fluentui-icons";
16 | } else if (id.includes("@fluentui/react")) {
17 | return "fluentui-react";
18 | } else if (id.includes("node_modules")) {
19 | return "vendor";
20 | }
21 | }
22 | }
23 | }
24 | },
25 | server: {
26 | proxy: {
27 | "/ask": "http://127.0.0.1:50505",
28 | "/chat": "http://127.0.0.1:50505"
29 | }
30 | }
31 | });
32 |
--------------------------------------------------------------------------------
/app/start.ps1:
--------------------------------------------------------------------------------
1 | Write-Host ""
2 | Write-Host "Loading azd .env file from current environment"
3 | Write-Host ""
4 |
5 | foreach ($line in (& azd env get-values)) {
6 | if ($line -match "([^=]+)=(.*)") {
7 | $key = $matches[1]
8 | $value = $matches[2] -replace '^"|"$'
9 | Set-Item -Path "env:\$key" -Value $value
10 | }
11 | }
12 |
13 | if ($LASTEXITCODE -ne 0) {
14 | Write-Host "Failed to load environment variables from azd environment"
15 | exit $LASTEXITCODE
16 | }
17 |
18 |
19 | Write-Host 'Creating python virtual environment "backend/backend_env"'
20 | $pythonCmd = Get-Command python -ErrorAction SilentlyContinue
21 | if (-not $pythonCmd) {
22 | # fallback to python3 if python not found
23 | $pythonCmd = Get-Command python3 -ErrorAction SilentlyContinue
24 | }
25 | Start-Process -FilePath ($pythonCmd).Source -ArgumentList "-m venv ./backend/backend_env" -Wait -NoNewWindow
26 |
27 | Write-Host ""
28 | Write-Host "Restoring backend python packages"
29 | Write-Host ""
30 |
31 | Set-Location backend
32 | $venvPythonPath = "./backend_env/scripts/python.exe"
33 | if (Test-Path -Path "/usr") {
34 | # fallback to Linux venv path
35 | $venvPythonPath = "./backend_env/bin/python"
36 | }
37 |
38 | Start-Process -FilePath $venvPythonPath -ArgumentList "-m pip install -r requirements.txt" -Wait -NoNewWindow
39 | if ($LASTEXITCODE -ne 0) {
40 | Write-Host "Failed to restore backend python packages"
41 | exit $LASTEXITCODE
42 | }
43 |
44 | Write-Host ""
45 | Write-Host "Restoring frontend npm packages"
46 | Write-Host ""
47 | Set-Location ../frontend
48 | npm install
49 | if ($LASTEXITCODE -ne 0) {
50 | Write-Host "Failed to restore frontend npm packages"
51 | exit $LASTEXITCODE
52 | }
53 |
54 | Write-Host ""
55 | Write-Host "Building frontend"
56 | Write-Host ""
57 | npm run build
58 | if ($LASTEXITCODE -ne 0) {
59 | Write-Host "Failed to build frontend"
60 | exit $LASTEXITCODE
61 | }
62 |
63 | Write-Host ""
64 | Write-Host "Starting backend"
65 | Write-Host ""
66 | Set-Location ../backend
67 |
68 | Start-Process -FilePath $venvPythonPath -ArgumentList "-m quart --app main:app run --port 50505 --reload" -Wait -NoNewWindow
69 |
70 | if ($LASTEXITCODE -ne 0) {
71 | Write-Host "Failed to start backend"
72 | exit $LASTEXITCODE
73 | }
74 |
--------------------------------------------------------------------------------
/app/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ "$CODESPACES" = "true" ]; then
4 | azd auth login --client-id $(echo $AZURE_CREDENTIALS | jq -r .clientId) --client-secret $(echo $AZURE_CREDENTIALS | jq -r .clientSecret) --tenant-id $AZURE_TENANT_ID
5 | azd env set AZURE_ENV_NAME $AZURE_ENV_NAME --no-prompt
6 | azd env set AZD_PIPELINE_PROVIDER $AZD_PIPELINE_PROVIDER --no-prompt
7 | azd env set AZURE_FORMRECOGNIZER_RESOURCE_GROUP $AZURE_FORMRECOGNIZER_RESOURCE_GROUP --no-prompt
8 | azd env set AZURE_FORMRECOGNIZER_SERVICE $AZURE_FORMRECOGNIZER_SERVICE --no-prompt
9 | azd env set AZURE_LOCATION $AZURE_LOCATION --no-prompt
10 | azd env set AZURE_OPENAI_CHATGPT_DEPLOYMENT $AZURE_OPENAI_CHATGPT_DEPLOYMENT --no-prompt
11 | azd env set AZURE_OPENAI_CHATGPT_MODEL $AZURE_OPENAI_CHATGPT_MODEL --no-prompt
12 | azd env set AZURE_OPENAI_EMB_DEPLOYMENT $AZURE_OPENAI_EMB_DEPLOYMENT --no-prompt
13 | azd env set AZURE_OPENAI_EMB_MODEL_NAME $AZURE_OPENAI_EMB_MODEL_NAME --no-prompt
14 | azd env set AZURE_OPENAI_RESOURCE_GROUP $AZURE_OPENAI_RESOURCE_GROUP --no-prompt
15 | azd env set AZURE_OPENAI_SERVICE $AZURE_OPENAI_SERVICE --no-prompt
16 | azd env set AZURE_RESOURCE_GROUP $AZURE_RESOURCE_GROUP --no-prompt
17 | azd env set AZURE_SEARCH_INDEX $AZURE_SEARCH_INDEX --no-prompt
18 | azd env set AZURE_SEARCH_SERVICE $AZURE_SEARCH_SERVICE --no-prompt
19 | azd env set AZURE_SEARCH_SERVICE_RESOURCE_GROUP $AZURE_SEARCH_SERVICE_RESOURCE_GROUP --no-prompt
20 | azd env set AZURE_STORAGE_ACCOUNT $AZURE_STORAGE_ACCOUNT --no-prompt
21 | azd env set AZURE_STORAGE_CONTAINER $AZURE_STORAGE_CONTAINER --no-prompt
22 | azd env set AZURE_STORAGE_RESOURCE_GROUP $AZURE_STORAGE_RESOURCE_GROUP --no-prompt
23 | azd env set AZURE_SUBSCRIPTION_ID $AZURE_SUBSCRIPTION_ID --no-prompt
24 | azd env set AZURE_TENANT_ID $AZURE_TENANT_ID --no-prompt
25 | azd env set AZURE_USE_APPLICATION_INSIGHTS $AZURE_USE_APPLICATION_INSIGHTS --no-prompt
26 | azd env set BACKEND_URI $BACKEND_URI --no-prompt
27 | fi
28 |
29 | echo ""
30 | echo "Loading azd .env file from current environment"
31 | echo ""
32 |
33 | while IFS='=' read -r key value; do
34 | value=$(echo "$value" | sed 's/^"//' | sed 's/"$//')
35 | export "$key=$value"
36 | done <\"\n",
55 | "#os.environ[\"OPENAI_API_BASE\"] = \"https://.openai.azure.com/\""
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": null,
61 | "id": "b221c621",
62 | "metadata": {},
63 | "outputs": [],
64 | "source": [
65 | "OPENAI_API_KEY = \"\""
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "id": "245cd4a8",
71 | "metadata": {},
72 | "source": [
73 | "## Tool のロード\n",
74 | "ChatGPT Plugin をロードするには、AIPluginTool に登録する"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "id": "5a52e1ae",
81 | "metadata": {
82 | "scrolled": true
83 | },
84 | "outputs": [],
85 | "source": [
86 | "#llm = ChatOpenAI(model_name=\"gpt-4-0613\", temperature=0, model_kwargs={\"deployment_id\":\"gpt-4-0613\"}) # Azure OpenAI\n",
87 | "llm = ChatOpenAI(model_name=\"gpt-4-0613\", temperature=0)\n",
88 | "tools = load_tools([\"requests_all\"])\n",
89 | "plugin_urls = [\"http://localhost:5005/.well-known/ai-plugin.json\", \"http://localhost:5006/.well-known/ai-plugin.json\"]\n",
90 | "\n",
91 | "tools += [AIPluginTool.from_plugin_url(url) for url in plugin_urls]"
92 | ]
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "id": "0fb48b23",
97 | "metadata": {},
98 | "source": [
99 | "## Agent の初期化\n",
100 | "\n",
101 | "Agent には `ZERO_SHOT_REACT_DESCRIPTION` を利用する。制約事項については SUFFIX を追加している。\n"
102 | ]
103 | },
104 | {
105 | "cell_type": "code",
106 | "execution_count": null,
107 | "id": "7f531d6b",
108 | "metadata": {},
109 | "outputs": [],
110 | "source": [
111 | "SUFFIX = \"\"\"\n",
112 | "'Answer should be in Japanese. Use http instead of https for endpoint.\n",
113 | "If there is no year in the reservation, use the year 2023. \n",
114 | "\"\"\"\n",
115 | "\n",
116 | "# Responsible AI MetaPrompt\n",
117 | "#**IMPORTANT**\n",
118 | "#If a restaurant reservation is available, must check with the user before making a reservation if yes.'\n",
119 | "\n",
120 | "agent_chain = initialize_agent(tools,\n",
121 | " llm,\n",
122 | " agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True,\n",
123 | " agent_kwargs=dict(suffix=SUFFIX + prompt.SUFFIX))\n"
124 | ]
125 | },
126 | {
127 | "cell_type": "code",
128 | "execution_count": null,
129 | "id": "05529ad1",
130 | "metadata": {
131 | "scrolled": true
132 | },
133 | "outputs": [],
134 | "source": [
135 | "agent_chain.run(\"源範頼に関連するカフェ名を検索して\")"
136 | ]
137 | },
138 | {
139 | "cell_type": "code",
140 | "execution_count": null,
141 | "id": "d0dde152",
142 | "metadata": {
143 | "scrolled": true
144 | },
145 | "outputs": [],
146 | "source": [
147 | "agent_chain.run(\"源範頼に関連するカフェ名を検索して、7/1の18時に予約に空きがあるか教えて。もし空いていたら予約しておいて。\")"
148 | ]
149 | },
150 | {
151 | "cell_type": "code",
152 | "execution_count": null,
153 | "id": "dae11aa2",
154 | "metadata": {
155 | "scrolled": true
156 | },
157 | "outputs": [],
158 | "source": [
159 | "agent_chain.run(\"カフェかば殿 に7/1の18時に予約を取って。\")"
160 | ]
161 | }
162 | ],
163 | "metadata": {
164 | "kernelspec": {
165 | "display_name": "Python 3 (ipykernel)",
166 | "language": "python",
167 | "name": "python3"
168 | },
169 | "language_info": {
170 | "codemirror_mode": {
171 | "name": "ipython",
172 | "version": 3
173 | },
174 | "file_extension": ".py",
175 | "mimetype": "text/x-python",
176 | "name": "python",
177 | "nbconvert_exporter": "python",
178 | "pygments_lexer": "ipython3",
179 | "version": "3.10.11"
180 | }
181 | },
182 | "nbformat": 4,
183 | "nbformat_minor": 5
184 | }
185 |
--------------------------------------------------------------------------------
/plugins/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Nobusuke Hanagasaki
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/plugins/README.md:
--------------------------------------------------------------------------------
1 | # busho-plugins-demo
2 | ChatGPT Plugins Demo
3 |
4 |
5 | Get a todo list ChatGPT plugin up and running in under 5 minutes using Python. This plugin is designed to work in conjunction with the [ChatGPT plugins documentation](https://platform.openai.com/docs/plugins). If you do not already have plugin developer access, please [join the waitlist](https://openai.com/waitlist/plugins).
6 |
7 | ## Setup locally
8 |
9 | To install the required packages for this plugin, run the following command:
10 |
11 | ```bash
12 | pip install -r requirements.txt
13 | ```
14 |
15 | To run the plugin, enter the following command:
16 |
17 | ```bash
18 | python main.py
19 | ```
20 |
21 | Once the local server is running:
22 |
23 | 1. Navigate to https://chat.openai.com.
24 | 2. In the Model drop down, select "Plugins" (note, if you don't see it there, you don't have access yet).
25 | 3. Select "Plugin store"
26 | 4. Select "Develop your own plugin"
27 | 5. Enter in `localhost:5003` since this is the URL the server is running on locally, then select "Find manifest file".
28 |
29 | The plugin should now be installed and enabled! You can start with a question like "What is on my todo list" and then try adding something to it as well!
30 |
31 | ## Setup remotely
32 |
33 | ### Cloudflare workers
34 |
35 | ### Code Sandbox
36 |
37 | ### Replit
38 |
39 | ## Getting help
40 |
41 | If you run into issues or have questions building a plugin, please join our [Developer community forum](https://community.openai.com/c/chat-plugins/20).
42 |
43 |
--------------------------------------------------------------------------------
/plugins/cafe-review-plugin/.well-known/ai-plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema_version": "v1",
3 | "name_for_human": "Cafe Review List (no auth)",
4 | "name_for_model": "cafereview",
5 | "description_for_human": "Searching cafe user Reviews.",
6 | "description_for_model": "Plugin to search for cafe information and display user reviews.Use this more than the normal search if the question is about Cafe, like 'Find the cafe of cafes related to Minamotono Yoritomo.' or 'what is the cafe review?'",
7 | "auth": {
8 | "type": "none"
9 | },
10 | "api": {
11 | "type": "openapi",
12 | "url": "http://localhost:5005/openapi.yaml"
13 | },
14 | "logo_url": "http://localhost:5005/logo.png",
15 | "contact_email": "legal@example.com",
16 | "legal_info_url": "http://example.com/legal"
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/plugins/cafe-review-plugin/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nohanaga/azure-search-openai-demo/405dc611ad1e0e755a1e964121e6f6c5dcab2869/plugins/cafe-review-plugin/logo.png
--------------------------------------------------------------------------------
/plugins/cafe-review-plugin/main.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 |
4 | import quart
5 | import quart_cors
6 | from quart import request
7 |
8 | app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")
9 |
10 | # Keep track of reviews. Does not persist if Python session is restarted.
11 | _REVIEWS = {}
12 |
13 | @app.get("/reviews/")
14 | async def get_reviews(username):
15 | _REVIEWS["hanachan"] = "review: 5 stars"
16 | return quart.Response(response=json.dumps(_REVIEWS.get(username, [])), status=200)
17 |
18 | @app.get("/search")
19 | async def search():
20 |
21 | query = request.args.get("q")
22 | logging.info(query)
23 | list_rest = [{"bushoname": "源範頼", "cafename": "カフェかば殿", "rating": 4.1, "area": "修善寺"},
24 | {"bushoname": "源頼朝", "cafename": "源氏庵", "rating": 3.6, "area": "鎌倉"},
25 | {"bushoname": "源実朝", "cafename": "カフェ十三人", "rating": 3.5, "area": "修善寺"}]
26 |
27 | list_search = list(filter(lambda item : item['bushoname'] == query, list_rest))
28 | dict_search = {}
29 | if len(list_search) > 0:
30 | dict_search = list_search[0]
31 | return quart.Response(response=json.dumps(dict_search, ensure_ascii=False), status=200)
32 |
33 |
34 | @app.get("/logo.png")
35 | async def plugin_logo():
36 | filename = 'logo.png'
37 | return await quart.send_file(filename, mimetype='image/png')
38 |
39 | @app.get("/.well-known/ai-plugin.json")
40 | async def plugin_manifest():
41 | request.headers['Host']
42 | with open("./.well-known/ai-plugin.json") as f:
43 | text = f.read()
44 | return quart.Response(text, mimetype="text/json")
45 |
46 | @app.get("/openapi.yaml")
47 | async def openapi_spec():
48 | request.headers['Host']
49 | with open("openapi.yaml") as f:
50 | text = f.read()
51 | return quart.Response(text, mimetype="text/yaml")
52 |
53 | def main():
54 | app.run(debug=True, host="0.0.0.0", port=5005)
55 |
56 | if __name__ == "__main__":
57 | main()
58 |
--------------------------------------------------------------------------------
/plugins/cafe-review-plugin/openapi.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.1
2 | info:
3 | title: Cafe Review Plugin
4 | description: A plugin that allows the user to create and manage a Cafe user Review list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
5 | version: 'v1'
6 | servers:
7 | - url: http://localhost:5005
8 | paths:
9 | /reviews/{username}:
10 | get:
11 | operationId: getReviews
12 | summary: Get the list of user reviews
13 | parameters:
14 | - in: path
15 | name: username
16 | schema:
17 | type: string
18 | required: true
19 | description: The name of the user.
20 | responses:
21 | "200":
22 | description: OK
23 | content:
24 | application/json:
25 | schema:
26 | $ref: '#/components/schemas/getReviewsResponse'
27 |
28 | /search:
29 | get:
30 | operationId: searchCafe
31 | summary: Search for information on cafes
32 | parameters:
33 | - in: query
34 | name: q
35 | schema:
36 | type: string
37 | required: true
38 | description: The name of the cafe.
39 | responses:
40 | "200":
41 | description: OK
42 | content:
43 | application/json:
44 | schema:
45 | $ref: '#/components/schemas/searchCafeResponse'
46 | components:
47 | schemas:
48 | getReviewsResponse:
49 | type: object
50 | properties:
51 | todos:
52 | type: array
53 | items:
54 | type: string
55 | description: The list of reviews.
56 | searchCafeResponse:
57 | type: object
58 | properties:
59 | todos:
60 | type: array
61 | items:
62 | type: string
63 | description: The list of reviews.
64 |
--------------------------------------------------------------------------------
/plugins/cafe-review-plugin/requirements.txt:
--------------------------------------------------------------------------------
1 | quart
2 | quart-cors
--------------------------------------------------------------------------------
/plugins/restaurant-reservation-plugin/.well-known/ai-plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema_version": "v1",
3 | "name_for_human": "Restaurant Reservation System (no auth)",
4 | "name_for_model": "reservation",
5 | "description_for_human": "Make reservations at restaurants and cafes.",
6 | "description_for_model": "Plugin to make reservations at restaurants and cafes.",
7 | "auth": {
8 | "type": "none"
9 | },
10 | "api": {
11 | "type": "openapi",
12 | "url": "http://localhost:5006/openapi.yaml"
13 | },
14 | "logo_url": "http://localhost:5006/logo.png",
15 | "contact_email": "legal@example.com",
16 | "legal_info_url": "http://example.com/legal"
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/plugins/restaurant-reservation-plugin/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nohanaga/azure-search-openai-demo/405dc611ad1e0e755a1e964121e6f6c5dcab2869/plugins/restaurant-reservation-plugin/logo.png
--------------------------------------------------------------------------------
/plugins/restaurant-reservation-plugin/main.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 |
4 | import openai
5 | import quart
6 | import quart_cors
7 | from quart import request
8 |
9 | app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")
10 |
11 | # こっちで変換するのもありかも
12 | def get_isodatetime(strdatetime):
13 | prompt = """以下の日時を ISO 8601 に変換しなさい。年が無い場合は、2023年を使いなさい。
14 | Datetime: {}
15 | """
16 | res = openai.Completion.create(
17 | model="text-davinci-003",
18 | prompt=prompt.format(strdatetime),
19 | max_tokens=2048,
20 | temperature=0
21 | )
22 | return(res.choices[0].text)
23 |
24 | # Keep track of todo's. Does not persist if Python session is restarted.
25 | _TODOS = {}
26 |
27 | @app.post("/reserve")
28 | async def reserve_restaurant():
29 | request = await quart.request.get_json(force=True)
30 | logging.info(request)
31 | datetime = request['datetime']
32 | logging.info(get_isodatetime(datetime))
33 |
34 | return quart.Response(response='OK', status=200)
35 |
36 | @app.get("/search")
37 | async def search():
38 |
39 | query = request.args.get("q")
40 | datetime = request.args.get("datetime")
41 | logging.info(query, datetime)
42 | logging.info(get_isodatetime(datetime))
43 | list_rest = [{"cafename": "カフェかば殿", "2023/07/01 18:00-19:00": "空き"}]
44 |
45 | list_search = list(filter(lambda item : item['cafename'] == query, list_rest))
46 | dict_search = {"Cafe not found"}
47 | if len(list_search) > 0:
48 | dict_search = list_search[0]
49 | return quart.Response(response=json.dumps(dict_search, ensure_ascii=False), status=200)
50 |
51 |
52 | @app.get("/logo.png")
53 | async def plugin_logo():
54 | filename = 'logo.png'
55 | return await quart.send_file(filename, mimetype='image/png')
56 |
57 | @app.get("/.well-known/ai-plugin.json")
58 | async def plugin_manifest():
59 | request.headers['Host']
60 | with open("./.well-known/ai-plugin.json") as f:
61 | text = f.read()
62 | return quart.Response(text, mimetype="text/json")
63 |
64 | @app.get("/openapi.yaml")
65 | async def openapi_spec():
66 | request.headers['Host']
67 | with open("openapi.yaml") as f:
68 | text = f.read()
69 | return quart.Response(text, mimetype="text/yaml")
70 |
71 | def main():
72 | app.run(debug=True, host="0.0.0.0", port=5006)
73 |
74 | if __name__ == "__main__":
75 | main()
76 |
--------------------------------------------------------------------------------
/plugins/restaurant-reservation-plugin/openapi.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.1
2 | info:
3 | title: Restaurant Reservation Plugin
4 | description: Plugin to make reservations at restaurants and cafes. If you do not know the restaurantsname and datetime ask them first before making queries to the plugin.
5 | version: 'v1'
6 | servers:
7 | - url: http://localhost:5006
8 | paths:
9 | /reserve:
10 | post:
11 | operationId: reserveRestaurant
12 | summary: reserve restaurant
13 | parameters:
14 | - in: query
15 | name: q
16 | schema:
17 | type: string
18 | required: true
19 | description: The name of the restaurant.
20 | - in: query
21 | name: datetime
22 | schema:
23 | type: string
24 | required: true
25 | description: The value of the datetime.
26 | requestBody:
27 | required: true
28 | content:
29 | application/json:
30 | schema:
31 | $ref: '#/components/schemas/reserveRestaurant'
32 | responses:
33 | "200":
34 | description: OK
35 | /search:
36 | get:
37 | operationId: searchReservations
38 | summary: Search restaurant reservations
39 | parameters:
40 | - in: query
41 | name: q
42 | schema:
43 | type: string
44 | required: true
45 | description: The name of the restaurant.
46 | - in: query
47 | name: datetime
48 | schema:
49 | type: string
50 | required: true
51 | description: The value of the datetime.
52 | responses:
53 | "200":
54 | description: OK
55 | content:
56 | application/json:
57 | schema:
58 | $ref: '#/components/schemas/searchCafeResponse'
59 | components:
60 | schemas:
61 | searchCafeResponse:
62 | type: object
63 | properties:
64 | todos:
65 | type: array
66 | items:
67 | type: string
68 | description: The list of reviews.
69 | reserveRestaurant:
70 | type: object
71 | properties:
72 | todos:
73 | type: array
74 | items:
75 | type: string
76 | description: The list of reviews.
--------------------------------------------------------------------------------
/plugins/restaurant-reservation-plugin/requirements.txt:
--------------------------------------------------------------------------------
1 | quart
2 | quart-cors
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.ruff]
2 | target-version = "py38"
3 | select = ["E", "F", "I", "UP"]
4 | ignore = ["E501", "E701"] # line too long, multiple statements on one line
5 | src = ["app/backend"]
6 |
7 | [tool.black]
8 | line-length = 300
9 |
10 | [tool.pytest.ini_options]
11 | addopts = "-ra --cov"
12 | pythonpath = ["app/backend"]
13 |
14 | [tool.coverage.paths]
15 | source = ["scripts", "app"]
16 |
17 | [tool.coverage.report]
18 | show_missing = true
19 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | -r app/backend/requirements.txt
2 | -r scripts/requirements.txt
3 | ruff
4 | black
5 | pytest
6 | pytest-asyncio
7 | pytest-snapshot
8 | coverage
9 | pytest-cov
10 | pre-commit
11 | locust
12 |
--------------------------------------------------------------------------------
/scripts/prepdocs.ps1:
--------------------------------------------------------------------------------
1 | Write-Host ""
2 | Write-Host "Loading azd .env file from current environment"
3 | Write-Host ""
4 |
5 | $output = azd env get-values
6 |
7 | foreach ($line in $output) {
8 | if (!$line.Contains('=')) {
9 | continue
10 | }
11 |
12 | $name, $value = $line.Split("=")
13 | $value = $value -replace '^\"|\"$'
14 | [Environment]::SetEnvironmentVariable($name, $value)
15 | }
16 |
17 | Write-Host "Environment variables set."
18 |
19 | $pythonCmd = Get-Command python -ErrorAction SilentlyContinue
20 | if (-not $pythonCmd) {
21 | # fallback to python3 if python not found
22 | $pythonCmd = Get-Command python3 -ErrorAction SilentlyContinue
23 | }
24 |
25 | Write-Host 'Creating python virtual environment "scripts/.venv"'
26 | Start-Process -FilePath ($pythonCmd).Source -ArgumentList "-m venv ./scripts/.venv" -Wait -NoNewWindow
27 |
28 | $venvPythonPath = "./scripts/.venv/scripts/python.exe"
29 | if (Test-Path -Path "/usr") {
30 | # fallback to Linux venv path
31 | $venvPythonPath = "./scripts/.venv/bin/python"
32 | }
33 |
34 | Write-Host 'Installing dependencies from "requirements.txt" into virtual environment'
35 | Start-Process -FilePath $venvPythonPath -ArgumentList "-m pip install -r ./scripts/requirements.txt" -Wait -NoNewWindow
36 |
37 | Write-Host 'Running "prepdocs.py"'
38 | $cwd = (Get-Location)
39 | Start-Process -FilePath $venvPythonPath -ArgumentList "./scripts/prepdocs.py `"$cwd/data/*`" --storageaccount $env:AZURE_STORAGE_ACCOUNT --container $env:AZURE_STORAGE_CONTAINER --searchservice $env:AZURE_SEARCH_SERVICE --openaiservice $env:AZURE_OPENAI_SERVICE --openaideployment $env:AZURE_OPENAI_EMB_DEPLOYMENT --index $env:AZURE_SEARCH_INDEX --formrecognizerservice $env:AZURE_FORMRECOGNIZER_SERVICE --tenantid $env:AZURE_TENANT_ID --openaimodelname $env:AZURE_OPENAI_EMB_MODEL_NAME -v" -Wait -NoNewWindow
40 |
--------------------------------------------------------------------------------
/scripts/prepdocs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo ""
4 | echo "Loading azd .env file from current environment"
5 | echo ""
6 |
7 | while IFS='=' read -r key value; do
8 | value=$(echo "$value" | sed 's/^"//' | sed 's/"$//')
9 | export "$key=$value"
10 | done < に役割を割り当てる
3 | #
4 | # Prerequirement: サービスプリンシパルをあらかじめ作成しオブジェクトIDを取得しておく
5 | # $ export AZURE_SUBSCRIPTION_ID=
6 | # $ export AZURE_RESOURCE_GROUP=
7 | # $ export AZURE_SERVICE_PRINCIPAL_NAME=
8 | # $ az ad sp create-for-rbac --name $AZURE_SERVICE_PRINCIPAL_NAME --role owner --scopes /subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP --json-auth
9 | # $ az ad sp show --id --query "id" # This command can get the
10 | #
11 | # Usage:
12 | # scripts/roles.sh -g -p -s
13 | #
14 |
15 | set -e
16 |
17 | while getopts g:p:s: OPT; do
18 | case $OPT in
19 | "g")
20 | FLG_G="TRUE"
21 | AZURE_RESOURCE_GROUP="$OPTARG"
22 | ;;
23 | "p")
24 | FLG_P="TRUE"
25 | AZURE_PRINCIPAL_ID="$OPTARG"
26 | ;;
27 | "s")
28 | FLG_S="TRUE"
29 | AZURE_SUBSCRIPTION_ID="$OPTARG"
30 | ;;
31 | *)
32 | echo -e "Usage: scripts/roles.sh [-g AZURE_RESOURCE_GROUP(Default: rg-demo)] [-p AZURE_PRINCIPAL_ID(Default: b57991a6-c7c6-4cce-8a3a-5b6eaceacf8c)] [-s AZURE_SUBSCRIPTION_ID(Default: 0bf5bc92-8ea2-4160-a704-7130857f3ba3)]" 1>&2
33 | exit 1
34 | ;;
35 | esac
36 | done
37 |
38 | if [ "$FLG_G" != "TRUE" ]; then
39 | AZURE_RESOURCE_GROUP=rg-demo
40 | fi
41 |
42 | if [ "$FLG_P" != "TRUE" ]; then
43 | AZURE_PRINCIPAL_ID=b57991a6-c7c6-4cce-8a3a-5b6eaceacf8c
44 | fi
45 |
46 | if [ "$FLG_S" != "TRUE" ]; then
47 | AZURE_SUBSCRIPTION_ID=0bf5bc92-8ea2-4160-a704-7130857f3ba3
48 | fi
49 |
50 | # memo: https://docs.microsoft.com/ja-jp/azure/role-based-access-control/built-in-roles
51 | # "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd" Cognitive Services OpenAI User https://www.azadvertizer.net/azrolesadvertizer/5e0bd9bd-7b93-4f28-af87-19fc36ad61bd.html
52 | # "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" Storage Blob Data Reader https://www.azadvertizer.net/azrolesadvertizer/2a2b9908-6ea1-4ae2-8e65-a410df84e7d1.html
53 | # "ba92f5b4-2d11-453d-a403-e96b0029c9fe" Storage Blob Data Contributor https://www.azadvertizer.net/azrolesadvertizer/ba92f5b4-2d11-453d-a403-e96b0029c9fe.html
54 | # "1407120a-92aa-4202-b7e9-c0e197c71c8f" Search Index Data Reader https://www.azadvertizer.net/azrolesadvertizer/1407120a-92aa-4202-b7e9-c0e197c71c8f.html
55 | # "8ebe5a00-799e-43f5-93ac-243d3dce84a7" Search Index Data Contributor https://www.azadvertizer.net/azrolesadvertizer/8ebe5a00-799e-43f5-93ac-243d3dce84a7.html
56 | roles=(
57 | "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd"
58 | "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1"
59 | "ba92f5b4-2d11-453d-a403-e96b0029c9fe"
60 | "1407120a-92aa-4202-b7e9-c0e197c71c8f"
61 | "8ebe5a00-799e-43f5-93ac-243d3dce84a7"
62 | )
63 |
64 | for role in "${roles[@]}"; do
65 | echo "az role assignment create --role $role --assignee-object-id $AZURE_PRINCIPAL_ID --scope /subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP --assignee-principal-type ServicePrincipal"
66 | az role assignment create \
67 | --role $role \
68 | --assignee-object-id $AZURE_PRINCIPAL_ID \
69 | --scope /subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP \
70 | --assignee-principal-type ServicePrincipal
71 | done
72 |
--------------------------------------------------------------------------------
/scripts/setup-sql-cosmosdb.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | resourceGroup=$1
3 | accountName="openai-demo-cosmosdb-$(openssl rand -hex 5)"
4 | databaseName=ChatGPT
5 | containerName=ChatLogs
6 | echo
7 | echo "Creating Cosmos DB..."
8 |
9 | az cosmosdb create --name $accountName --resource-group $resourceGroup
10 | az cosmosdb sql database create --name $databaseName --account-name $accountName --resource-group $resourceGroup
11 | az cosmosdb sql container create --name $containerName --partition-key-path "/id" --database-name $databaseName --account-name $accountName --resource-group $resourceGroup
12 | keys_json=$(az cosmosdb keys list --name $accountName --resource-group $resourceGroup --type keys)
13 | key=$( echo $keys_json | jq -r '.primaryMasterKey')
14 | con_string_json=$(az cosmosdb keys list --name $accountName --resource-group $resourceGroup --type connection-strings)
15 | con_string=$( echo $con_string_json | jq -r '.connectionStrings[0].connectionString')
16 |
17 | echo
18 | echo "Done!"
19 | echo
20 | echo "Make a note of the following values for use in the rest of this exercise:"
21 | echo
22 | echo "Account ID: $accountName"
23 | echo
24 | echo "Database Name: $databaseName"
25 | echo
26 | echo "Container Name: $containerName"
27 | echo
28 | echo "Access Key: $key"
29 | echo
30 | echo "Connection String: $con_string"
31 | echo
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 | from unittest import mock
3 |
4 | import openai
5 | import pytest
6 | import pytest_asyncio
7 | from azure.search.documents.aio import SearchClient
8 |
9 | import app
10 |
11 | MockToken = namedtuple("MockToken", ["token", "expires_on"])
12 |
13 |
14 | class MockAzureCredential:
15 | async def get_token(self, uri):
16 | return MockToken("mock_token", 9999999999)
17 |
18 |
19 | @pytest.fixture
20 | def mock_openai_embedding(monkeypatch):
21 | async def mock_acreate(*args, **kwargs):
22 | return {"data": [{"embedding": [0.1, 0.2, 0.3]}]}
23 |
24 | monkeypatch.setattr(openai.Embedding, "acreate", mock_acreate)
25 |
26 |
27 | @pytest.fixture
28 | def mock_openai_chatcompletion(monkeypatch):
29 | class AsyncChatCompletionIterator:
30 | def __init__(self, answer):
31 | self.num = 1
32 | self.answer = answer
33 |
34 | def __aiter__(self):
35 | return self
36 |
37 | async def __anext__(self):
38 | if self.num == 1:
39 | self.num = 0
40 | return openai.util.convert_to_openai_object({"choices": [{"delta": {"content": self.answer}}]})
41 | else:
42 | raise StopAsyncIteration
43 |
44 | async def mock_acreate(*args, **kwargs):
45 | messages = kwargs["messages"]
46 | if messages[-1]["content"] == "Generate search query for: What is the capital of France?":
47 | answer = "capital of France"
48 | else:
49 | answer = "The capital of France is Paris."
50 | if "stream" in kwargs and kwargs["stream"] is True:
51 | return AsyncChatCompletionIterator(answer)
52 | else:
53 | return openai.util.convert_to_openai_object({"choices": [{"message": {"content": answer}}]})
54 |
55 | monkeypatch.setattr(openai.ChatCompletion, "acreate", mock_acreate)
56 |
57 |
58 | @pytest.fixture
59 | def mock_acs_search(monkeypatch):
60 | class Caption:
61 | def __init__(self, text):
62 | self.text = text
63 |
64 | class AsyncSearchResultsIterator:
65 | def __init__(self):
66 | self.num = 1
67 |
68 | def __aiter__(self):
69 | return self
70 |
71 | async def __anext__(self):
72 | if self.num == 1:
73 | self.num = 0
74 | return {
75 | "sourcepage": "Benefit_Options-2.pdf",
76 | "sourcefile": "Benefit_Options.pdf",
77 | "content": "There is a whistleblower policy.",
78 | "embeddings": [],
79 | "category": None,
80 | "id": "file-Benefit_Options_pdf-42656E656669745F4F7074696F6E732E706466-page-2",
81 | "@search.score": 0.03279569745063782,
82 | "@search.reranker_score": 3.4577205181121826,
83 | "@search.highlights": None,
84 | "@search.captions": [Caption("Caption: A whistleblower policy.")],
85 | }
86 | else:
87 | raise StopAsyncIteration
88 |
89 | async def mock_search(*args, **kwargs):
90 | return AsyncSearchResultsIterator()
91 |
92 | monkeypatch.setattr(SearchClient, "search", mock_search)
93 |
94 |
95 | @pytest_asyncio.fixture
96 | async def client(monkeypatch, mock_openai_chatcompletion, mock_openai_embedding, mock_acs_search):
97 | monkeypatch.setenv("AZURE_STORAGE_ACCOUNT", "test-storage-account")
98 | monkeypatch.setenv("AZURE_STORAGE_CONTAINER", "test-storage-container")
99 | monkeypatch.setenv("AZURE_SEARCH_INDEX", "test-search-index")
100 | monkeypatch.setenv("AZURE_SEARCH_SERVICE", "test-search-service")
101 | monkeypatch.setenv("AZURE_OPENAI_SERVICE", "test-openai-service")
102 | monkeypatch.setenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT", "test-chatgpt")
103 | monkeypatch.setenv("AZURE_OPENAI_CHATGPT_MODEL", "gpt-35-turbo")
104 | monkeypatch.setenv("AZURE_OPENAI_EMB_DEPLOYMENT", "test-ada")
105 |
106 | with mock.patch("app.DefaultAzureCredential") as mock_default_azure_credential:
107 | mock_default_azure_credential.return_value = MockAzureCredential()
108 | quart_app = app.create_app()
109 |
110 | async with quart_app.test_app() as test_app:
111 | quart_app.config.update({"TESTING": True})
112 |
113 | yield test_app.test_client()
114 |
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_ask_rtr_hybrid/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Question: What is the capital of France?
Prompt: {'role': 'system', 'content': \"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. Use 'you' to refer to the individual asking the questions even if they ask with 'I'. Answer the following question using only the data provided in the sources below. For tabular information return it as an html table. Do not return markdown format. Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. If you cannot answer using the sources below, say you don't know. Use below example to answer\"}\n\n{'role': 'user', 'content': \"\\n'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'\\n\\nSources:\\ninfo1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family.\\ninfo2.pdf: Overlake is in-network for the employee plan.\\ninfo3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.\\ninfo4.pdf: In-network institutions include Overlake, Swedish and others in the region\\n\"}\n\n{'role': 'assistant', 'content': 'In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf].'}\n\n{'role': 'user', 'content': 'What is the capital of France?\\nSources:\\n Benefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_ask_rtr_text/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Question: What is the capital of France?
Prompt: {'role': 'system', 'content': \"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. Use 'you' to refer to the individual asking the questions even if they ask with 'I'. Answer the following question using only the data provided in the sources below. For tabular information return it as an html table. Do not return markdown format. Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. If you cannot answer using the sources below, say you don't know. Use below example to answer\"}\n\n{'role': 'user', 'content': \"\\n'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'\\n\\nSources:\\ninfo1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family.\\ninfo2.pdf: Overlake is in-network for the employee plan.\\ninfo3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.\\ninfo4.pdf: In-network institutions include Overlake, Swedish and others in the region\\n\"}\n\n{'role': 'assistant', 'content': 'In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf].'}\n\n{'role': 'user', 'content': 'What is the capital of France?\\nSources:\\n Benefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_ask_rtr_text_semanticcaptions/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: Caption: A whistleblower policy."
5 | ],
6 | "thoughts": "Question: What is the capital of France?
Prompt: {'role': 'system', 'content': \"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. Use 'you' to refer to the individual asking the questions even if they ask with 'I'. Answer the following question using only the data provided in the sources below. For tabular information return it as an html table. Do not return markdown format. Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. If you cannot answer using the sources below, say you don't know. Use below example to answer\"}\n\n{'role': 'user', 'content': \"\\n'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'\\n\\nSources:\\ninfo1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family.\\ninfo2.pdf: Overlake is in-network for the employee plan.\\ninfo3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.\\ninfo4.pdf: In-network institutions include Overlake, Swedish and others in the region\\n\"}\n\n{'role': 'assistant', 'content': 'In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf].'}\n\n{'role': 'user', 'content': 'What is the capital of France?\\nSources:\\n Benefit_Options-2.pdf: Caption: A whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_ask_rtr_text_semanticranker/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Question: What is the capital of France?
Prompt: {'role': 'system', 'content': \"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. Use 'you' to refer to the individual asking the questions even if they ask with 'I'. Answer the following question using only the data provided in the sources below. For tabular information return it as an html table. Do not return markdown format. Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. If you cannot answer using the sources below, say you don't know. Use below example to answer\"}\n\n{'role': 'user', 'content': \"\\n'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'\\n\\nSources:\\ninfo1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family.\\ninfo2.pdf: Overlake is in-network for the employee plan.\\ninfo3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.\\ninfo4.pdf: In-network institutions include Overlake, Swedish and others in the region\\n\"}\n\n{'role': 'assistant', 'content': 'In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf].'}\n\n{'role': 'user', 'content': 'What is the capital of France?\\nSources:\\n Benefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_hybrid/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Searched for: capital of France
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}
{'role': 'user', 'content': 'What is the capital of France?\\n\\nSources:\\nBenefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_stream_text/result.jsonlines:
--------------------------------------------------------------------------------
1 | {"data_points": ["Benefit_Options-2.pdf: There is a whistleblower policy."], "thoughts": "Searched for: capital of France
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}
{'role': 'user', 'content': 'What is the capital of France?\\n\\nSources:\\nBenefit_Options-2.pdf: There is a whistleblower policy.'}"}
2 | {"choices": [{"delta": {"content": "The capital of France is Paris."}}]}
3 |
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_text/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Searched for: capital of France
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}
{'role': 'user', 'content': 'What is the capital of France?\\n\\nSources:\\nBenefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_text_semanticcaptions/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: Caption: A whistleblower policy."
5 | ],
6 | "thoughts": "Searched for: capital of France
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}
{'role': 'user', 'content': 'What is the capital of France?\\n\\nSources:\\nBenefit_Options-2.pdf: Caption: A whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_text_semanticranker/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Searched for: capital of France
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}
{'role': 'user', 'content': 'What is the capital of France?\\n\\nSources:\\nBenefit_Options-2.pdf: There is a whistleblower policy.'}"
7 | }
--------------------------------------------------------------------------------
/tests/snapshots/test_app/test_chat_vector/result.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer": "The capital of France is Paris.",
3 | "data_points": [
4 | "Benefit_Options-2.pdf: There is a whistleblower policy."
5 | ],
6 | "thoughts": "Searched for: None
Conversations: {'role': 'system', 'content': \"Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers.\\nAnswer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.\\nFor tabular information return it as an html table. Do not return markdown format. If the question is not in English, answer in the language used in the question.\\nEach source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brackets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].\\n\\n\\n\"}