Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
4794655
frontend/jupyter: add "Ask a Question" option to LLM cell tool dropdo…
haraldschilly Aug 11, 2025
177f37a
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 12, 2025
1caf369
frontend/jupyter/llm: add Assistant dialog to markdown cells
haraldschilly Aug 12, 2025
3605fcb
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 13, 2025
4ebd714
frontend/jupyter/llm: adjust layout and labeling of llm dialog
haraldschilly Aug 14, 2025
84e0482
frontend/jupyter/llm: generalize cell content context for llm-tool an…
haraldschilly Aug 14, 2025
b01839a
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 18, 2025
d6393eb
frontend/jupyter/llm: fix bubbling up slider clicks erroneously closi…
haraldschilly Aug 18, 2025
93ebf3f
frontend/juypter/ai-cell-generator: tricky off-by-one error needs to …
haraldschilly Aug 18, 2025
c35697f
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 21, 2025
1f75d9a
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 22, 2025
fe4813b
frontend/llm-context: simplify logic as a first step
haraldschilly Aug 22, 2025
7e77995
frontend/jupyter/llm: fix ai cell generator context selection
haraldschilly Aug 22, 2025
9e7c2f5
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 22, 2025
7b944e2
Merge remote-tracking branch 'origin/master' into jupyter-llm-8500
haraldschilly Aug 25, 2025
70784fa
jupyter/llm: fix target language preview dependency and type it
haraldschilly Aug 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion src/packages/frontend/account/i18n-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ Basically a drop-down to change the language (i18n localization)
*/

import { DownOutlined } from "@ant-design/icons";
import { Button, Dropdown, MenuProps, Modal, Space, Tooltip } from "antd";
import {
Button,
Dropdown,
MenuProps,
Modal,
Select,
SelectProps,
Space,
Tooltip,
} from "antd";
import { SizeType } from "antd/es/config-provider/SizeContext";
import { useState } from "react";
import { defineMessage, useIntl } from "react-intl";
Expand Down Expand Up @@ -54,6 +63,50 @@ Thank you for your patience and understanding as we work to make our application
description: "Content of translation information modal",
});

interface LanguageSelectorProps
extends Omit<SelectProps, "options" | "onChange"> {
value?: string;
onChange?: (language: Locale) => void;
}

/**
* A reusable language selector component for translation purposes.
*/
export function LanguageSelector({
value,
onChange,
...props
}: LanguageSelectorProps) {
const intl = useIntl();

let availableLocales = Object.keys(LOCALIZATIONS) as Locale[];

const options = availableLocales.map((locale) => {
const localization = LOCALIZATIONS[locale];
const other =
locale === value
? localization.name
: intl.formatMessage(localization.trans);
return {
value: locale,
label: `${localization.flag} ${localization.native} (${other})`,
};
});

return (
<Select
value={value}
onChange={onChange}
options={options}
placeholder="Select a language..."
showSearch
optionFilterProp="label"
popupMatchSelectWidth={false}
{...props}
/>
);
}

