99from feeluown .app import App
1010from feeluown .ai .llm import create_chat_model_with_config
1111from feeluown .ai .matcher import SongSuggestionMatcher
12+ from feeluown .ai .model_cache import ModelCache
1213from feeluown .ai .models import SongSuggestion
1314from feeluown .ai .tools import copilot_tools
14- from feeluown .library import BriefSongModel , SimpleSearchResult
15+ from feeluown .library import (
16+ BaseModel ,
17+ BriefSongModel ,
18+ SimpleSearchResult ,
19+ )
1520from feeluown .utils .dispatch import Signal
1621
1722
@@ -99,26 +104,32 @@ class CopilotContext:
99104
100105通用规则:
101106- 当你向用户推荐或整理一组歌曲时,优先调用 create_song_suggestions_artifact 工具创建可交互歌曲建议列表。
107+ - SongSuggestion 是尚未匹配成 SongModel 的歌曲建议;不要把一组 SongSuggestion 一次性转换或播放。
108+ - create_song_suggestions_artifact 会清洗并校验歌曲建议;单个 artifact 最多包含 20 首。
109+ - play_song_suggestion 只用于“最新用户消息明确要求播放某一首建议歌曲”的场景。
110+ - 对 SongSuggestion artifact 中的歌曲,如果用户要求播放,先用 library_search 找到 SongModel。
111+ - 播放真实歌曲资源时,调用 play_song_by_uri,传入歌曲 uri。
102112- 上一首、下一首、暂停、继续、停止、音量调整等基础播放控制,应通过 playback_ 开头的工具完成。
103113- 当用户要求搜索在线音乐资源时,优先使用 library_search 工具,并用 timeout 控制最长等待时间。
104114- library_search 返回的 data.results 中的 uri 是真实资源 URI,可以在 Markdown 链接里使用。
105115- library_search 会创建搜索结果 artifact,并在 data.artifact_id 返回编号。
106- - 当用户要求播放搜索结果中的某首歌时,使用歌曲的 artifact_song_position 调用 play_artifact_song。
107116
108117AI 电台:
109118- AI 电台开关、状态和偏好应优先通过 ai_radio_ 开头的工具完成,不要要求用户去其它界面操作。
110119- AI 电台只是激活 FM 模式的一种方式;FeelUOwn 也可以通过歌曲电台等其它方式进入 FM 模式。
111- - 当用户要求开启 、启动、进入 AI 电台时,调用 ai_radio_activate。
120+ - 当用户明确要求开启 、启动、进入 AI 电台时,才调用 ai_radio_activate。
112121- 当用户要求关闭、停止、退出 AI 电台时,调用 ai_radio_deactivate。
113122- 当用户反馈会影响后续 AI 电台推荐偏好时,调用 ai_radio_update_preferences。
123+ - 在执行依赖 AI 电台已开启的操作前,先调用 ai_radio_get_state;如果返回 inactive,不要自动开启,除非最新用户消息明确要求开启 AI 电台。
114124
115125FM 候选列表:
116126- FM 候选歌曲指播放列表中当前播放歌曲后面的真实歌曲。
117127- FM 候选歌曲不是 SongSuggestion,也不是正文中的 fuo://song-suggestion 链接。
118128- FM 候选列表和 AI 电台是否开启无直接关系。
119129- 查看 FM 候选列表时调用 fm_candidates_get_state。
120130- 修改 FM 候选列表时只使用 fm_candidates_remove 和 fm_candidates_append。
121- - fm_candidates_append 接收真实 provider 歌曲。
131+ - fm_candidates_append 接收真实歌曲 URI 列表。
132+ - fm_candidates_append 一次最多追加 3 首真实歌曲;更多歌曲需要分批处理。
122133- 如果只有文字描述,先调用 library_search 找到真实歌曲资源。
123134- 清空候选列表时,先调用 fm_candidates_get_state,再用 fm_candidates_remove 删除全部候选位置。
124135- 替换候选列表时,先 remove 不需要的候选,再 append 新候选。
@@ -170,6 +181,7 @@ def __init__(self, app: App):
170181 self ._agent_context = CopilotContext (copilot = self , app = app )
171182 self ._agent_stream_callback = AgentStreamCallback (self )
172183 self ._artifacts = ArtifactsManager ()
184+ self ._model_cache = ModelCache (getattr (app , "library" , None ))
173185 self .artifact_added = self ._artifacts .added
174186 self ._current_thread_id = 1
175187 # Agent is working or not
@@ -190,6 +202,7 @@ def is_working(self, working: bool):
190202 def new_thread (self ):
191203 self ._current_thread_id += 1
192204 self ._artifacts .clear ()
205+ self ._model_cache = ModelCache (getattr (self ._app , "library" , None ))
193206
194207 async def match_song_suggestion (
195208 self , suggestion : SongSuggestion
@@ -214,7 +227,22 @@ def add_songs_artifact(
214227 def add_search_result_artifact (
215228 self , results : List [SimpleSearchResult ], title : str = ""
216229 ) -> CopilotArtifact :
217- return self ._artifacts .add_search_result (results , title = title )
230+ artifact = self ._artifacts .add_search_result (results , title = title )
231+ for song in artifact .songs :
232+ if not isinstance (song , SongSuggestion ):
233+ self .cache_model (song )
234+ return artifact
235+
236+ def cache_model (self , model : BaseModel ):
237+ self ._model_cache .set_model (model )
238+
239+ def get_model_by_uri (self , uri : str ) -> BaseModel :
240+ return self ._model_cache .get (uri )
241+
242+ def get_song_by_uri (self , uri : str ) -> BriefSongModel :
243+ model = self .get_model_by_uri (uri )
244+ assert isinstance (model , BriefSongModel )
245+ return model
218246
219247 def get_artifacts (self ) -> List [CopilotArtifact ]:
220248 return self ._artifacts .list ()
0 commit comments