Hello there! I'm a Computer Science student based in Tokyo, Japan
![]() |
![]() |
---|---|
Tokyo Train Delay | Smart Ryokou |
![]() |
![]() |
AI-House Automation | Naitei Journey |
Smart旅行
Home Page: https://smart-ryokou.vercel.app
UI for the main page, there are a input bar for prompt asking
Figma
Input bar is displayed
Add drag and drop for result page
Use dnd-kit
for library
Many times I tried enter some data and it return validation error.
Example 1
INFO: 127.0.0.1:53122 - "OPTIONS /api/recommendation/structured-format HTTP/1.1" 200 OK
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:115)] ====User query====
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:116)] place: tokyo
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:117)] date_from: 11月1日
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:118)] date_to: 11月5日
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:119)] people_num: 1
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:120)] budget: None
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:121)] trip_pace: None
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:122)] interests: None
INFO: [2023-11-01 21:14:49 app.use_case.recommendation (recommendation.py:123)] trip_type: None
INFO: [2023-11-01 21:15:13 app.use_case.recommendation (recommendation.py:158)] openai json response: {'recommendation': [{'date': '11月1日', 'activities': [{'place': '東京タワー', 'description': '東京のランドマークとして有名な展望塔です。高層階からの眺めは絶景です。'}, {'place': '浅草寺', 'description': '東京で最も有名な仏教寺院であり、観光名所です。古い歴史と豪華な建物が特徴です。'}]}, {'date': '11月2日', 'activities': [{'place': '上野公園', 'description': '広大な公園であり、美しい自然とさまざまな文化施設があります。動物園や美術館などもあります。'}, {'place': '東京ディズニーランド', 'description': '世界的に有名なディズニーテーマパークです。楽しいアトラクションやキャラクターとの出会いが待っています。'}]}, {'date': '11月3日', 'activities': [{'place': '築地市場', 'description': '新鮮な魚介類や海産物を扱う市場であり、食文化の一端を担っています。お寿司を食べるのもおすすめです。'}, {'place': '明治神宮', 'description': '東京で最も有名な神社の一つであり、静かな雰囲気と美しい自然が魅力です。参拝や散策におすすめです。'}]}, {'date': '11月4日', 'activities': [{'place': '東京スカイツリー', 'description': '東京のシンボルとして知られている展望塔です。高さ634メートルの展望台からの眺めは息をのむ美しさです。'}, {'place': '秋葉原', 'description': 'エレクトロニクスやアニメグッズのショッピングが楽しめる地区です。おしゃれなカフェやレストランもあります。'}]}, {'date': '11月5日', 'activities': [{'place': '東京ディズニーシー', 'description': 'ディズニーテーマパークの2つ目のパークであり、幻想的で神秘的な世界が広がっています。楽しいアトラクションやショーがあります。'}, {'place': '表参道', 'description': 'ファッションブランドやカフェ、レストランが並ぶおしゃれなショッピングエリアです。散策しながらおしゃれを楽しんでください。'}]}]}
INFO: 127.0.0.1:53122 - "POST /api/recommendation/structured-format HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
result = await app( # type: ignore[func-returns-value]
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/applications.py", line 290, in __call__
await super().__call__(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/applications.py", line 122, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in __call__
raise exc
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/cors.py", line 91, in __call__
await self.simple_response(scope, receive, send, request_headers=headers)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/cors.py", line 146, in simple_response
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
raise exc
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
await self.app(scope, receive, sender)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
raise e
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 718, in __call__
await route.handle(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 276, in handle
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 66, in app
response = await func(request)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 259, in app
content = await serialize_response(
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 145, in serialize_response
raise ValidationError(errors, field.type_)
pydantic.error_wrappers.ValidationError: 1 validation error for RecommendationResponse
response -> title
field required (type=value_error.missing)
Example 2
INFO: 127.0.0.1:57808 - "OPTIONS /api/recommendation/structured-format HTTP/1.1" 200 OK
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:148)] ====User query====
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:149)] place: 東京
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:150)] date_from: 11月4日
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:151)] date_to: 11月5日
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:152)] people_num: 1
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:153)] budget: None
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:154)] trip_pace: None
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:155)] interests: None
INFO: [2023-11-04 00:36:30 app.use_case.recommendation (recommendation.py:156)] trip_type: None
next-translate - compiled page: / - locale: en - namespaces: common, home - used loader: server /page
INFO: [2023-11-04 00:36:37 app.use_case.recommendation (recommendation.py:191)] openai json response: {'recommendation': [{'date': '11月4日', 'activities': [{'place': '東京ディズニーランド', 'description': '東京ディズニーランドで楽しい一日を過ごしましょう!'}]}, {'date': '11月5日', 'activities': [{'place': '浅草寺', 'description': '浅草寺でお参りし、下町情緒溢れる街を散策しましょう!'}, {'place': '東京スカイツリー', 'description': '東京スカイツリーからの眺めを楽しみましょう!'}]}]}
INFO: 127.0.0.1:57808 - "POST /api/recommendation/structured-format HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
result = await app( # type: ignore[func-returns-value]
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/applications.py", line 290, in __call__
await super().__call__(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/applications.py", line 122, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in __call__
raise exc
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/cors.py", line 91, in __call__
await self.simple_response(scope, receive, send, request_headers=headers)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/cors.py", line 146, in simple_response
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
raise exc
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
await self.app(scope, receive, sender)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
raise e
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 718, in __call__
await route.handle(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 276, in handle
await self.app(scope, receive, send)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/starlette/routing.py", line 66, in app
response = await func(request)
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 259, in app
content = await serialize_response(
File "/Users/chanon_mike/code/projects/smart-ryokou/backend/.venv/lib/python3.9/site-packages/fastapi/routing.py", line 145, in serialize_response
raise ValidationError(errors, field.type_)
pydantic.error_wrappers.ValidationError: 1 validation error for RecommendationResponse
response -> title
field required (type=value_error.missing)
Currently, in .env only contains endpoint for localhost, when deploy to staging and prod, the CORS_ORIGIN
is only specified to localhost:3000
.
Make CORS_ORIGIN
value change up to the stage (local, develop, main)
When select amount of interests more than 3, generated trip may recommend unexpected places
Set max limit of interests can be selected in PreferenceModal
to 3
Result after GPT return answer page. You can implement only the UI part without any logic.
It has the trip title at the top right, with pin icon and following place location.
After that, it show result for each day, with cards including an image, place title, description, new place button, edit button, and delete button.
You don't need to implement the distance from each place yet I guessed.
If you think the content is too large, try divide into many pr.
Currently, the result page is in the bottom of the home page, which is not expected design
After user input place prompt and preferences, go to /trip
page, then fetch gpt data, while waiting show loading screen, after finish loading, show the place and map
This could be divide into 2 tasks
UI for asking user preference. Below is the preferences list. Some data need to added such as interests
.
Request body
serverResponse = (
await axios.post('http://localhost:8000/api/recommendation/structured-format', {
place: 'string',
date_from: 'string',
date_to: 'string',
people_num: 1,
budget: 'low',
trip_pace: 'relaxed',
interests: ['food'],
trip_type: 'solo',
})
).data;
Response
openai error: expecting property name enclosed in double quotes: line 19 column 5 (char 677)
I found this happen sometime, and this happened within use_case/recommendation.py
with extract_json
function, as data return something else.
Return json everytime, remove extract_json function and use openai api instead.
OpenAI Chat completions api has function
and function calling
arguments which I think can be used. (maybe we can change the prompt too) Try search how to make gpt api return as json or something related.
References
https://betterprogramming.pub/return-json-from-gpt-65d40bfc2ef6
https://platform.openai.com/docs/guides/gpt/completions-api
User need to click on inputbar first to be able to enter date, by add autofocus, we can improve user experience
Add autofocus to InputBar
Make the design in figma and change the left side home icon and text of navbar to the website icon
Then ask review from @chanon-mike to see if it work or not.
If it work, we can implement it.
Currenlt, if you enter some strange data (such as a
) or enter place name in english, sometimes it will return place in English or strange place
Make the prompt stable and only return japanese language
Currently, the data pass to backend is fetch after navigating to the page with fixed data, and date is not displaying in result screen.
Add budget for each location in gpt response. Try test it if it accurate or not and have a discussion with @chanon-mike
When access api through frontend within INIAD Wi-Fi
Request URL:
https://gpcfxyv6ig.execute-api.ap-northeast-1.amazonaws.com/main//api/recommendation/structured-format
Request Method:
POST
Status Code:
504 Gateway Timeout
Referrer Policy:
strict-origin-when-cross-origin
Here is the error in console.
Access to XMLHttpRequest at 'https://gpcfxyv6ig.execute-api.ap-northeast-1.amazonaws.com/main//api/recommendation/structured-format' from origin 'https://smart-ryokou.vercel.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Cause:
When click go to google map button in card details, it redirect to google map, and when user want to go back to our app. They need to click go back button many times
Make go too google map button open in new link
Currently, description is truncated
When click the card, detailed dialog appear
1 week or more may result in bugged result (e.g. ask for 7 days trip but only display 6) due to token limit
For example, asking for Japan trip only display max of 7 days, but asking for Tokyo trip can display more date than that.
Try to adjust token limit or max date user can selected.
Tried examples
I think we can limit user choices to 7 days for now.
Set date limit to 7 day in PreferencesModal
.
GPT new model may be able to handle more date?
When there are 3 or more dates, map marker is very hard to see.
Save the travel plan generated by gpt in the db session
When add a new location, you need another endpoint for returning only a location
Add new endpoint which user will enter the prompt and pass through fastapi as optional. Return value is a list of location.
Parameters
prompt: str
Return
{
"locations": [
{
"name": "place",
"description": "description"
},
]
}
Process GPT data to useable data. Right now, it only return answer from the prompt. We need to make the data processable to be able to convert into card for each place.
Here is what I'm thinking. We ask gpt to return data in json format. Below is what I'm trying to do.
Tell me one day itenaries in Tokyo in json in below format.
[
{
"place": "xxxx",
"description": "xxxx"
},
{
"place": "xxxx",
"description": "xxxx"
},
]
[
{
"place": "Tsukiji Outer Market",
"description": "Begin your day by exploring the remnants of the world's largest fish market. While the wholesale market has moved to Toyosu, the outer market remains a bustling area filled with seafood stalls, restaurants, and shops selling Japanese kitchenware."
},
{
"place": "Hama-Rikyu Gardens",
"description": "A short walk from Tsukiji, this is a tranquil Edo-period garden surrounded by Tokyo's skyscrapers. The garden features tidal ponds, teahouses, and a stunning variety of seasonal flora."
},
{
"place": "Asakusa & Senso-ji Temple",
"description": "Tokyo's most famous and oldest temple, Senso-ji is dedicated to Kannon, the goddess of mercy. Approach the temple through Nakamise Street, lined with shops selling traditional goods and snacks."
},
{
"place": "Ueno Park",
"description": "A spacious public park, home to museums like Tokyo National Museum and Ueno Zoo. It's also a great spot for some relaxation amidst nature."
},
{
"place": "Akihabara",
"description": "Dubbed as the 'Electric Town', this is the hub for anime, manga, and electronic goods. Wander around its streets filled with shops, arcades, and themed cafes."
},
{
"place": "Shibuya Crossing",
"description": "Experience the world's busiest pedestrian crossing and the essence of modern Tokyo. The surrounding area is also great for shopping, dining, and entertainment."
},
{
"place": "Meiji Shrine",
"description": "End the day with a visit to this peaceful Shinto shrine dedicated to Emperor Meiji and Empress Shoken. Located amidst 70 hectares of forest, it offers a serene contrast to the bustling city around it."
}
]
When user enter the preference, the data will be fetch from backend, and show in the result screen
Calling GPT api from the backend after ask for user input and preferences.
src/apiUtils/request.ts
and make a common request method for GET, POST, PUT, PATCH, DELETEsrc/apiUtils/recommendationApi.ts
This can divide by 2 pr
Deploy the frontend to vercel.
Deploy backend with AWS Lambda with serverless framework.
Use GitHub Actions for CD.
Currently prompt can be entered with anything without suggestion
When there are 2 places with same name, it return both 2 in different province or even country.
For example: https://smart-ryokou.vercel.app/ja/session/?id=6545cf1d1968e9eb28c24e7a
When changing language, path is changed but nothing happened.
I found that it works until git commit hash 92d11e1efe729a48839a70dc91aa37ffcb0d798d
but after merging into develop in hash 37a4a898ff3aad087d69e607d6f08e2634fc1955
, it is not working anymore
Work until this commit
92d11e1
This commit make it not work anymore
37a4a89
This one is the same as #68 for the fastapi endpoint.
We don't need to manually edit the card. We can pass the prompt input to gpt and make the mreplace the card.
Maybe we can skip the edit and work on memo function instead?
This one is on hold.
Update the favicon to the website icon, change the title from Create Next App
to Smart Ryokou
Data after the gpt need to save to db.
Prompt -> FastAPI -> GPT -> FastAPI -> Nextjs -> db
We plan to use Nextjs as crud, so add the saving logic to nextjs
Currently, when error appear, alert is displayed in frontend but the loading screen is still going.
When click ok in alert, refresh page or make it go back to home screen
Current logging system using python stdio print
which return the process like below image
Make a logging middleware to show information such as request and response stuff.
The detailed log design has not been made right now, have discussion with @chanon-mike and @phattd15 and implement.
Implement caching (redis)
The result from gpt in description is too long, stepping has some number and checkmark, loading is appear only when loading google maps api (not when calling backend api)
Show a pin marker for all location. When click at the card let the mark be at the center of the map
We got many feedbacks of to make the route direction for each location in map
Add route direction for each location for each date
Add Navbar UI.
It should include website home logo that navigate to the home page.
Login/Logout button
// components/LocationGeocoder.js
import { useEffect, useState } from 'react';
const LocationGeocoder = ({ locationName, apiKey, onLocationFetched }) => {
useEffect(() => {
if (!locationName) return;
// Create a new Google Maps Geocoder instance
const geocoder = new window.google.maps.Geocoder();
// Perform geocoding
geocoder.geocode({ address: locationName }, (results, status) => {
if (status === 'OK' && results.length > 0) {
const { lat, lng } = results[0].geometry.location;
onLocationFetched({ lat: lat(), lng: lng() });
} else {
console.error('Geocoding failed:', status);
onLocationFetched(null);
}
});
}, [locationName, apiKey, onLocationFetched]);
return null;
};
export default LocationGeocoder;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.