export function I18NSelector(props: Readonly<Props>) {
const { isWide = true, size, confirm = false } = props;

Expand Down
10 changes: 6 additions & 4 deletions src/packages/frontend/components/raw-prompt.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { CSS } from "@cocalc/frontend/app-framework";
import { useBottomScroller } from "@cocalc/frontend/app-framework/use-bottom-scroller";
import { COLORS } from "@cocalc/util/theme";
import StaticMarkdown from "@cocalc/frontend/editors/slate/static-markdown";
import { Paragraph } from "@cocalc/frontend/components";
import StaticMarkdown from "@cocalc/frontend/editors/slate/static-markdown";
import { COLORS } from "@cocalc/util/theme";

const STYLE = {
border: "1px solid lightgrey",
Expand All @@ -21,18 +21,20 @@ interface Props {
input: React.JSX.Element | string;
style?: CSS;
scrollBottom?: boolean;
rawText?: boolean;
}

export function RawPrompt({
input,
style: style0,
scrollBottom = false,
rawText = false,
}: Props) {
const ref = useBottomScroller(scrollBottom, input);
const style = { ...STYLE, ...style0 };
if (typeof input == "string") {
if (typeof input == "string" && !rawText) {
// this looks so much nicer; I realize it doesn't implement scrollBottom.
// But just dropping the input as plain text like below just seems
// But just dropping the input as plain text like below just seems
// utterly broken!
return <StaticMarkdown style={style} value={input} />;
} else {
Expand Down
9 changes: 8 additions & 1 deletion src/packages/frontend/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
"language": "en",
"enabled": true,
"words": [
"ANOVA",
"ARIMA",
"autograde",
"autograding",
"Bioconductor",
"bioinformatics",
"CoCalc",
"conat",
"dplyr",
"dstream",
"formatjs",
"geospatial",
"ggplot",
"ipython",
"ipywidgets",
Expand All @@ -35,14 +40,16 @@
"sagetex",
"sagews",
"scikit",
"simplelocalize",
"sklearn",
"SocketIO",
"statsmodels",
"syncdb",
"syncdoc",
"syncdoc",
"syncstring",
"synctable",
"synctables",
"tidymodels",
"tidyverse",
"timetravel",
"tolerations",
Expand Down
2 changes: 1 addition & 1 deletion src/packages/frontend/frame-editors/llm/consts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// number of characters we send to an LLM for context
export const CUTOFF = 3000;
export const CUTOFF = 5000;

// this came from ./create-chat, but for all frame types
export const AI_ASSIST_TAG = "code-editor";
28 changes: 28 additions & 0 deletions src/packages/frontend/i18n/bin/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,31 @@ check_api_key() {
exit 1
fi
}

# Execute a function for each language, optionally in parallel
# Usage: run_for_each_lang <function_name>
run_for_each_lang() {
local func_name="$1"

if [ -z "$func_name" ]; then
echo "Error: function name is required" >&2
exit 1
fi

start_time=$(date +%s)

if command -v parallel &>/dev/null; then
echo "Parallel is installed. Running $func_name in parallel."
export -f "$func_name"
echo "$LANGS" | tr ' ' '\n' | parallel -j8 --delay 0.1 --will-cite "$func_name"
else
echo "Parallel is not installed. Running $func_name sequentially."
for L in $LANGS; do
"$func_name" "$L"
done
fi

end_time=$(date +%s)
execution_time=$((end_time - start_time))
echo "$func_name completed in ${execution_time} seconds."
}
14 changes: 10 additions & 4 deletions src/packages/frontend/i18n/bin/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@
# It was necessary to write a custom formatter (see formatter.js) – not clear why, but it works. It's just a trivial mapping.
# "--ast" this is the main point of compiling: we use ICU messages, which no longer need to be parsed each time.
# This compile step is called by the `pnpm build` step as well, hence there is no need to keep the compiled files in the sources.
for L in $LANGS; do

# Each language is compiled into a separate file – this allows for dynamic imports.
compile() {
local lang="$1"
echo "compiling '$lang'"
pnpm exec formatjs compile \
--ast \
--format i18n/formatter.js \
--out-file ./i18n/trans/$L.compiled.json \
./i18n/trans/$L.json
done
--out-file ./i18n/trans/$lang.compiled.json \
./i18n/trans/$lang.json
}

run_for_each_lang compile
13 changes: 2 additions & 11 deletions src/packages/frontend/i18n/bin/download.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

check_api_key

# Each language is downloaded into a spearate file and compiled – this allows for dynamic imports.
# Each language is downloaded into a separate file and compiled – this allows for dynamic imports.
download() {
local lang="$1"
echo "calling download '$lang'"
Expand All @@ -14,13 +14,4 @@ download() {
--languageKey="$lang"
}

if command -v parallel &>/dev/null; then
echo "Parallel is installed. Running downloads in parallel."
export -f download
echo "$LANGS" | tr ' ' '\n' | parallel -j8 --delay 0.1 --will-cite download
else
echo "Parallel is not installed. Running downloads sequentially."
for L in $LANGS; do
download "$L"
done
fi
run_for_each_lang download
4 changes: 2 additions & 2 deletions src/packages/frontend/jupyter/_jupyter.sass
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
.cocalc-jupyter-insert-cell
margin-bottom: 10px
height: 8px
margin-top: 8px
margin-top: 10px
cursor: pointer
text-align: center
&:hover
Expand Down Expand Up @@ -111,4 +111,4 @@
// %matplotlib widgets
// from pylab import plot; plot([1,2],[3,4])
cocalc-lumino-adapter
position: relative
position: relative
17 changes: 12 additions & 5 deletions src/packages/frontend/jupyter/cell-buttonbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
RUN_ALL_CELLS_ABOVE_ICON,
RUN_ALL_CELLS_BELOW_ICON,
} from "./consts";
import { LLMCellTool } from "./llm";
import { LLMCellTool } from "./llm/cell-tool";

interface Props {
id: string;
Expand Down Expand Up @@ -192,8 +192,15 @@ export const CellButtonBar: React.FC<Props> = React.memo(
}

function renderCodeBarLLMButtons() {
if (!isCodeCell || !llmTools || !haveLLMCellTools || is_readonly) return;
return <LLMCellTool id={id} actions={actions} llmTools={llmTools} />;
if (!llmTools || !haveLLMCellTools || is_readonly) return;
return (
<LLMCellTool
id={id}
actions={actions}
llmTools={llmTools}
cellType={isCodeCell ? "code" : "markdown"}
/>
);
}

function renderCodeBarFormatButton() {
Expand All @@ -204,7 +211,7 @@ export const CellButtonBar: React.FC<Props> = React.memo(
return (
<Tooltip
title={intl.formatMessage({
id: "jupyter.cell-buttonbr.format-button.tooltip",
id: "jupyter.cell-buttonbar.format-button.tooltip",
defaultMessage: "Format this code to look nice",
description: "Code cell in a Jupyter Notebook",
})}
Expand All @@ -230,7 +237,7 @@ export const CellButtonBar: React.FC<Props> = React.memo(
>
<Icon name={formatting ? "spinner" : "sitemap"} spin={formatting} />{" "}
<FormattedMessage
id="jupyter.cell-buttonbr.format-button.label"
id="jupyter.cell-buttonbar.format-button.label"
defaultMessage={"Format"}
description={"Code cell in a Jupyter Notebook"}
/>
Expand Down
Loading