diff --git a/.vscode/settings.json b/.vscode/settings.json index af905e0a..40706eb2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,7 @@ "landuse", "langchain", "Liban", + "lightbrown", "lightgreen", "lightpink", "lightyellow", diff --git a/src/app/api/ai/inner/route.ts b/src/app/api/ai/inner/route.ts index 828ae71d..2a73ca47 100644 --- a/src/app/api/ai/inner/route.ts +++ b/src/app/api/ai/inner/route.ts @@ -11,9 +11,6 @@ export async function POST(request: Request) { const reqJson = await request.json(); const pastMessagesJsonString = reqJson.pastMessages; - console.log("pastMessagesJsonString"); - console.debug(pastMessagesJsonString); - const chatHistoryLines = parsePastMessagesToLines( pastMessagesJsonString, true diff --git a/src/app/api/ai/suggests/route.ts b/src/app/api/ai/suggests/route.ts index c52632a5..8596c7c0 100644 --- a/src/app/api/ai/suggests/route.ts +++ b/src/app/api/ai/suggests/route.ts @@ -13,9 +13,6 @@ export async function POST(request: Request) { const location = reqJson.location; const pastMessagesJsonString = reqJson.pastMessages; - console.log("pastMessagesJsonString"); - console.debug(pastMessagesJsonString); - const chatHistoryLines = parsePastMessagesToLines( pastMessagesJsonString, true @@ -62,7 +59,8 @@ export async function POST(request: Request) { const result = await chain.call({ input }); console.log(""); - console.log("Suggests:\n", result.text); + console.log("Suggests:"); + console.log(result.text); console.log(""); console.log("----- end suggest -----"); diff --git a/src/app/api/ai/surface/route.ts b/src/app/api/ai/surface/route.ts index 591d2403..342ba512 100644 --- a/src/app/api/ai/surface/route.ts +++ b/src/app/api/ai/surface/route.ts @@ -55,7 +55,8 @@ export async function POST(request: Request) { console.log(""); const history = await memory.chatHistory.getMessages(); - console.log(history); + // debug用 + //console.log(history); console.log("----- end surface -----"); console.log("----- ----- -----"); diff --git a/src/app/page.tsx b/src/app/page.tsx index 4cd3cc0c..f0487156 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -20,6 +20,8 @@ import { fitBoundsToGeoJson } from "@/utils/map/fitBoundsToGeoJson"; import { parseInnerResJson } from "@/utils/trident/parseInnerResJson"; import { LegalNotice } from "@/components/LegalNotice"; import { InputSuggest } from "@/components/InputSuggest"; +import { InputPredict } from "@/components/InputPredict"; +import { LocationProvider } from "@/contexts/LocationContext"; const greetings = { en: "Welcome! I'm TRIDENT, interactive Smart Maps assistant. Could you indicate me the areas and themes you want to see as the map?", @@ -52,11 +54,11 @@ export default function Home() { // maps ref and state const mapRef = useRef(null); - const geolocationControlRef = useRef(null); const [mapTitle, setMapTitle] = useState(undefined); const [geojsonWithStyleList, setGeojsonWithStyleList] = useState< Array<{ id: string; style: TridentMapsStyle; geojson: FeatureCollection }> >([]); + const [location, setLocation] = useState(undefined); // base maps style state const [mapStyleJsonUrl, setMapStyleJsonUrl] = useLocalStorage( @@ -135,6 +137,7 @@ export default function Home() { setInputText(""); setResponding(true); + setMapping(true); insertNewDialogue({ who: "user", text: newInputText }); @@ -228,6 +231,7 @@ export default function Home() { }); if (idx === linesWithAreaAndOrConcern.length - 1) { console.log("Finish!!!!!"); + setMapping(false); insertNewDialogue( { who: "assistant", @@ -238,7 +242,6 @@ export default function Home() { }, false ); - setMapping(false); } } else { if (retry) { @@ -262,6 +265,7 @@ export default function Home() { const onSelectedSuggestions = useCallback( async (value: string) => { + setResponding(true); await onSubmit(value); }, [onSubmit] @@ -319,6 +323,8 @@ export default function Home() { fitBoundsToGeoJson(mapRef, everything, padding); } catch (error) { console.error(error); + setResponding(false); + setMapping(false); } }, 500); }, [geojsonWithStyleList, showingFloatingChat]); @@ -410,9 +416,28 @@ export default function Home() { ); })} - {dialogueList.length === 1 && inputText.length === 0 && ( - - )} + + {dialogueList.length === 1 && inputText.length === 0 && ( + { + setLocation(v); + }} + /> + )} + {pastMessages && + pastMessages.length > 1 && + !responding && + !mapping && ( + { + scrollToBottom(); + }} + onSelected={onSelectedSuggestions} + /> + )} +
void; + onSelected?: (value: string) => void; +}> = ({ pastMessages, onUpdateSuggestions, onSelected }) => { + const locationInfo = useContext(LocationContext); + const [requesting, setRequesting] = useState(false); + const [suggests, setSuggests] = useState(undefined); + + useEffect(() => { + if (!pastMessages) { + return; + } + if (pastMessages.length === 0) { + return; + } + if (requesting) { + return; + } + const thisEffect = async () => { + setRequesting(true); + const resJson = await nextPostJsonWithCache("/api/ai/suggests", { + lang: window.navigator.language, + location: locationInfo.location, + pastMessages: JSON.stringify(pastMessages), + }); + if (!resJson.suggests) { + return; + } + const newSuggests = resJson.suggests.split("\n"); + setSuggests(newSuggests); + onUpdateSuggestions && onUpdateSuggestions(); + setRequesting(false); + }; + thisEffect(); + }, [locationInfo, onUpdateSuggestions, pastMessages, requesting]); + + return ( + <> +
+ {suggests?.map((suggest) => { + return ( + + ); + })} +
+ + ); +}; diff --git a/src/components/InputPredict/styles.module.scss b/src/components/InputPredict/styles.module.scss new file mode 100644 index 00000000..42b1f8fb --- /dev/null +++ b/src/components/InputPredict/styles.module.scss @@ -0,0 +1,12 @@ +.suggestListWrap { + display: flex; + flex-direction: column; + flex-wrap: no-wrap; + gap: 2%; +} + +.suggestListItem { + font-size: 0.8em; + margin-top: 12px; + padding: 6px; +} diff --git a/src/components/InputSuggest/SuggestByCurrentLocation/index.tsx b/src/components/InputSuggest/SuggestByCurrentLocation/index.tsx index 0c365314..e2161f56 100644 --- a/src/components/InputSuggest/SuggestByCurrentLocation/index.tsx +++ b/src/components/InputSuggest/SuggestByCurrentLocation/index.tsx @@ -6,9 +6,10 @@ import styles from "./styles.module.scss"; export const SuggestByCurrentLocation: React.FC<{ coordinates: GeolocationCoordinates | null; + onChangeLocation?: (location: string) => void; onSelected?: (value: string) => void; -}> = ({ coordinates, onSelected }) => { - const [address, setAddress] = useState(null); +}> = ({ coordinates, onChangeLocation, onSelected }) => { + const [location, setLocation] = useState(null); const [suggests, setSuggests] = useState([]); useEffect(() => { @@ -27,15 +28,18 @@ export const SuggestByCurrentLocation: React.FC<{ 10 ); console.log("address", address); - const name = address.display_name; - setAddress(name); + const newLocation = address.display_name; + setLocation(newLocation); + if (onChangeLocation) { + onChangeLocation(newLocation); + } setSuggests([]); }; thisEffect(); - }, [coordinates]); + }, [coordinates, onChangeLocation]); useEffect(() => { - if (!address) { + if (!location) { return; } if (suggests.length > 0) { @@ -44,7 +48,7 @@ export const SuggestByCurrentLocation: React.FC<{ const thisEffect = async () => { const resJson = await nextPostJsonWithCache("/api/ai/suggests", { lang: window.navigator.language, - location: address, + location: location, }); console.log(resJson.suggests); if (!resJson.suggests) { @@ -54,11 +58,11 @@ export const SuggestByCurrentLocation: React.FC<{ setSuggests(newSuggests); }; thisEffect(); - }, [address, suggests]); + }, [location, suggests]); return (
- {address &&
{address}
} + {location &&
{location}
} {coordinates && suggests?.length > 0 && (
{suggests.map((suggest) => ( diff --git a/src/components/InputSuggest/index.tsx b/src/components/InputSuggest/index.tsx index 5c86b0cc..22329da7 100644 --- a/src/components/InputSuggest/index.tsx +++ b/src/components/InputSuggest/index.tsx @@ -8,7 +8,8 @@ import { SuggestByTrend } from "./SuggestByTrend"; export const InputSuggest: React.FC<{ onSelected?: (value: string) => void; -}> = ({ onSelected }) => { + onChangeLocation?: (location: string) => void; +}> = ({ onSelected, onChangeLocation }) => { const [suggestMode, setSuggestMode] = useState<"location" | "trend" | null>( null ); @@ -46,6 +47,7 @@ export const InputSuggest: React.FC<{ )} {suggestMode === "trend" && } diff --git a/src/contexts/LocationContext.tsx b/src/contexts/LocationContext.tsx new file mode 100644 index 00000000..578a3e09 --- /dev/null +++ b/src/contexts/LocationContext.tsx @@ -0,0 +1,24 @@ +import React, { createContext } from "react"; + +export type LocationInfo = { + location: string | undefined; +}; + +export const LocationContext = createContext({ + location: undefined, +}); + +export const LocationProvider = ({ + locationInfo, + children, +}: { + locationInfo: LocationInfo; + children: React.ReactNode; +}) => { + return ( + + {children} + + ); +}; + diff --git a/src/utils/langchain/chains/deep/prompt.ts b/src/utils/langchain/chains/deep/prompt.ts index fe58a1ff..c93fcdcd 100644 --- a/src/utils/langchain/chains/deep/prompt.ts +++ b/src/utils/langchain/chains/deep/prompt.ts @@ -44,6 +44,12 @@ out geom;`, input: "Area: Tokyo", output: `[out:json][timeout:30000]; relation["boundary"="administrative"]["admin_level"=4]["name:en"="Tokyo"]; +out geom;`, + }, + { + input: "Area: Kanto region", + output: `[out:json][timeout:30000]; +relation["type"="boundary"]["name:en"="Kanto"]; out geom;`, }, { diff --git a/src/utils/langchain/chains/inner/prompt.ts b/src/utils/langchain/chains/inner/prompt.ts index 8c998f76..ebc12f25 100644 --- a/src/utils/langchain/chains/inner/prompt.ts +++ b/src/utils/langchain/chains/inner/prompt.ts @@ -231,6 +231,9 @@ EmojiForConcern: National treasure castles, 🏯 ColorForConcern: National treasure castles, white EmojiForConcern: River, 🏞 ColorForConcern: River, blue +EmojiForConcern: Cafe, ☕️ +ColorForConcern: Cafe, brown +Important note: lightbrown is not a Web Safe Color, so you must not use it. `; const tridentInnerPromptPrefix = `You are a conversation analysis assistant dedicated to generate web maps. You analyze the following conversation and accurately output map definition to instruct the Map Building Agent. Map definition MUST be enclosed by three backticks on new lines, denoting that it is a code block. diff --git a/src/utils/langchain/chains/suggest/prompt.ts b/src/utils/langchain/chains/suggest/prompt.ts index 7ce3d6a0..4834edbf 100644 --- a/src/utils/langchain/chains/suggest/prompt.ts +++ b/src/utils/langchain/chains/suggest/prompt.ts @@ -13,12 +13,73 @@ export const tridentSuggestExampleList: Array<{ { input: `Primary language of user: ja Current location of user: 台東区, 東京都, 日本`, - output: `台東区の地図を表示して -東京都の地図を表示して -日本の地図を表示して`, + output: `台東区を表示して +東京都を表示して +日本を表示して`, }, { - input: "台東区の地図を表示して", + input: `Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +台東区を表示して`, + output: `ラーメン屋を表示して +カフェを表示して +駅を表示して +病院を表示して`, + }, + { + input: `Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +台東区を表示して +ラーメン屋を表示して`, + output: `蕎麦屋を表示して +寿司屋を表示して +ハンバーガー屋を表示して +カレー屋を表示して`, + }, + { + input: `Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +台東区を表示して +カフェを表示して`, + output: `公園を表示して +ベンチを表示して`, + }, + { + input: `Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +台東区を表示して +公園を表示して`, + output: `ベンチを表示して +川を表示して`, + }, + { + input: `Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +東京都を表示して`, + output: `台東区に絞り込んで +文京区に絞り込んで +関東に広げて +日本に広げて`, + }, + { + input: `input: +Primary language of user: ja +Current location of user: 台東区, 東京都, 日本 + +Chat history: +東京都を表示して +関東に広げて +台東区に絞り込んで`, output: `ラーメン屋を表示して 駅を表示して 公園を表示して @@ -48,7 +109,7 @@ export const loadTridentSuggestPrompt = async (embeddings: Embeddings) => { const memoryVectorStore = new MemoryVectorStore(embeddings); const exampleSelector = new SemanticSimilarityExampleSelector({ vectorStore: memoryVectorStore, - k: 3, + k: 5, inputKeys: ["input"], }); const examplePrompt = PromptTemplate.fromTemplate( diff --git a/src/utils/nextPostJson.ts b/src/utils/nextPostJson.ts index fec70a1a..dd878086 100644 --- a/src/utils/nextPostJson.ts +++ b/src/utils/nextPostJson.ts @@ -19,7 +19,7 @@ export const nextPostJsonWithCache = async ( const md5 = new Md5(); md5.appendStr(`${url}\n${bodyJsonString}`); const hash = md5.end(); - const key = `trident-cache_2024-01-08_${hash}`; + const key = `trident-cache_2024-01-08_005_${hash}`; const unixtime = Math.floor(new Date().getTime() / 1000); const fetchAndCache = async () => {