Skip to content

Commit

Permalink
Update feedback when feedback is already present
Browse files Browse the repository at this point in the history
  • Loading branch information
dqbd committed Nov 10, 2023
1 parent a4199f7 commit 8dc4d15
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 16 deletions.
2 changes: 1 addition & 1 deletion langserve/playground/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ function App() {

{schemas.feedbackEnabled && latest.id ? (
<div className="absolute right-4 top-4 flex items-center gap-2 transition-opacity opacity-0 focus-within:opacity-100 group-hover:opacity-100">
<CorrectnessFeedback runId={latest.id} />
<CorrectnessFeedback key={latest.id} runId={latest.id} />
</div>
) : null}
</div>
Expand Down
2 changes: 1 addition & 1 deletion langserve/playground/src/components/IntermediateSteps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function IntermediateSteps(props: {
</pre>
{props.feedbackEnabled && log.id ? (
<div className="absolute right-3 top-3 flex items-center gap-2 transition-opacity opacity-0 focus-within:opacity-100 group-hover:opacity-100">
<CorrectnessFeedback runId={log.id} />
<CorrectnessFeedback key={log.id} runId={log.id} />
</div>
) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { cn } from "../../utils/cn";

export function CorrectnessFeedback(props: { runId?: string }) {
const [loading, setLoading] = useState<number | null>(null);
const [state, setState] = useState<number | null>(null);
const [state, setState] = useState<{ id: string; score: number } | null>(
null
);

const isMounted = useRef<boolean>(true);
useEffect(() => {
Expand All @@ -25,20 +27,23 @@ export function CorrectnessFeedback(props: { runId?: string }) {
if (isMounted.current) setLoading(payload.score);

try {
const request = await fetch(resolveApiUrl("/feedback"), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const request = await fetch(
resolveApiUrl(state?.id ? `/feedback/${state.id}` : "/feedback"),
{
method: state?.id ? "PATCH" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
}
);

if (!request.ok) throw new Error(`Failed request ${request.status}`);
const json: {
id: string;
score: number;
} = await request.json();

if (isMounted.current) setState(json.score);
if (isMounted.current)
setState(json ?? { id: state?.id, score: payload.score });
} finally {
if (isMounted.current) setLoading(null);
}
Expand All @@ -51,7 +56,7 @@ export function CorrectnessFeedback(props: { runId?: string }) {
type="button"
className={cn(
"border focus-within:border-ls-blue focus-within:outline-none bg-background rounded p-1 border-divider-700 hover:bg-divider-500/50 active:bg-divider-500",
state === 1 && "text-teal-500"
state?.score === 1 && "text-teal-500"
)}
disabled={loading != null}
onClick={() => {
Expand All @@ -75,7 +80,7 @@ export function CorrectnessFeedback(props: { runId?: string }) {
type="button"
className={cn(
"border focus-within:border-ls-blue focus-within:outline-none bg-background rounded p-1 border-divider-700 hover:bg-divider-500/50 active:bg-divider-500",
state === -1 && "text-red-500"
state?.score === -1 && "text-red-500"
)}
disabled={loading != null}
onClick={() => {
Expand Down
2 changes: 1 addition & 1 deletion langserve/playground/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineConfig({
plugins: [svgr(), react()],
server: {
proxy: {
"^/____LANGSERVE_BASE_URL.*/(config_schema|input_schema|stream_log|feedback)$": {
"^/____LANGSERVE_BASE_URL.*/(config_schema|input_schema|stream_log|feedback)(/[a-zA-Z0-9-]*)?$": {
target: "http://127.0.0.1:8000",
changeOrigin: true,
rewrite: (path) => path.replace("/____LANGSERVE_BASE_URL", ""),
Expand Down
15 changes: 15 additions & 0 deletions langserve/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ class FeedbackCreateRequest(BaseFeedback):
"""Comment or explanation for the feedback."""


class FeedbackUpdateRequest(BaseFeedback):
"""
Represents a request that updates an existing feedback
"""

score: Optional[Union[float, int, bool]] = None
"""Value or score to assign the run."""

value: Optional[Union[float, int, bool, str, dict]] = None
"""The display value for the feedback if not a metric."""

comment: Optional[str] = None
"""Comment or explanation for the feedback."""


class Feedback(BaseFeedback):
"""
Represents feedback given on an individual run
Expand Down
36 changes: 34 additions & 2 deletions langserve/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Type,
Union,
)
from uuid import UUID

from fastapi import HTTPException, Request, Response
from fastapi.encoders import jsonable_encoder
Expand Down Expand Up @@ -51,6 +52,7 @@
CustomUserType,
Feedback,
FeedbackCreateRequest,
FeedbackUpdateRequest,
SingletonResponseMetadata,
)
from langserve.serialization import WellKnownLCSerializer
Expand Down Expand Up @@ -1014,7 +1016,7 @@ async def playground(

@app.head(namespace + "/c/{config_hash}/feedback")
@app.head(namespace + "/feedback")
async def feedback_enabled():
async def feedback_enabled(config_hash: str = ""):
if not tracing_is_enabled() or not enable_feedback_endpoint:
raise HTTPException(
400,
Expand All @@ -1024,7 +1026,9 @@ async def feedback_enabled():

@app.post(namespace + "/c/{config_hash}/feedback")
@app.post(namespace + "/feedback")
async def feedback(feedback_create_req: FeedbackCreateRequest) -> Feedback:
async def create_feedback(
feedback_create_req: FeedbackCreateRequest, config_hash: str = ""
) -> Feedback:
"""
Send feedback on an individual run to langsmith
"""
Expand Down Expand Up @@ -1074,6 +1078,34 @@ async def feedback(feedback_create_req: FeedbackCreateRequest) -> Feedback:
comment=feedback_from_langsmith.comment,
)

@app.patch(namespace + "/c/{config_hash}/feedback/{feedback_id}")
@app.patch(namespace + "/feedback/{feedback_id}")
async def update_feedback(
feedback_id: UUID,
feedback_update_req: FeedbackUpdateRequest,
config_hash: str = "",
) -> None:
"""
Send feedback on an individual run to langsmith
"""

if not tracing_is_enabled() or not enable_feedback_endpoint:
raise HTTPException(
400,
"The feedback endpoint is only accessible when LangSmith is "
+ "enabled on your LangServe server.",
)

try:
langsmith_client.update_feedback(
feedback_id,
score=feedback_update_req.score,
value=feedback_update_req.value,
comment=feedback_update_req.comment,
)
except LangSmithNotFoundError:
raise HTTPException(404, "No feedback with the given feedback_id exists")

#######################################
# Documentation variants of end points.
#######################################
Expand Down

0 comments on commit 8dc4d15

Please sign in to comment.